Compare commits
467 Commits
v0.2.0
...
archive/cu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
493b80095d | ||
|
|
73a9b2af89 | ||
|
|
b167107c8b | ||
|
|
972d601664 | ||
|
|
7bc40ab13d | ||
|
|
5243530d81 | ||
|
|
e3108261ab | ||
|
|
883c465a14 | ||
|
|
1d98152953 | ||
|
|
a6f8ee317f | ||
|
|
4315618782 | ||
|
|
b71f39cfb4 | ||
|
|
2ec493e2af | ||
|
|
7e43d574d8 | ||
|
|
01a0a376e3 | ||
|
|
59500e5278 | ||
|
|
5390a9f375 | ||
|
|
1412cd5277 | ||
|
|
ca57749a3b | ||
|
|
6706ff23ce | ||
|
|
daf3c28929 | ||
|
|
821058740f | ||
|
|
fbe7533d4b | ||
|
|
4a833e82cd | ||
|
|
a692899f5b | ||
|
|
a86363a6d2 | ||
|
|
4ab7f1dcb3 | ||
|
|
0f1cee44a3 | ||
|
|
d16fe5376d | ||
|
|
514d05b237 | ||
|
|
f95c5b7921 | ||
|
|
1dd4a5b48b | ||
|
|
7bf06a59d4 | ||
|
|
fd759e4a9d | ||
|
|
11d47cc67a | ||
|
|
46ce6bf45e | ||
|
|
5af5a02e31 | ||
|
|
664acb140e | ||
|
|
09a27df6db | ||
|
|
1996893a26 | ||
|
|
86d1f808af | ||
|
|
aaa4329d8c | ||
|
|
5a5e8f0e31 | ||
|
|
83b2e59910 | ||
|
|
8f04ce894f | ||
|
|
2260d19364 | ||
|
|
90409b0b3d | ||
|
|
559367ee55 | ||
|
|
cab3688890 | ||
|
|
3294634d24 | ||
|
|
36cf1c3179 | ||
|
|
930fb331db | ||
|
|
eb7f592154 | ||
|
|
aa77b017e8 | ||
|
|
09900a08e4 | ||
|
|
9beb7e48d4 | ||
|
|
5481959018 | ||
|
|
32fae60930 | ||
|
|
d564d3bc39 | ||
|
|
6537aead64 | ||
|
|
2848da0b8e | ||
|
|
923c5698b5 | ||
|
|
8d3bccbd56 | ||
|
|
44b2b1b958 | ||
|
|
eadb661515 | ||
|
|
42066fc8a1 | ||
|
|
ba88b2b1da | ||
|
|
f550ba67aa | ||
|
|
bdc637d3af | ||
|
|
73693b88f6 | ||
|
|
77fcc4a673 | ||
|
|
54f5f0ac08 | ||
|
|
425b85d5a7 | ||
|
|
f6fe9ce85c | ||
|
|
75aa9541e0 | ||
|
|
03bfb22559 | ||
|
|
05ff4e0956 | ||
|
|
959bf7c477 | ||
|
|
7c562af0aa | ||
|
|
57c3f63a26 | ||
|
|
f08455073a | ||
|
|
812654fe32 | ||
|
|
aaf0b7a645 | ||
|
|
e64d80d02e | ||
|
|
ac9d236955 | ||
|
|
fc2d53eb4f | ||
|
|
77367345b6 | ||
|
|
02fbc5938b | ||
|
|
ce794c4dac | ||
|
|
edf280e2df | ||
|
|
1bd17f73b1 | ||
|
|
511741d11a | ||
|
|
f86ad6175e | ||
|
|
afef34a648 | ||
|
|
802fda3cfd | ||
|
|
b5feb0db2a | ||
|
|
4b60c03688 | ||
|
|
e0aaab56e3 | ||
|
|
9a76c70b37 | ||
|
|
e619b3026c | ||
|
|
54b7d3f229 | ||
|
|
a4b0c4e213 | ||
|
|
47f33e002d | ||
|
|
a4e369e629 | ||
|
|
d03da83fda | ||
|
|
c20ba98a1e | ||
|
|
c4ea6e53e8 | ||
|
|
1856cb079c | ||
|
|
56f1233967 | ||
|
|
da932c5caa | ||
|
|
bf6e38703a | ||
|
|
b5af7b1c3e | ||
|
|
e0a4735fe2 | ||
|
|
9c0a670525 | ||
|
|
ca01e245cb | ||
|
|
92da411ea5 | ||
|
|
f60b0fce7d | ||
|
|
3cceb35445 | ||
|
|
ca58afd81b | ||
|
|
32103979ed | ||
|
|
51f7f14c08 | ||
|
|
0db46da30e | ||
|
|
411c23c46e | ||
|
|
e984fc24b6 | ||
|
|
33782ed7f3 | ||
|
|
e31078d8ef | ||
|
|
39d99485eb | ||
|
|
f73824adcb | ||
|
|
8a49546add | ||
|
|
89745202f5 | ||
|
|
d98ce413bb | ||
|
|
e2e5982d68 | ||
|
|
4773aad40c | ||
|
|
b44ca8df8d | ||
|
|
02a655d005 | ||
|
|
1da8e66281 | ||
|
|
301cebc254 | ||
|
|
26c8995dad | ||
|
|
6b99946fd8 | ||
|
|
4ffaf3fbe6 | ||
|
|
43cb54bb21 | ||
|
|
498c248c24 | ||
|
|
4f3f82f27f | ||
|
|
0c9a95bc54 | ||
|
|
f19795edaf | ||
|
|
c1b9bb348d | ||
|
|
ece6e0a833 | ||
|
|
c2c512a7e3 | ||
|
|
690e9dbfe8 | ||
|
|
1e696edcff | ||
|
|
1fe09c580c | ||
|
|
12261c5b56 | ||
|
|
72cff220cf | ||
|
|
e0cf442041 | ||
|
|
a9f148c04e | ||
|
|
a652e39b1c | ||
|
|
79ee241bb7 | ||
|
|
63b98f26a6 | ||
|
|
95fe7fdd25 | ||
|
|
9c9984a40a | ||
|
|
7f188b0f44 | ||
|
|
023c76db59 | ||
|
|
672482194c | ||
|
|
689d16ee65 | ||
|
|
a912c999a9 | ||
|
|
26da24c3c5 | ||
|
|
4cf8e18d1f | ||
|
|
6df5028d7a | ||
|
|
e179e89c03 | ||
|
|
a7f86a4333 | ||
|
|
aea14074cc | ||
|
|
fac91af34d | ||
|
|
7c54a3c923 | ||
|
|
542428df32 | ||
|
|
adaf0ade52 | ||
|
|
4265fac7b8 | ||
|
|
8a90e5d186 | ||
|
|
c213fa8cdf | ||
|
|
45567c7acc | ||
|
|
d549c44f95 | ||
|
|
9cfa0d447a | ||
|
|
590cb1e85c | ||
|
|
fedc0ad71c | ||
|
|
ce54c489eb | ||
|
|
d63c879404 | ||
|
|
35f9de3366 | ||
|
|
17b31c417b | ||
|
|
421847e9d3 | ||
|
|
3a7a3a89ba | ||
|
|
b89615342e | ||
|
|
4198b6dc4e | ||
|
|
0cf34d2d26 | ||
|
|
d5a9747712 | ||
|
|
45767d881d | ||
|
|
2d4f1780bf | ||
|
|
ca8609f42c | ||
|
|
1580750606 | ||
|
|
58709d2d26 | ||
|
|
94c00dda95 | ||
|
|
0595088409 | ||
|
|
3ab8036363 | ||
|
|
1f177a044d | ||
|
|
96b8ded8af | ||
|
|
32bd23f85e | ||
|
|
447db2e458 | ||
|
|
480d3b26c4 | ||
|
|
8b1be6edee | ||
|
|
b2e2aef78d | ||
|
|
62b31eee00 | ||
|
|
774f5f0db7 | ||
|
|
f8ff829e27 | ||
|
|
34083d3e8d | ||
|
|
173329de8f | ||
|
|
ef2b665ff0 | ||
|
|
841bb101c5 | ||
|
|
7198a7c78d | ||
|
|
de148fc98f | ||
|
|
6de5c01afb | ||
|
|
0d30bc2676 | ||
|
|
e5150d3714 | ||
|
|
7032c8a92e | ||
|
|
51359cf77b | ||
|
|
6529542277 | ||
|
|
63611cef80 | ||
|
|
0b5759abe6 | ||
|
|
1e425f3c28 | ||
|
|
4720353fa2 | ||
|
|
e8679d9308 | ||
|
|
808f35adc6 | ||
|
|
7d307832a0 | ||
|
|
12cf5559c2 | ||
|
|
6497cdf8ff | ||
|
|
e4f3ea7798 | ||
|
|
10ac4418e4 | ||
|
|
3a0856505d | ||
|
|
8a6751711a | ||
|
|
50755a040b | ||
|
|
69796bf1bc | ||
|
|
9ac0e02574 | ||
|
|
738fbdd376 | ||
|
|
0e1eb71149 | ||
|
|
f5cbbb5c84 | ||
|
|
9a1e4450d8 | ||
|
|
563dda69d4 | ||
|
|
44c9feaebf | ||
|
|
c457a2603a | ||
|
|
981c36dbdb | ||
|
|
6630e454c6 | ||
|
|
9c60d4936d | ||
|
|
e2511f8ad5 | ||
|
|
19379decd5 | ||
|
|
743ede2243 | ||
|
|
0edccd8934 | ||
|
|
6f704f0320 | ||
|
|
62db0573bd | ||
|
|
4d5c34bd58 | ||
|
|
f0fb3eb434 | ||
|
|
7de97eeb2c | ||
|
|
def32d80dd | ||
|
|
e4bba4cb6f | ||
|
|
9a38577a18 | ||
|
|
f3f05b0396 | ||
|
|
fd109436e5 | ||
|
|
d629dc449f | ||
|
|
5db8cda0b6 | ||
|
|
d113a738de | ||
|
|
bd3fe8f86b | ||
|
|
445e88cce8 | ||
|
|
33e11c0c3a | ||
|
|
370f4e140d | ||
|
|
b556fd0019 | ||
|
|
be9dc90738 | ||
|
|
8896f46ef3 | ||
|
|
dcffe0ef04 | ||
|
|
a5b19b10e0 | ||
|
|
d6e378c3bf | ||
|
|
6893541f9c | ||
|
|
74dd24f39c | ||
|
|
3634b17be4 | ||
|
|
006341daf7 | ||
|
|
427836fec9 | ||
|
|
bd5a4e33ab | ||
|
|
d7360f8709 | ||
|
|
6249a129c0 | ||
|
|
21612794c5 | ||
|
|
fa2d633313 | ||
|
|
09ca46fbd0 | ||
|
|
cf97ef7ad1 | ||
|
|
963bb28f0f | ||
|
|
0cc980b26a | ||
|
|
a2d8fc1ef9 | ||
|
|
18392610c9 | ||
|
|
fc13e21e73 | ||
|
|
a346eb3e12 | ||
|
|
ef99cac28f | ||
|
|
02d509fc5f | ||
|
|
ac55ccf46e | ||
|
|
bd96190bbc | ||
|
|
61e516c4ac | ||
|
|
66c327805f | ||
|
|
31487c1cf1 | ||
|
|
3e972b501a | ||
|
|
59c758fa1c | ||
|
|
10ca375284 | ||
|
|
76f732058a | ||
|
|
a4aab7dbd1 | ||
|
|
0090af6b3b | ||
|
|
de141c49c5 | ||
|
|
892d0ee162 | ||
|
|
e8485ee6c5 | ||
|
|
e668bbbade | ||
|
|
cbea6bf41f | ||
|
|
35e88ea62c | ||
|
|
6c97b63e59 | ||
|
|
ed1271c30b | ||
|
|
b496e8ef29 | ||
|
|
375813e5e2 | ||
|
|
dd06c71735 | ||
|
|
364279e0f7 | ||
|
|
415ac8fa46 | ||
|
|
fc5d7835c0 | ||
|
|
b55d6cbf75 | ||
|
|
d5283fca09 | ||
|
|
311f843ea1 | ||
|
|
3f4c9a8326 | ||
|
|
e570f10d69 | ||
|
|
97e18b9ed4 | ||
|
|
c56d56c2d1 | ||
|
|
4e2f694a0d | ||
|
|
892b9d041d | ||
|
|
ea58ebed50 | ||
|
|
adb7e1b598 | ||
|
|
b9f6ea68ce | ||
|
|
63bb4c4d0a | ||
|
|
5c40300474 | ||
|
|
6ca9e16670 | ||
|
|
deb2b984eb | ||
|
|
0d7674b934 | ||
|
|
fc1dd51e63 | ||
|
|
0815050b2a | ||
|
|
36078382e4 | ||
|
|
34f4731c9b | ||
|
|
6e2799f048 | ||
|
|
ba8b495ec0 | ||
|
|
b62fb4a318 | ||
|
|
9353a060f2 | ||
|
|
5aafe89d95 | ||
|
|
7a55c07e22 | ||
|
|
9ffbb51fd1 | ||
|
|
f3b460c8b4 | ||
|
|
0329150109 | ||
|
|
264a63b7f6 | ||
|
|
70e3cffa90 | ||
|
|
fc046fb8ca | ||
|
|
9acf37e99d | ||
|
|
1645cb2dd0 | ||
|
|
12e635a411 | ||
|
|
b40a96f545 | ||
|
|
64f148cb6e | ||
|
|
4d31537add | ||
|
|
ecd77d6c48 | ||
|
|
5716671dcf | ||
|
|
6bdd26506c | ||
|
|
5858de0b08 | ||
|
|
ffc9f10399 | ||
|
|
0f0a3eb822 | ||
|
|
9ba5f9f2a3 | ||
|
|
ecb7cd3c66 | ||
|
|
293f88599d | ||
|
|
55f9411493 | ||
|
|
4232397aa8 | ||
|
|
ee029de5e7 | ||
|
|
34e7edb5f5 | ||
|
|
03ac153417 | ||
|
|
8a88ee7f90 | ||
|
|
d6113b6147 | ||
|
|
7306bcc35a | ||
|
|
77216af44e | ||
|
|
ffbff0d765 | ||
|
|
9431011ba5 | ||
|
|
44fdf4022e | ||
|
|
09b1066122 | ||
|
|
ecbf9a7706 | ||
|
|
ab1108b731 | ||
|
|
f0053f15bf | ||
|
|
4175f891fb | ||
|
|
c207297c57 | ||
|
|
6ca70b0156 | ||
|
|
6e6aef62c6 | ||
|
|
27d7337abf | ||
|
|
66c5affa65 | ||
|
|
be4197351a | ||
|
|
4dcbf28714 | ||
|
|
4c67856dd6 | ||
|
|
1c81f6097f | ||
|
|
7f5654bb06 | ||
|
|
534af65f7c | ||
|
|
73dc55d8ef | ||
|
|
225bc86d73 | ||
|
|
3b48926d75 | ||
|
|
b38a014b02 | ||
|
|
aed1a0d985 | ||
|
|
9cb37a6376 | ||
|
|
6be135a137 | ||
|
|
20c387158a | ||
|
|
88920696f3 | ||
|
|
3c476d2b40 | ||
|
|
72ba0d9458 | ||
|
|
c95f17f54b | ||
|
|
f116e887ea | ||
|
|
d2a1309cb6 | ||
|
|
73ab543cc2 | ||
|
|
96eb4afdf6 | ||
|
|
3a25395ff9 | ||
|
|
afd1215b03 | ||
|
|
d4384aef73 | ||
|
|
a2e6500d54 | ||
|
|
418522b714 | ||
|
|
e142155b01 | ||
|
|
844518d921 | ||
|
|
589d52158c | ||
|
|
e5090cd10d | ||
|
|
0071321c53 | ||
|
|
7b9038e6da | ||
|
|
b59c1a2b0f | ||
|
|
8b593d28c6 | ||
|
|
4b30c7e710 | ||
|
|
d7505ca8b5 | ||
|
|
831af2f157 | ||
|
|
ab954c9f53 | ||
|
|
7c3cf945cf | ||
|
|
b38e780f01 | ||
|
|
89c485200b | ||
|
|
c759d35dea | ||
|
|
81fd26f5db | ||
|
|
7753ae7c3a | ||
|
|
41cb27dd67 | ||
|
|
d3947c73ab | ||
|
|
4cd99fc624 | ||
|
|
3c09c18943 | ||
|
|
6079950220 | ||
|
|
8c59d2e3b9 | ||
|
|
fb9dbd8e16 | ||
|
|
7454c62ff2 | ||
|
|
cf234fe66f | ||
|
|
ca9cc36a93 | ||
|
|
7422d9148a | ||
|
|
6c76c5d917 | ||
|
|
687d22188a | ||
|
|
b996466b3d | ||
|
|
02da078baf | ||
|
|
121d440ac9 | ||
|
|
a246d7e48d | ||
|
|
ed60c41c35 | ||
|
|
3488ca0173 | ||
|
|
de334904b4 | ||
|
|
8cf5195db6 | ||
|
|
041038fa1b | ||
|
|
151d3a3672 | ||
|
|
1d9d01b355 | ||
|
|
d5ec234fd3 | ||
|
|
e95bf0a642 | ||
|
|
a7f1520d1f | ||
|
|
d9628d39eb | ||
|
|
bb20243b05 | ||
|
|
e5d9634cfe | ||
|
|
d3053c3c8c |
@@ -1,5 +1,5 @@
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2017
|
||||
image: Visual Studio 2019
|
||||
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
@@ -12,10 +12,9 @@ build:
|
||||
before_build:
|
||||
- cmd: py -3 -m pip install --user requests
|
||||
- cmd: py -3 RUN_THIS.py --no-prompt
|
||||
- cmd: nuget restore SpaceStation14.sln
|
||||
|
||||
build_script:
|
||||
- ps: msbuild SpaceStation14.sln /v:m /nologo /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Platform=x64 /p:Configuration=Debug /p:AppVeyor=yes
|
||||
- ps: dotnet build SpaceStation14.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:AppVeyor=yes
|
||||
|
||||
test:
|
||||
assemblies:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -261,7 +261,8 @@ __pycache__/
|
||||
*.pyc
|
||||
|
||||
# Visual Studio Code workspace settings.
|
||||
.vscode/
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Release package files go here:
|
||||
release/
|
||||
|
||||
10
.travis.yml
10
.travis.yml
@@ -2,6 +2,8 @@ language: csharp
|
||||
|
||||
dist: trusty
|
||||
sudo: false
|
||||
mono: none
|
||||
# dotnet: 3.1.100 # Travis is shitting itself right now and it can't locate .NET Core packages.
|
||||
|
||||
os:
|
||||
- linux
|
||||
@@ -20,7 +22,9 @@ cache:
|
||||
directories:
|
||||
- packages/
|
||||
- RobustToolbox/Dependencies/
|
||||
- RobustToolbox/SS14.Client.Godot/.mono/assemblies/
|
||||
|
||||
install:
|
||||
- curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --version 3.1.100
|
||||
|
||||
#before_install:
|
||||
# - if [ $TRAVIS_OS_NAME = osx ]; then brew update && brew upgrade python; fi
|
||||
@@ -28,11 +32,9 @@ cache:
|
||||
before_script:
|
||||
#- "if [ $TRAVIS_OS_NAME = linux ]; then pyenv shell 3.6; fi"
|
||||
- "python3.5 -m pip install --user requests"
|
||||
- "nuget restore SpaceStation14.sln"
|
||||
- "python3.5 RUN_THIS.py --no-prompt"
|
||||
|
||||
script:
|
||||
- "msbuild /p:Configuration=Debug /p:Platform=x64 /nologo /m SpaceStation14.sln /p:Python=python3.5"
|
||||
- "mono packages/nunit.consolerunner/3.10.0/tools/nunit3-console.exe bin/Content.Tests/Content.Tests.dll bin/Content.IntegrationTests/Content.IntegrationTests.dll"
|
||||
- "Tools/run_travis.sh"
|
||||
|
||||
|
||||
|
||||
6
.vscode/extensions.json
vendored
Normal file
6
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-vscode.csharp",
|
||||
"editorconfig.editorconfig"
|
||||
]
|
||||
}
|
||||
3
BuildChecker/.gitignore
vendored
3
BuildChecker/.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
INSTALLED_HOOKS_VERSION
|
||||
DISABLE_SUBMODULE_AUTOUPDATE
|
||||
*.nuget*
|
||||
project.assets.json
|
||||
project.packagespec.json
|
||||
@@ -17,7 +17,7 @@ https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild
|
||||
<Python>python3</Python>
|
||||
<Python Condition="'$(OS)'=='Windows_NT' Or '$(OS)'=='Windows'">py -3</Python>
|
||||
<ProjectGuid>{C899FCA4-7037-4E49-ABC2-44DE72487110}</ProjectGuid>
|
||||
<TargetFrameworkMoniker>.NETFramework, Version=v4.7.1</TargetFrameworkMoniker>
|
||||
<TargetFrameworkMoniker>.NETFramework, Version=v4.7.2</TargetFrameworkMoniker>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
@@ -83,7 +83,7 @@ def install_hooks():
|
||||
|
||||
for filename in os.listdir(str(hooks_source_dir)):
|
||||
print("Copying hook {}".format(filename))
|
||||
shutil.copyfile(str(hooks_source_dir/filename),
|
||||
shutil.copy2(str(hooks_source_dir/filename),
|
||||
str(hooks_target_dir/filename))
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
exec mono bin/SS14.Launcher.exe
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleName</key>
|
||||
<string>SS14L</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Space Station 14 Launcher</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>SS14</string>
|
||||
<!--
|
||||
Just a note about this icon.
|
||||
MacOS seems REALLY iffy about this and even when the file is correct,
|
||||
it can take forever before it decides to actually update it and display it.
|
||||
TL;DR Apple is stupid.
|
||||
-->
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>ss14</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# cd to file containing script or something?
|
||||
BASEDIR=$(dirname "$0")
|
||||
echo "$BASEDIR"
|
||||
cd "$BASEDIR"
|
||||
|
||||
exec /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono ../Resources/SS14.Launcher.exe
|
||||
Binary file not shown.
@@ -5,4 +5,4 @@ BASEDIR=$(dirname "$0")
|
||||
echo "$BASEDIR"
|
||||
cd "$BASEDIR"
|
||||
|
||||
exec /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono ../Resources/Robust.Client.exe
|
||||
exec ../Resources/Robust.Client "$@"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
call bin\SS14.Launcher.exe
|
||||
166
Content.Benchmarks/ColorInterpolateBenchmark.cs
Normal file
166
Content.Benchmarks/ColorInterpolateBenchmark.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
#if NETCOREAPP
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
#endif
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Content.Benchmarks
|
||||
{
|
||||
[DisassemblyDiagnoser]
|
||||
public class ColorInterpolateBenchmark
|
||||
{
|
||||
#if NETCOREAPP
|
||||
private const MethodImplOptions AggressiveOpt = MethodImplOptions.AggressiveOptimization;
|
||||
#else
|
||||
private const MethodImplOptions AggressiveOpt = default;
|
||||
#endif
|
||||
|
||||
private (Color, Color)[] _colors;
|
||||
private Color[] _output;
|
||||
|
||||
[Params(100)] public int N { get; set; }
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var random = new Random(3005);
|
||||
|
||||
_colors = new (Color, Color)[N];
|
||||
_output = new Color[N];
|
||||
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
var r1 = random.NextFloat();
|
||||
var g1 = random.NextFloat();
|
||||
var b1 = random.NextFloat();
|
||||
var a1 = random.NextFloat();
|
||||
|
||||
var r2 = random.NextFloat();
|
||||
var g2 = random.NextFloat();
|
||||
var b2 = random.NextFloat();
|
||||
var a2 = random.NextFloat();
|
||||
|
||||
_colors[i] = (new Color(r1, g1, b1, a1), new Color(r2, g2, b2, a2));
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void BenchSimple()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
ref var tuple = ref _colors[i];
|
||||
_output[i] = InterpolateSimple(tuple.Item1, tuple.Item2, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Benchmark]
|
||||
public void BenchSysVector4In()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
ref var tuple = ref _colors[i];
|
||||
_output[i] = InterpolateSysVector4In(tuple.Item1, tuple.Item2, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void BenchSysVector4()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
ref var tuple = ref _colors[i];
|
||||
_output[i] = InterpolateSysVector4(tuple.Item1, tuple.Item2, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP
|
||||
[Benchmark]
|
||||
public void BenchSimd()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
ref var tuple = ref _colors[i];
|
||||
_output[i] = InterpolateSimd(tuple.Item1, tuple.Item2, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void BenchSimdIn()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
ref var tuple = ref _colors[i];
|
||||
_output[i] = InterpolateSimdIn(tuple.Item1, tuple.Item2, 0.5f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[MethodImpl(AggressiveOpt)]
|
||||
public static Color InterpolateSimple(Color a, Color b, float lambda)
|
||||
{
|
||||
return new Color(
|
||||
a.R + (b.R - a.R) * lambda,
|
||||
a.G + (b.G - a.G) * lambda,
|
||||
a.B + (b.G - a.B) * lambda,
|
||||
a.A + (b.A - a.A) * lambda
|
||||
);
|
||||
}
|
||||
|
||||
[MethodImpl(AggressiveOpt)]
|
||||
public static Color InterpolateSysVector4(Color a, Color b,
|
||||
float lambda)
|
||||
{
|
||||
ref var sva = ref Unsafe.As<Color, SysVector4>(ref a);
|
||||
ref var svb = ref Unsafe.As<Color, SysVector4>(ref b);
|
||||
|
||||
var res = SysVector4.Lerp(sva, svb, lambda);
|
||||
|
||||
return Unsafe.As<SysVector4, Color>(ref res);
|
||||
}
|
||||
|
||||
[MethodImpl(AggressiveOpt)]
|
||||
public static Color InterpolateSysVector4In(in Color endPoint1, in Color endPoint2,
|
||||
float lambda)
|
||||
{
|
||||
ref var sva = ref Unsafe.As<Color, SysVector4>(ref Unsafe.AsRef(endPoint1));
|
||||
ref var svb = ref Unsafe.As<Color, SysVector4>(ref Unsafe.AsRef(endPoint2));
|
||||
|
||||
var res = SysVector4.Lerp(svb, sva, lambda);
|
||||
|
||||
return Unsafe.As<SysVector4, Color>(ref res);
|
||||
}
|
||||
|
||||
#if NETCOREAPP
|
||||
[MethodImpl(AggressiveOpt)]
|
||||
public static Color InterpolateSimd(Color a, Color b,
|
||||
float lambda)
|
||||
{
|
||||
var vecA = Unsafe.As<Color, Vector128<float>>(ref a);
|
||||
var vecB = Unsafe.As<Color, Vector128<float>>(ref b);
|
||||
|
||||
vecB = Fma.MultiplyAdd(Sse.Subtract(vecB, vecA), Vector128.Create(lambda), vecA);
|
||||
|
||||
return Unsafe.As<Vector128<float>, Color>(ref vecB);
|
||||
}
|
||||
|
||||
[MethodImpl(AggressiveOpt)]
|
||||
public static Color InterpolateSimdIn(in Color a, in Color b,
|
||||
float lambda)
|
||||
{
|
||||
var vecA = Unsafe.As<Color, Vector128<float>>(ref Unsafe.AsRef(a));
|
||||
var vecB = Unsafe.As<Color, Vector128<float>>(ref Unsafe.AsRef(b));
|
||||
|
||||
vecB = Fma.MultiplyAdd(Sse.Subtract(vecB, vecA), Vector128.Create(lambda), vecA);
|
||||
|
||||
return Unsafe.As<Vector128<float>, Color>(ref vecB);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace Content.Benchmarks
|
||||
dummyReg.SetupGet(p => p.Type).Returns(typeof(DummyComponent));
|
||||
dummyReg.SetupGet(p => p.NetID).Returns((uint?) null);
|
||||
dummyReg.SetupGet(p => p.NetworkSynchronizeExistence).Returns(false);
|
||||
dummyReg.SetupGet(p => p.References).Returns(new Type[] {typeof(DummyComponent)});
|
||||
dummyReg.SetupGet(p => p.References).Returns(new [] {typeof(DummyComponent)});
|
||||
|
||||
var componentFactory = new Mock<IComponentFactory>();
|
||||
componentFactory.Setup(p => p.GetComponent<DummyComponent>()).Returns(new DummyComponent());
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<!-- Work around https://github.com/dotnet/project-system/issues/4314 -->
|
||||
<TargetFramework>$(TargetFramework)</TargetFramework>
|
||||
<OutputPath>..\bin\Content.Benchmarks\</OutputPath>
|
||||
<IsPackable>false</IsPackable>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<Platforms>x86;x64</Platforms>
|
||||
<Platforms>x64</Platforms>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>8</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Content.Client\Content.Client.csproj" />
|
||||
|
||||
69
Content.Benchmarks/DependencyInjectBenchmark.cs
Normal file
69
Content.Benchmarks/DependencyInjectBenchmark.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Benchmarks
|
||||
{
|
||||
// To actually run this benchmark you'll have to make DependencyCollection public so it's accessible.
|
||||
|
||||
public class DependencyInjectBenchmark
|
||||
{
|
||||
[Params(InjectMode.Reflection, InjectMode.DynamicMethod)]
|
||||
public InjectMode Mode { get; set; }
|
||||
|
||||
private DependencyCollection _dependencyCollection;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_dependencyCollection = new DependencyCollection();
|
||||
_dependencyCollection.Register<X1, X1>();
|
||||
_dependencyCollection.Register<X2, X2>();
|
||||
_dependencyCollection.Register<X3, X3>();
|
||||
_dependencyCollection.Register<X4, X4>();
|
||||
_dependencyCollection.Register<X5, X5>();
|
||||
|
||||
_dependencyCollection.BuildGraph();
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case InjectMode.Reflection:
|
||||
break;
|
||||
case InjectMode.DynamicMethod:
|
||||
// Running this without oneOff will cause DependencyCollection to cache the DynamicMethod injector.
|
||||
// So future injections (even with oneOff) will keep using the DynamicMethod.
|
||||
// AKA, be fast.
|
||||
_dependencyCollection.InjectDependencies(new TestDummy());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Inject()
|
||||
{
|
||||
_dependencyCollection.InjectDependencies(new TestDummy(), true);
|
||||
}
|
||||
|
||||
public enum InjectMode
|
||||
{
|
||||
Reflection,
|
||||
DynamicMethod
|
||||
}
|
||||
|
||||
private sealed class X1 { }
|
||||
private sealed class X2 { }
|
||||
private sealed class X3 { }
|
||||
private sealed class X4 { }
|
||||
private sealed class X5 { }
|
||||
|
||||
private sealed class TestDummy
|
||||
{
|
||||
[Dependency] private readonly X1 _x1;
|
||||
[Dependency] private readonly X2 _x2;
|
||||
[Dependency] private readonly X3 _x3;
|
||||
[Dependency] private readonly X4 _x4;
|
||||
[Dependency] private readonly X5 _x5;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,9 +1,8 @@
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
namespace Content.Benchmarks
|
||||
{
|
||||
internal class Program
|
||||
internal static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
||||
3
Content.Client/AssemblyInfo.cs
Normal file
3
Content.Client/AssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Content.Tests")]
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client.Chat
|
||||
{
|
||||
@@ -21,15 +21,15 @@ namespace Content.Client.Chat
|
||||
|
||||
private readonly IList<string> _inputHistory = new List<string>();
|
||||
|
||||
private ILocalizationManager localize = IoCManager.Resolve<ILocalizationManager>();
|
||||
private readonly ILocalizationManager localize = IoCManager.Resolve<ILocalizationManager>();
|
||||
|
||||
public LineEdit Input { get; private set; }
|
||||
public OutputPanel contents;
|
||||
public OutputPanel Contents { get; }
|
||||
|
||||
// Buttons for filtering
|
||||
public Button AllButton;
|
||||
public Button LocalButton;
|
||||
public Button OOCButton;
|
||||
public Button AllButton { get; }
|
||||
public Button LocalButton { get; }
|
||||
public Button OOCButton { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Index while cycling through the input history. -1 means not going through history.
|
||||
@@ -48,17 +48,15 @@ namespace Content.Client.Chat
|
||||
|
||||
public bool ReleaseFocusOnEnter { get; set; } = true;
|
||||
|
||||
protected override void Initialize()
|
||||
public ChatBox()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
MarginLeft = -475.0f;
|
||||
/*MarginLeft = -475.0f;
|
||||
MarginTop = 10.0f;
|
||||
MarginRight = -10.0f;
|
||||
MarginBottom = 235.0f;
|
||||
|
||||
AnchorLeft = 1.0f;
|
||||
AnchorRight = 1.0f;
|
||||
AnchorRight = 1.0f;*/
|
||||
|
||||
var outerVBox = new VBoxContainer();
|
||||
|
||||
@@ -79,12 +77,12 @@ namespace Content.Client.Chat
|
||||
MarginLeftOverride = 4, MarginRightOverride = 4,
|
||||
SizeFlagsVertical = SizeFlags.FillExpand
|
||||
};
|
||||
contents = new OutputPanel();
|
||||
contentMargin.AddChild(contents);
|
||||
Contents = new OutputPanel();
|
||||
contentMargin.AddChild(Contents);
|
||||
vBox.AddChild(contentMargin);
|
||||
|
||||
Input = new LineEdit();
|
||||
Input.OnKeyDown += InputKeyDown;
|
||||
Input.OnKeyBindDown += InputKeyBindDown;
|
||||
Input.OnTextEntered += Input_OnTextEntered;
|
||||
vBox.AddChild(Input);
|
||||
|
||||
@@ -121,23 +119,27 @@ namespace Content.Client.Chat
|
||||
AddChild(outerVBox);
|
||||
}
|
||||
|
||||
protected override void MouseDown(GUIMouseButtonEventArgs e)
|
||||
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.MouseDown(e);
|
||||
base.KeyBindDown(args);
|
||||
|
||||
if (!args.CanFocus)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Input.GrabKeyboardFocus();
|
||||
}
|
||||
|
||||
private void InputKeyDown(GUIKeyEventArgs e)
|
||||
private void InputKeyBindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
if (e.Key == Keyboard.Key.Escape)
|
||||
if (args.Function == EngineKeyFunctions.TextReleaseFocus)
|
||||
{
|
||||
Input.ReleaseKeyboardFocus();
|
||||
e.Handle();
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Key == Keyboard.Key.Up)
|
||||
else if (args.Function == EngineKeyFunctions.TextHistoryPrev)
|
||||
{
|
||||
if (_inputIndex == -1 && _inputHistory.Count != 0)
|
||||
{
|
||||
@@ -153,12 +155,12 @@ namespace Content.Client.Chat
|
||||
{
|
||||
Input.Text = _inputHistory[_inputIndex];
|
||||
}
|
||||
Input.CursorPos = Input.Text.Length;
|
||||
|
||||
e.Handle();
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Key == Keyboard.Key.Down)
|
||||
else if (args.Function == EngineKeyFunctions.TextHistoryNext)
|
||||
{
|
||||
if (_inputIndex == 0)
|
||||
{
|
||||
@@ -171,20 +173,9 @@ namespace Content.Client.Chat
|
||||
_inputIndex--;
|
||||
Input.Text = _inputHistory[_inputIndex];
|
||||
}
|
||||
Input.CursorPos = Input.Text.Length;
|
||||
|
||||
e.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
TextSubmitted = null;
|
||||
Input = null;
|
||||
contents = null;
|
||||
args.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +194,7 @@ namespace Content.Client.Chat
|
||||
formatted.PushColor(color);
|
||||
formatted.AddText(message);
|
||||
formatted.Pop();
|
||||
contents.AddMessage(formatted);
|
||||
Contents.AddMessage(formatted);
|
||||
}
|
||||
|
||||
private void Input_OnTextEntered(LineEdit.LineEditEventArgs args)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
@@ -13,6 +12,7 @@ using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Chat
|
||||
@@ -81,13 +81,16 @@ namespace Content.Client.Chat
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgChatMessage>(MsgChatMessage.NAME, _onChatMessage);
|
||||
|
||||
_speechBubbleRoot = new Control();
|
||||
_speechBubbleRoot.SetAnchorPreset(Control.LayoutPreset.Wide);
|
||||
_speechBubbleRoot = new LayoutContainer
|
||||
{
|
||||
MouseFilter = Control.MouseFilterMode.Ignore
|
||||
};
|
||||
LayoutContainer.SetAnchorPreset(_speechBubbleRoot, LayoutContainer.LayoutPreset.Wide);
|
||||
_userInterfaceManager.StateRoot.AddChild(_speechBubbleRoot);
|
||||
_speechBubbleRoot.SetPositionFirst();
|
||||
}
|
||||
|
||||
public void FrameUpdate(RenderFrameEventArgs delta)
|
||||
public void FrameUpdate(FrameEventArgs delta)
|
||||
{
|
||||
// Update queued speech bubbles.
|
||||
if (_queuedSpeechBubbles.Count == 0)
|
||||
@@ -103,7 +106,7 @@ namespace Content.Client.Chat
|
||||
continue;
|
||||
}
|
||||
|
||||
queueData.TimeLeft -= delta.Elapsed;
|
||||
queueData.TimeLeft -= delta.DeltaSeconds;
|
||||
if (queueData.TimeLeft > 0)
|
||||
{
|
||||
continue;
|
||||
@@ -270,7 +273,7 @@ namespace Content.Client.Chat
|
||||
|
||||
private void RepopulateChat(IEnumerable<StoredChatMessage> filteredMessages)
|
||||
{
|
||||
_currentChatBox.contents.Clear();
|
||||
_currentChatBox.Contents.Clear();
|
||||
|
||||
foreach (var msg in filteredMessages)
|
||||
{
|
||||
@@ -328,7 +331,7 @@ namespace Content.Client.Chat
|
||||
{
|
||||
// Word is STILL too long.
|
||||
// Truncate it with an ellipse.
|
||||
messages.Add($"{word.Substring(0, SingleBubbleCharLimit-3)}...");
|
||||
messages.Add($"{word.Substring(0, SingleBubbleCharLimit - 3)}...");
|
||||
currentWordLength = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timers;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Chat
|
||||
{
|
||||
@@ -31,14 +31,12 @@ namespace Content.Client.Chat
|
||||
private readonly IEntity _senderEntity;
|
||||
private readonly IChatManager _chatManager;
|
||||
|
||||
private Control _panel;
|
||||
|
||||
private float _timeLeft = TotalTime;
|
||||
|
||||
public float VerticalOffset { get; set; }
|
||||
private float _verticalOffsetAchieved;
|
||||
|
||||
public float ContentHeight { get; }
|
||||
public float ContentHeight { get; private set; }
|
||||
|
||||
public SpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
|
||||
{
|
||||
@@ -57,7 +55,7 @@ namespace Content.Client.Chat
|
||||
};
|
||||
label.SetMessage(text);
|
||||
|
||||
_panel = new PanelContainer
|
||||
var panel = new PanelContainer
|
||||
{
|
||||
StyleClasses = { "tooltipBox" },
|
||||
Children = { label },
|
||||
@@ -65,19 +63,24 @@ namespace Content.Client.Chat
|
||||
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
|
||||
};
|
||||
|
||||
AddChild(_panel);
|
||||
AddChild(panel);
|
||||
|
||||
_panel.Size = _panel.CombinedMinimumSize;
|
||||
ContentHeight = _panel.Height;
|
||||
Size = (_panel.Width, 0);
|
||||
ForceRunStyleUpdate();
|
||||
|
||||
ContentHeight = panel.CombinedMinimumSize.Y;
|
||||
_verticalOffsetAchieved = -ContentHeight;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(RenderFrameEventArgs args)
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return (base.CalculateMinimumSize().X, 0);
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
_timeLeft -= args.Elapsed;
|
||||
_timeLeft -= args.DeltaSeconds;
|
||||
|
||||
if (_timeLeft <= FadeTime)
|
||||
{
|
||||
@@ -99,7 +102,7 @@ namespace Content.Client.Chat
|
||||
}
|
||||
else
|
||||
{
|
||||
_verticalOffsetAchieved = FloatMath.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.Elapsed);
|
||||
_verticalOffsetAchieved = FloatMath.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.DeltaSeconds);
|
||||
}
|
||||
|
||||
var worldPos = _senderEntity.Transform.WorldPosition;
|
||||
@@ -107,10 +110,10 @@ namespace Content.Client.Chat
|
||||
|
||||
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
|
||||
var screenPos = lowerCenter - (Width / 2, ContentHeight + _verticalOffsetAchieved);
|
||||
Position = screenPos;
|
||||
LayoutContainer.SetPosition(this, screenPos);
|
||||
|
||||
var height = (lowerCenter.Y - screenPos.Y).Clamp(0, ContentHeight);
|
||||
Size = (Size.X, height);
|
||||
LayoutContainer.SetSize(this, (Size.X, height));
|
||||
}
|
||||
|
||||
private void Die()
|
||||
|
||||
32
Content.Client/ClientContentIoC.cs
Normal file
32
Content.Client/ClientContentIoC.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Content.Client.Chat;
|
||||
using Content.Client.GameTicking;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Client.Interfaces.Parallax;
|
||||
using Content.Client.Parallax;
|
||||
using Content.Client.Sandbox;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client
|
||||
{
|
||||
internal static class ClientContentIoC
|
||||
{
|
||||
public static void Register()
|
||||
{
|
||||
IoCManager.Register<IGameHud, GameHud>();
|
||||
IoCManager.Register<IClientNotifyManager, ClientNotifyManager>();
|
||||
IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>();
|
||||
IoCManager.Register<IClientGameTicker, ClientGameTicker>();
|
||||
IoCManager.Register<IParallaxManager, ParallaxManager>();
|
||||
IoCManager.Register<IChatManager, ChatManager>();
|
||||
IoCManager.Register<IEscapeMenuOwner, EscapeMenuOwner>();
|
||||
IoCManager.Register<ISandboxManager, SandboxManager>();
|
||||
IoCManager.Register<IModuleManager, ClientModuleManager>();
|
||||
IoCManager.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
||||
IoCManager.Register<IItemSlotManager, ItemSlotManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Shared;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
@@ -14,6 +13,7 @@ using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client
|
||||
@@ -59,8 +59,8 @@ namespace Content.Client
|
||||
{
|
||||
var label = new PopupLabel {Text = message};
|
||||
var minimumSize = label.CombinedMinimumSize;
|
||||
label.InitialPos = label.Position = coordinates.Position - minimumSize / 2;
|
||||
_userInterfaceManager.StateRoot.AddChild(label);
|
||||
LayoutContainer.SetPosition(label, label.InitialPos = coordinates.Position - minimumSize / 2);
|
||||
_userInterfaceManager.PopupRoot.AddChild(label);
|
||||
_aliveLabels.Add(label);
|
||||
}
|
||||
|
||||
@@ -69,42 +69,38 @@ namespace Content.Client
|
||||
PopupMessage(new ScreenCoordinates(_inputManager.MouseScreenPosition), message);
|
||||
}
|
||||
|
||||
public void FrameUpdate(RenderFrameEventArgs eventArgs)
|
||||
public void FrameUpdate(FrameEventArgs eventArgs)
|
||||
{
|
||||
foreach (var label in _aliveLabels)
|
||||
_aliveLabels.ForEach(l =>
|
||||
{
|
||||
label.Update(eventArgs);
|
||||
}
|
||||
if (l.TimeLeft > 3f)
|
||||
{
|
||||
l.Dispose();
|
||||
}
|
||||
});
|
||||
|
||||
_aliveLabels.RemoveAll(l => l.Disposed);
|
||||
}
|
||||
|
||||
private class PopupLabel : Label
|
||||
{
|
||||
private float _timeLeft;
|
||||
public float TimeLeft { get; private set; }
|
||||
public Vector2 InitialPos { get; set; }
|
||||
|
||||
protected override void Initialize()
|
||||
public PopupLabel()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
ShadowOffsetXOverride = 1;
|
||||
ShadowOffsetYOverride = 1;
|
||||
FontColorShadowOverride = Color.Black;
|
||||
|
||||
}
|
||||
|
||||
public void Update(RenderFrameEventArgs eventArgs)
|
||||
protected override void Update(FrameEventArgs eventArgs)
|
||||
{
|
||||
_timeLeft += eventArgs.Elapsed;
|
||||
Position = InitialPos - new Vector2(0, 20 * (_timeLeft * _timeLeft + _timeLeft));
|
||||
if (_timeLeft > 0.5f)
|
||||
TimeLeft += eventArgs.DeltaSeconds;
|
||||
LayoutContainer.SetPosition(this, InitialPos - (0, 20 * (TimeLeft * TimeLeft + TimeLeft)));
|
||||
if (TimeLeft > 0.5f)
|
||||
{
|
||||
Modulate = Color.White.WithAlpha(1f - 0.2f * (float)Math.Pow(_timeLeft - 0.5f, 3f));
|
||||
if (_timeLeft > 3f)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
Modulate = Color.White.WithAlpha(1f - 0.2f * (float)Math.Pow(TimeLeft - 0.5f, 3f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
74
Content.Client/ClientPreferencesManager.cs
Normal file
74
Content.Client/ClientPreferencesManager.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Shared.Preferences;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Receives <see cref="PlayerPreferences" /> and <see cref="GameSettings" /> from the server during the initial
|
||||
/// connection.
|
||||
/// Stores preferences on the server through <see cref="SelectCharacter" /> and <see cref="UpdateCharacter" />.
|
||||
/// </summary>
|
||||
public class ClientPreferencesManager : SharedPreferencesManager, IClientPreferencesManager
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IClientNetManager _netManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
public GameSettings Settings { get; private set; }
|
||||
public PlayerPreferences Preferences { get; private set; }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgPreferencesAndSettings>(nameof(MsgPreferencesAndSettings),
|
||||
HandlePreferencesAndSettings);
|
||||
}
|
||||
|
||||
public void SelectCharacter(ICharacterProfile profile)
|
||||
{
|
||||
SelectCharacter(Preferences.IndexOfCharacter(profile));
|
||||
}
|
||||
|
||||
public void SelectCharacter(int slot)
|
||||
{
|
||||
Preferences = new PlayerPreferences(Preferences.Characters, slot);
|
||||
var msg = _netManager.CreateNetMessage<MsgSelectCharacter>();
|
||||
msg.SelectedCharacterIndex = slot;
|
||||
_netManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
public void UpdateCharacter(ICharacterProfile profile, int slot)
|
||||
{
|
||||
var characters = Preferences.Characters.ToArray();
|
||||
characters[slot] = profile;
|
||||
Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex);
|
||||
var msg = _netManager.CreateNetMessage<MsgUpdateCharacter>();
|
||||
msg.Profile = profile;
|
||||
msg.Slot = slot;
|
||||
_netManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
public void CreateCharacter(ICharacterProfile profile)
|
||||
{
|
||||
UpdateCharacter(profile, Preferences.FirstEmptySlot);
|
||||
}
|
||||
|
||||
public void DeleteCharacter(ICharacterProfile profile)
|
||||
{
|
||||
DeleteCharacter(Preferences.IndexOfCharacter(profile));
|
||||
}
|
||||
|
||||
public void DeleteCharacter(int slot)
|
||||
{
|
||||
UpdateCharacter(null, slot);
|
||||
}
|
||||
|
||||
private void HandlePreferencesAndSettings(MsgPreferencesAndSettings message)
|
||||
{
|
||||
Preferences = message.Preferences;
|
||||
Settings = message.Settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,62 +3,50 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using Content.Shared.Construction;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Placement;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Construction
|
||||
{
|
||||
public class ConstructionMenu : SS14Window
|
||||
{
|
||||
|
||||
#pragma warning disable CS0649
|
||||
[Dependency]
|
||||
readonly IPrototypeManager PrototypeManager;
|
||||
[Dependency]
|
||||
readonly IResourceCache ResourceCache;
|
||||
[Dependency] readonly IPrototypeManager PrototypeManager;
|
||||
[Dependency] readonly IResourceCache ResourceCache;
|
||||
#pragma warning restore
|
||||
|
||||
public ConstructorComponent Owner { get; set; }
|
||||
Button BuildButton;
|
||||
Button EraseButton;
|
||||
LineEdit SearchBar;
|
||||
Tree RecipeList;
|
||||
TextureRect InfoIcon;
|
||||
Label InfoLabel;
|
||||
ItemList StepList;
|
||||
private readonly Button BuildButton;
|
||||
private readonly Button EraseButton;
|
||||
private readonly LineEdit SearchBar;
|
||||
private readonly Tree RecipeList;
|
||||
private readonly TextureRect InfoIcon;
|
||||
private readonly Label InfoLabel;
|
||||
private readonly ItemList StepList;
|
||||
|
||||
private CategoryNode RootCategory;
|
||||
|
||||
CategoryNode RootCategory;
|
||||
// This list is flattened in such a way that the top most deepest category is first.
|
||||
List<CategoryNode> FlattenedCategories;
|
||||
PlacementManager Placement;
|
||||
private List<CategoryNode> FlattenedCategories;
|
||||
private readonly PlacementManager Placement;
|
||||
|
||||
protected override Vector2? CustomSize => (500, 350);
|
||||
|
||||
public ConstructionMenu()
|
||||
{
|
||||
Size = new Vector2(500.0f, 350.0f);
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
IoCManager.InjectDependencies(this);
|
||||
Placement = (PlacementManager)IoCManager.Resolve<IPlacementManager>();
|
||||
Placement = (PlacementManager) IoCManager.Resolve<IPlacementManager>();
|
||||
Placement.PlacementCanceled += OnPlacementCanceled;
|
||||
|
||||
Title = "Construction";
|
||||
@@ -66,18 +54,18 @@ namespace Content.Client.Construction
|
||||
var hSplitContainer = new HSplitContainer();
|
||||
|
||||
// Left side
|
||||
var recipes = new VBoxContainer("Recipes") {CustomMinimumSize = new Vector2(150.0f, 0.0f)};
|
||||
SearchBar = new LineEdit("Search") {PlaceHolder = "Search"};
|
||||
RecipeList = new Tree("Tree") {SizeFlagsVertical = SizeFlags.FillExpand, HideRoot = true};
|
||||
var recipes = new VBoxContainer {CustomMinimumSize = new Vector2(150.0f, 0.0f)};
|
||||
SearchBar = new LineEdit {PlaceHolder = "Search"};
|
||||
RecipeList = new Tree {SizeFlagsVertical = SizeFlags.FillExpand, HideRoot = true};
|
||||
recipes.AddChild(SearchBar);
|
||||
recipes.AddChild(RecipeList);
|
||||
hSplitContainer.AddChild(recipes);
|
||||
|
||||
// Right side
|
||||
var guide = new VBoxContainer("Guide");
|
||||
var info = new HBoxContainer("Info");
|
||||
InfoIcon = new TextureRect("TextureRect");
|
||||
InfoLabel = new Label("Label")
|
||||
var guide = new VBoxContainer();
|
||||
var info = new HBoxContainer();
|
||||
InfoIcon = new TextureRect();
|
||||
InfoLabel = new Label
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||
};
|
||||
@@ -85,7 +73,7 @@ namespace Content.Client.Construction
|
||||
info.AddChild(InfoLabel);
|
||||
guide.AddChild(info);
|
||||
|
||||
var stepsLabel = new Label("Label")
|
||||
var stepsLabel = new Label
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
@@ -93,14 +81,14 @@ namespace Content.Client.Construction
|
||||
};
|
||||
guide.AddChild(stepsLabel);
|
||||
|
||||
StepList = new ItemList("StepsList")
|
||||
StepList = new ItemList
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand, SelectMode = ItemList.ItemListSelectMode.None
|
||||
};
|
||||
guide.AddChild(StepList);
|
||||
|
||||
var buttonsContainer = new HBoxContainer("Buttons");
|
||||
BuildButton = new Button("BuildButton")
|
||||
var buttonsContainer = new HBoxContainer();
|
||||
BuildButton = new Button
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
TextAlign = Button.AlignMode.Center,
|
||||
@@ -108,7 +96,7 @@ namespace Content.Client.Construction
|
||||
Disabled = true,
|
||||
ToggleMode = false
|
||||
};
|
||||
EraseButton = new Button("EraseButton")
|
||||
EraseButton = new Button
|
||||
{
|
||||
TextAlign = Button.AlignMode.Center, Text = "Clear Ghosts", ToggleMode = true
|
||||
};
|
||||
@@ -140,7 +128,7 @@ namespace Content.Client.Construction
|
||||
|
||||
void OnItemSelected()
|
||||
{
|
||||
var prototype = (ConstructionPrototype)RecipeList.Selected.Metadata;
|
||||
var prototype = (ConstructionPrototype) RecipeList.Selected.Metadata;
|
||||
|
||||
if (prototype == null)
|
||||
{
|
||||
@@ -163,6 +151,7 @@ namespace Content.Client.Construction
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Texture icon;
|
||||
string text;
|
||||
switch (forward)
|
||||
@@ -171,47 +160,55 @@ namespace Content.Client.Construction
|
||||
switch (mat.Material)
|
||||
{
|
||||
case ConstructionStepMaterial.MaterialType.Metal:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/sheet_metal.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>(
|
||||
"/Textures/Objects/Materials/sheet_metal.png");
|
||||
text = $"Metal x{mat.Amount}";
|
||||
break;
|
||||
case ConstructionStepMaterial.MaterialType.Glass:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/sheet_glass.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>(
|
||||
"/Textures/Objects/Materials/sheet_glass.png");
|
||||
text = $"Glass x{mat.Amount}";
|
||||
break;
|
||||
case ConstructionStepMaterial.MaterialType.Cable:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/cable_coil.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>(
|
||||
"/Textures/Objects/Tools/cable_coil.png");
|
||||
text = $"Cable Coil x{mat.Amount}";
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
break;
|
||||
case ConstructionStepTool tool:
|
||||
switch (tool.Tool)
|
||||
{
|
||||
case ConstructionStepTool.ToolType.Wrench:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/wrench.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/Tools/wrench.png");
|
||||
text = "Wrench";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Crowbar:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/crowbar.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/Tools/crowbar.png");
|
||||
text = "Crowbar";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Screwdriver:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/screwdriver.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>(
|
||||
"/Textures/Objects/Tools/screwdriver.png");
|
||||
text = "Screwdriver";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Welder:
|
||||
icon = ResourceCache.GetResource<RSIResource>("/Textures/Objects/tools.rsi").RSI["welder"].Frame0;
|
||||
icon = ResourceCache.GetResource<RSIResource>("/Textures/Objects/tools.rsi")
|
||||
.RSI["welder"].Frame0;
|
||||
text = $"Welding tool ({tool.Amount} fuel)";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Wirecutters:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/wirecutter.png");
|
||||
icon = ResourceCache.GetResource<TextureResource>(
|
||||
"/Textures/Objects/Tools/wirecutter.png");
|
||||
text = "Wirecutters";
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
@@ -228,9 +225,9 @@ namespace Content.Client.Construction
|
||||
PopulateTree(string.IsNullOrWhiteSpace(str) ? null : str.ToLowerInvariant());
|
||||
}
|
||||
|
||||
void OnBuildPressed(Button.ButtonEventArgs args)
|
||||
void OnBuildPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
var prototype = (ConstructionPrototype)RecipeList.Selected.Metadata;
|
||||
var prototype = (ConstructionPrototype) RecipeList.Selected.Metadata;
|
||||
if (prototype == null)
|
||||
{
|
||||
return;
|
||||
@@ -278,6 +275,7 @@ namespace Content.Client.Construction
|
||||
subNode = new CategoryNode(category, currentNode);
|
||||
currentNode.ChildCategories.Add(category, subNode);
|
||||
}
|
||||
|
||||
currentNode = subNode;
|
||||
}
|
||||
|
||||
@@ -334,7 +332,7 @@ namespace Content.Client.Construction
|
||||
{
|
||||
var found = false;
|
||||
// TODO: don't run ToLowerInvariant() constantly.
|
||||
if (prototype.Name.ToLowerInvariant().IndexOf(searchTerm) != -1)
|
||||
if (prototype.Name.ToLowerInvariant().IndexOf(searchTerm, StringComparison.Ordinal) != -1)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
@@ -343,7 +341,7 @@ namespace Content.Client.Construction
|
||||
foreach (var keyw in prototype.Keywords.Concat(prototype.CategorySegments))
|
||||
{
|
||||
// TODO: don't run ToLowerInvariant() constantly.
|
||||
if (keyw.ToLowerInvariant().IndexOf(searchTerm) != -1)
|
||||
if (keyw.ToLowerInvariant().IndexOf(searchTerm, StringComparison.Ordinal) != -1)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@@ -356,6 +354,7 @@ namespace Content.Client.Construction
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var subItem = RecipeList.CreateItem(ItemForNode(node));
|
||||
subItem.Text = prototype.Name;
|
||||
subItem.Metadata = prototype;
|
||||
@@ -370,14 +369,17 @@ namespace Content.Client.Construction
|
||||
|
||||
private static int ComparePrototype(ConstructionPrototype x, ConstructionPrototype y)
|
||||
{
|
||||
return x.Name.CompareTo(y.Name);
|
||||
return String.Compare(x.Name, y.Name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
class CategoryNode
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly CategoryNode Parent;
|
||||
public SortedDictionary<string, CategoryNode> ChildCategories = new SortedDictionary<string, CategoryNode>();
|
||||
|
||||
public SortedDictionary<string, CategoryNode>
|
||||
ChildCategories = new SortedDictionary<string, CategoryNode>();
|
||||
|
||||
public List<ConstructionPrototype> Prototypes = new List<ConstructionPrototype>();
|
||||
public int FlattenedIndex = -1;
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using Content.Shared.Construction;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.Construction
|
||||
{
|
||||
@@ -46,7 +43,6 @@ namespace Content.Client.Construction
|
||||
{
|
||||
base.StartHijack(manager);
|
||||
|
||||
var res = IoCManager.Resolve<IResourceCache>();
|
||||
manager.CurrentBaseSprite = Prototype.Icon.DirFrame0();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<!-- Work around https://github.com/dotnet/project-system/issues/4314 -->
|
||||
<TargetFramework>$(TargetFramework)</TargetFramework>
|
||||
<LangVersion>8</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>x64;x86</Platforms>
|
||||
<Platforms>x64</Platforms>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<OutputPath>..\bin\Content.Client\</OutputPath>
|
||||
<OutputType Condition="'$(FullRelease)' != 'True'">Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\RobustToolbox\MSBuild\Robust.DefineConstants.targets" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nett" Version="0.11.0" />
|
||||
<PackageReference Include="Nett" Version="0.13.0" />
|
||||
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0007" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0006" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="6.0.0" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.1.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="8.1.0" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RobustToolbox\Lidgren.Network\Lidgren.Network.csproj" />
|
||||
@@ -24,4 +26,6 @@
|
||||
<ProjectReference Include="..\RobustToolbox\Robust.Client\Robust.Client.csproj" />
|
||||
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\RobustToolbox\MSBuild\Robust.Engine.targets" />
|
||||
<Target Name="ContentAfterBuild" DependsOnTargets="ClientAfterBuild" AfterTargets="Build" />
|
||||
</Project>
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
using System;
|
||||
using Content.Client.Chat;
|
||||
using Content.Client.GameObjects.Components.Actor;
|
||||
using Content.Client.GameTicking;
|
||||
using Content.Client.Input;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Client.Interfaces.Parallax;
|
||||
using Content.Client.Parallax;
|
||||
using Content.Client.Sandbox;
|
||||
using Content.Client.State;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Cargo;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Markers;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Client;
|
||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client
|
||||
{
|
||||
@@ -29,6 +34,8 @@ namespace Content.Client
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IBaseClient _baseClient;
|
||||
[Dependency] private readonly IStateManager _stateManager;
|
||||
[Dependency] private readonly IEscapeMenuOwner _escapeMenuOwner;
|
||||
#pragma warning restore 649
|
||||
|
||||
@@ -41,6 +48,10 @@ namespace Content.Client
|
||||
|
||||
var registerIgnore = new[]
|
||||
{
|
||||
"Wrenchable",
|
||||
"AmmoBox",
|
||||
"Breakable",
|
||||
"Pickaxe",
|
||||
"Interactable",
|
||||
"Destructible",
|
||||
"Temperature",
|
||||
@@ -57,7 +68,6 @@ namespace Content.Client
|
||||
"EmitSoundOnUse",
|
||||
"FootstepModifier",
|
||||
"HeatResistance",
|
||||
"CombatMode",
|
||||
"Teleportable",
|
||||
"ItemTeleporter",
|
||||
"Portal",
|
||||
@@ -66,7 +76,6 @@ namespace Content.Client
|
||||
"Wirecutter",
|
||||
"Screwdriver",
|
||||
"Multitool",
|
||||
"Welder",
|
||||
"Wrench",
|
||||
"Crowbar",
|
||||
"HitscanWeapon",
|
||||
@@ -74,7 +83,6 @@ namespace Content.Client
|
||||
"Projectile",
|
||||
"MeleeWeapon",
|
||||
"Storeable",
|
||||
"Stack",
|
||||
"Dice",
|
||||
"Construction",
|
||||
"Apc",
|
||||
@@ -82,17 +90,46 @@ namespace Content.Client
|
||||
"PoweredLight",
|
||||
"Smes",
|
||||
"Powercell",
|
||||
"HandheldLight",
|
||||
"LightBulb",
|
||||
"Healing",
|
||||
"Catwalk",
|
||||
"BallisticMagazine",
|
||||
"BallisticMagazineWeapon",
|
||||
"BallisticBullet",
|
||||
"HitscanWeaponCapacitor",
|
||||
"PowerCell",
|
||||
"WeaponCapacitorCharger",
|
||||
"PowerCellCharger",
|
||||
"AiController",
|
||||
"PlayerInputMover",
|
||||
"Computer",
|
||||
"AsteroidRock",
|
||||
"ResearchServer",
|
||||
"ResearchPointSource",
|
||||
"ResearchClient",
|
||||
"IdCard",
|
||||
"Access",
|
||||
"AccessReader",
|
||||
"IdCardConsole",
|
||||
"Airlock",
|
||||
"MedicalScanner",
|
||||
"WirePlacer",
|
||||
"Species",
|
||||
"Drink",
|
||||
"Food",
|
||||
"DrinkFoodContainer",
|
||||
"Stomach",
|
||||
"Hunger",
|
||||
"Thirst",
|
||||
"Rotatable",
|
||||
"MagicMirror",
|
||||
"MedkitFill",
|
||||
"FloorTile",
|
||||
"FootstepSound",
|
||||
"UtilityBeltClothingFill",
|
||||
"ShuttleController",
|
||||
"HumanInventoryController",
|
||||
"UseDelay",
|
||||
"Pourable"
|
||||
};
|
||||
|
||||
foreach (var ignoreName in registerIgnore)
|
||||
@@ -100,19 +137,22 @@ namespace Content.Client
|
||||
factory.RegisterIgnore(ignoreName);
|
||||
}
|
||||
|
||||
factory.Register<SharedResearchConsoleComponent>();
|
||||
factory.Register<SharedLatheComponent>();
|
||||
factory.Register<SharedSpawnPointComponent>();
|
||||
|
||||
factory.Register<SolutionComponent>();
|
||||
|
||||
prototypes.RegisterIgnore("material");
|
||||
factory.Register<SharedVendingMachineComponent>();
|
||||
factory.Register<SharedWiresComponent>();
|
||||
factory.Register<SharedCargoConsoleComponent>();
|
||||
factory.Register<SharedReagentDispenserComponent>();
|
||||
|
||||
prototypes.RegisterIgnore("material");
|
||||
prototypes.RegisterIgnore("reaction"); //Chemical reactions only needed by server. Reactions checks are server-side.
|
||||
|
||||
ClientContentIoC.Register();
|
||||
|
||||
IoCManager.Register<IGameHud, GameHud>();
|
||||
IoCManager.Register<IClientNotifyManager, ClientNotifyManager>();
|
||||
IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>();
|
||||
IoCManager.Register<IClientGameTicker, ClientGameTicker>();
|
||||
IoCManager.Register<IParallaxManager, ParallaxManager>();
|
||||
IoCManager.Register<IChatManager, ChatManager>();
|
||||
IoCManager.Register<IEscapeMenuOwner, EscapeMenuOwner>();
|
||||
if (TestingCallbacks != null)
|
||||
{
|
||||
var cast = (ClientModuleTestingCallbacks) TestingCallbacks;
|
||||
@@ -132,6 +172,16 @@ namespace Content.Client
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_escapeMenuOwner.Initialize();
|
||||
|
||||
_baseClient.PlayerJoinedGame += (sender, args) =>
|
||||
{
|
||||
_stateManager.RequestStateChange<GameScreen>();
|
||||
};
|
||||
|
||||
_baseClient.PlayerJoinedServer += (sender, args) =>
|
||||
{
|
||||
IoCManager.Resolve<IMapManager>().CreateNewMapEntity(MapId.Nullspace);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -174,19 +224,21 @@ namespace Content.Client
|
||||
IoCManager.Resolve<IClientGameTicker>().Initialize();
|
||||
IoCManager.Resolve<IOverlayManager>().AddOverlay(new ParallaxOverlay());
|
||||
IoCManager.Resolve<IChatManager>().Initialize();
|
||||
IoCManager.Resolve<ISandboxManager>().Initialize();
|
||||
IoCManager.Resolve<IClientPreferencesManager>().Initialize();
|
||||
IoCManager.Resolve<IItemSlotManager>().Initialize();
|
||||
}
|
||||
|
||||
public override void Update(ModUpdateLevel level, float frameTime)
|
||||
public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs)
|
||||
{
|
||||
base.Update(level, frameTime);
|
||||
base.Update(level, frameEventArgs);
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case ModUpdateLevel.FramePreEngine:
|
||||
var renderFrameEventArgs = new RenderFrameEventArgs(frameTime);
|
||||
IoCManager.Resolve<IClientNotifyManager>().FrameUpdate(renderFrameEventArgs);
|
||||
IoCManager.Resolve<IClientGameTicker>().FrameUpdate(renderFrameEventArgs);
|
||||
IoCManager.Resolve<IChatManager>().FrameUpdate(renderFrameEventArgs);
|
||||
IoCManager.Resolve<IClientNotifyManager>().FrameUpdate(frameEventArgs);
|
||||
IoCManager.Resolve<IClientGameTicker>().FrameUpdate(frameEventArgs);
|
||||
IoCManager.Resolve<IChatManager>().FrameUpdate(frameEventArgs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Client.State;
|
||||
using Content.Client.UserInterface;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
@@ -10,7 +11,6 @@ using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client
|
||||
@@ -49,9 +49,8 @@ namespace Content.Client
|
||||
|
||||
_escapeMenu.OnClose += () => _gameHud.EscapeButtonDown = false;
|
||||
|
||||
var escapeMenuCommand = InputCmdHandler.FromDelegate(Enabled);
|
||||
|
||||
_inputManager.SetInputCommand(EngineKeyFunctions.EscapeMenu, escapeMenuCommand);
|
||||
_inputManager.SetInputCommand(EngineKeyFunctions.EscapeMenu,
|
||||
InputCmdHandler.FromDelegate(s => Enabled()));
|
||||
}
|
||||
else if (obj.OldState is GameScreen)
|
||||
{
|
||||
@@ -63,7 +62,7 @@ namespace Content.Client
|
||||
}
|
||||
}
|
||||
|
||||
private void Enabled(ICommonSession session)
|
||||
private void Enabled()
|
||||
{
|
||||
if (_escapeMenu.IsOpen)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Content.Shared.GameObjects.Components.Access.SharedIdCardConsoleComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Access
|
||||
{
|
||||
public class IdCardConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
#pragma warning restore 649
|
||||
public IdCardConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
private IdCardConsoleWindow _window;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new IdCardConsoleWindow(this, _localizationManager, _prototypeManager);
|
||||
_window.Title = Owner.Owner.Name;
|
||||
_window.OnClose += Close;
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
var castState = (IdCardConsoleBoundUserInterfaceState) state;
|
||||
_window.UpdateState(castState);
|
||||
}
|
||||
|
||||
public void ButtonPressed(UiButton button)
|
||||
{
|
||||
SendMessage(new IdButtonPressedMessage(button));
|
||||
}
|
||||
|
||||
public void SubmitData(string newFullName, string newJobTitle, List<string> newAccessList)
|
||||
{
|
||||
SendMessage(new WriteToTargetIdMessage(
|
||||
newFullName,
|
||||
newJobTitle,
|
||||
newAccessList));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
using Robust.Shared.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Access;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Content.Shared.GameObjects.Components.Access.SharedIdCardConsoleComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Access
|
||||
{
|
||||
public class IdCardConsoleWindow : SS14Window
|
||||
{
|
||||
private readonly Button _privilegedIdButton;
|
||||
private readonly Button _targetIdButton;
|
||||
|
||||
private readonly Label _privilegedIdLabel;
|
||||
private readonly Label _targetIdLabel;
|
||||
|
||||
private readonly Label _fullNameLabel;
|
||||
private readonly LineEdit _fullNameLineEdit;
|
||||
private readonly Label _jobTitleLabel;
|
||||
private readonly LineEdit _jobTitleLineEdit;
|
||||
|
||||
private readonly Button _fullNameSaveButton;
|
||||
private readonly Button _jobTitleSaveButton;
|
||||
|
||||
private readonly IdCardConsoleBoundUserInterface _owner;
|
||||
|
||||
private readonly ILocalizationManager _loc;
|
||||
|
||||
private readonly Dictionary<string, Button> _accessButtons = new Dictionary<string, Button>();
|
||||
|
||||
private string _lastFullName;
|
||||
private string _lastJobTitle;
|
||||
|
||||
protected override Vector2? CustomSize => (650, 270);
|
||||
|
||||
public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, ILocalizationManager loc, IPrototypeManager prototypeManager)
|
||||
{
|
||||
_loc = loc;
|
||||
_owner = owner;
|
||||
var vBox = new VBoxContainer();
|
||||
|
||||
vBox.AddChild(new GridContainer
|
||||
{
|
||||
Columns = 3,
|
||||
Children =
|
||||
{
|
||||
new Label {Text = loc.GetString("Privileged ID:")},
|
||||
(_privilegedIdButton = new Button()),
|
||||
(_privilegedIdLabel = new Label()),
|
||||
|
||||
new Label {Text = loc.GetString("Target ID:")},
|
||||
(_targetIdButton = new Button()),
|
||||
(_targetIdLabel = new Label())
|
||||
}
|
||||
});
|
||||
|
||||
_privilegedIdButton.OnPressed += _ => _owner.ButtonPressed(UiButton.PrivilegedId);
|
||||
_targetIdButton.OnPressed += _ => _owner.ButtonPressed(UiButton.TargetId);
|
||||
|
||||
// Separator
|
||||
vBox.AddChild(new Control {CustomMinimumSize = (0, 8)});
|
||||
|
||||
// Name and job title line edits.
|
||||
vBox.AddChild(new GridContainer
|
||||
{
|
||||
Columns = 3,
|
||||
HSeparationOverride = 4,
|
||||
Children =
|
||||
{
|
||||
// Name
|
||||
(_fullNameLabel = new Label
|
||||
{
|
||||
Text = loc.GetString("Full name:")
|
||||
}),
|
||||
(_fullNameLineEdit = new LineEdit
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
}),
|
||||
(_fullNameSaveButton = new Button
|
||||
{
|
||||
Text = loc.GetString("Save"),
|
||||
Disabled = true
|
||||
}),
|
||||
|
||||
// Title
|
||||
(_jobTitleLabel = new Label
|
||||
{
|
||||
Text = loc.GetString("Job title:")
|
||||
}),
|
||||
(_jobTitleLineEdit = new LineEdit
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
}),
|
||||
(_jobTitleSaveButton = new Button
|
||||
{
|
||||
Text = loc.GetString("Save"),
|
||||
Disabled = true
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
_fullNameLineEdit.OnTextEntered += _ => SubmitData();
|
||||
_fullNameLineEdit.OnTextChanged += _ =>
|
||||
{
|
||||
_fullNameSaveButton.Disabled = _fullNameSaveButton.Text == _lastFullName;
|
||||
};
|
||||
_fullNameSaveButton.OnPressed += _ => SubmitData();
|
||||
|
||||
_jobTitleLineEdit.OnTextEntered += _ => SubmitData();
|
||||
_jobTitleLineEdit.OnTextChanged += _ =>
|
||||
{
|
||||
_jobTitleSaveButton.Disabled = _jobTitleLineEdit.Text == _lastJobTitle;
|
||||
};
|
||||
_jobTitleSaveButton.OnPressed += _ => SubmitData();
|
||||
|
||||
// Separator
|
||||
vBox.AddChild(new Control {CustomMinimumSize = (0, 8)});
|
||||
|
||||
{
|
||||
var grid = new GridContainer
|
||||
{
|
||||
Columns = 5,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter
|
||||
};
|
||||
vBox.AddChild(grid);
|
||||
|
||||
foreach (var accessLevel in prototypeManager.EnumeratePrototypes<AccessLevelPrototype>())
|
||||
{
|
||||
var newButton = new Button
|
||||
{
|
||||
Text = accessLevel.Name,
|
||||
ToggleMode = true,
|
||||
};
|
||||
grid.AddChild(newButton);
|
||||
_accessButtons.Add(accessLevel.ID, newButton);
|
||||
newButton.OnPressed += _ => SubmitData();
|
||||
}
|
||||
}
|
||||
|
||||
Contents.AddChild(vBox);
|
||||
}
|
||||
|
||||
public void UpdateState(IdCardConsoleBoundUserInterfaceState state)
|
||||
{
|
||||
_privilegedIdButton.Text = state.IsPrivilegedIdPresent
|
||||
? _loc.GetString("Eject")
|
||||
: _loc.GetString("Insert");
|
||||
|
||||
_privilegedIdLabel.Text = state.PrivilegedIdName;
|
||||
|
||||
_targetIdButton.Text = state.IsTargetIdPresent
|
||||
? _loc.GetString("Eject")
|
||||
: _loc.GetString("Insert");
|
||||
|
||||
_targetIdLabel.Text = state.TargetIdName;
|
||||
|
||||
var interfaceEnabled =
|
||||
state.IsPrivilegedIdPresent && state.IsPrivilegedIdAuthorized && state.IsTargetIdPresent;
|
||||
|
||||
var fullNameDirty = _lastFullName != null && _fullNameLineEdit.Text != state.TargetIdFullName;
|
||||
var jobTitleDirty = _lastJobTitle != null && _jobTitleLineEdit.Text != state.TargetIdJobTitle;
|
||||
|
||||
_fullNameLabel.Modulate = interfaceEnabled ? Color.White : Color.Gray;
|
||||
_fullNameLineEdit.Editable = interfaceEnabled;
|
||||
if (!fullNameDirty)
|
||||
{
|
||||
_fullNameLineEdit.Text = state.TargetIdFullName;
|
||||
}
|
||||
|
||||
_fullNameSaveButton.Disabled = !interfaceEnabled || !fullNameDirty;
|
||||
|
||||
_jobTitleLabel.Modulate = interfaceEnabled ? Color.White : Color.Gray;
|
||||
_jobTitleLineEdit.Editable = interfaceEnabled;
|
||||
if (!jobTitleDirty)
|
||||
{
|
||||
_jobTitleLineEdit.Text = state.TargetIdJobTitle;
|
||||
}
|
||||
|
||||
_jobTitleSaveButton.Disabled = !interfaceEnabled || !jobTitleDirty;
|
||||
|
||||
foreach (var (accessName, button) in _accessButtons)
|
||||
{
|
||||
button.Disabled = !interfaceEnabled;
|
||||
if (interfaceEnabled)
|
||||
{
|
||||
button.Pressed = state.TargetIdAccessList.Contains(accessName);
|
||||
}
|
||||
}
|
||||
|
||||
_lastFullName = state.TargetIdFullName;
|
||||
_lastJobTitle = state.TargetIdJobTitle;
|
||||
}
|
||||
|
||||
private void SubmitData()
|
||||
{
|
||||
_owner.SubmitData(
|
||||
_fullNameLineEdit.Text,
|
||||
_jobTitleLineEdit.Text,
|
||||
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
|
||||
_accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Content.Client.GameObjects.Components.Actor
|
||||
/// </remarks>
|
||||
public SS14Window Window { get; private set; }
|
||||
|
||||
private List<ICharacterUI> _uiComponents;
|
||||
|
||||
/// <summary>
|
||||
/// Create the window with all character UIs and bind it to a keypress
|
||||
/// </summary>
|
||||
@@ -44,13 +46,13 @@ namespace Content.Client.GameObjects.Components.Actor
|
||||
base.Initialize();
|
||||
|
||||
//Use all the character ui interfaced components to create the character window
|
||||
var uiComponents = Owner.GetAllComponents<ICharacterUI>().ToList();
|
||||
if (uiComponents.Count == 0)
|
||||
_uiComponents = Owner.GetAllComponents<ICharacterUI>().ToList();
|
||||
if (_uiComponents.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Window = new CharacterWindow(uiComponents);
|
||||
Window = new CharacterWindow(_uiComponents);
|
||||
Window.OnClose += () => _gameHud.CharacterButtonDown = false;
|
||||
}
|
||||
|
||||
@@ -61,7 +63,15 @@ namespace Content.Client.GameObjects.Components.Actor
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
Window?.Dispose();
|
||||
foreach (var component in _uiComponents)
|
||||
{
|
||||
// Make sure these don't get deleted when the window is disposed.
|
||||
component.Scene.Orphan();
|
||||
}
|
||||
|
||||
_uiComponents = null;
|
||||
|
||||
Window?.Close();
|
||||
Window = null;
|
||||
|
||||
var inputMgr = IoCManager.Resolve<IInputManager>();
|
||||
@@ -124,8 +134,6 @@ namespace Content.Client.GameObjects.Components.Actor
|
||||
{
|
||||
_contentsVBox.AddChild(element.Scene);
|
||||
}
|
||||
|
||||
Size = CombinedMinimumSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class AnimationsTestComponent : Component
|
||||
{
|
||||
public override string Name => "AnimationsTest";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
var animations = Owner.GetComponent<AnimationPlayerComponent>();
|
||||
animations.Play(new Animation
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(20),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty
|
||||
{
|
||||
ComponentType = typeof(ITransformComponent),
|
||||
Property = nameof(ITransformComponent.LocalRotation),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Angle.Zero, 0),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(1440), 20)
|
||||
}
|
||||
},
|
||||
new AnimationTrackComponentProperty
|
||||
{
|
||||
ComponentType = typeof(ISpriteComponent),
|
||||
Property = "layer/0/texture",
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame("Objects/toolbox_r.png", 0),
|
||||
new AnimationTrackProperty.KeyFrame("Objects/Toolbox_b.png", 5),
|
||||
new AnimationTrackProperty.KeyFrame("Objects/Toolbox_y.png", 5),
|
||||
new AnimationTrackProperty.KeyFrame("Objects/toolbox_r.png", 5),
|
||||
}
|
||||
}
|
||||
}
|
||||
}, "yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using Content.Client.UserInterface.Cargo;
|
||||
using Content.Shared.GameObjects.Components.Cargo;
|
||||
using Content.Shared.Prototypes.Cargo;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Cargo
|
||||
{
|
||||
public class CargoConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private CargoConsoleMenu _menu;
|
||||
[ViewVariables]
|
||||
private CargoConsoleOrderMenu _orderMenu;
|
||||
|
||||
[ViewVariables]
|
||||
public GalacticMarketComponent Market { get; private set; }
|
||||
[ViewVariables]
|
||||
public CargoOrderDatabaseComponent Orders { get; private set; }
|
||||
[ViewVariables]
|
||||
public bool RequestOnly { get; private set; }
|
||||
[ViewVariables]
|
||||
public int BankId { get; private set; }
|
||||
[ViewVariables]
|
||||
public string BankName { get; private set; }
|
||||
[ViewVariables]
|
||||
public int BankBalance { get; private set; }
|
||||
|
||||
private CargoProductPrototype _product;
|
||||
|
||||
public CargoConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
if (!Owner.Owner.TryGetComponent(out GalacticMarketComponent market)
|
||||
|| !Owner.Owner.TryGetComponent(out CargoOrderDatabaseComponent orders)) return;
|
||||
|
||||
Market = market;
|
||||
Orders = orders;
|
||||
|
||||
_menu = new CargoConsoleMenu(this);
|
||||
_orderMenu = new CargoConsoleOrderMenu();
|
||||
|
||||
_menu.OnClose += Close;
|
||||
|
||||
_menu.Populate();
|
||||
|
||||
Market.OnDatabaseUpdated += _menu.PopulateProducts;
|
||||
Market.OnDatabaseUpdated += _menu.PopulateCategories;
|
||||
Orders.OnDatabaseUpdated += _menu.PopulateOrders;
|
||||
|
||||
_menu.CallShuttleButton.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedCargoConsoleComponent.CargoConsoleShuttleMessage());
|
||||
};
|
||||
_menu.OnItemSelected += (args) =>
|
||||
{
|
||||
if (!(args.Button.Parent is CargoProductRow row))
|
||||
return;
|
||||
_product = row.Product;
|
||||
_orderMenu.Requester.Text = null;
|
||||
_orderMenu.Reason.Text = null;
|
||||
_orderMenu.Amount.Value = 1;
|
||||
_orderMenu.OpenCenteredMinSize();
|
||||
};
|
||||
_menu.OnOrderApproved += ApproveOrder;
|
||||
_menu.OnOrderCanceled += RemoveOrder;
|
||||
_orderMenu.SubmitButton.OnPressed += (args) =>
|
||||
{
|
||||
AddOrder();
|
||||
_orderMenu.Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (!(state is CargoConsoleInterfaceState cstate))
|
||||
return;
|
||||
if (RequestOnly != cstate.RequestOnly)
|
||||
{
|
||||
RequestOnly = cstate.RequestOnly;
|
||||
_menu.UpdateRequestOnly();
|
||||
}
|
||||
BankId = cstate.BankId;
|
||||
BankName = cstate.BankName;
|
||||
BankBalance = cstate.BankBalance;
|
||||
_menu.UpdateBankData();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
Market.OnDatabaseUpdated -= _menu.PopulateProducts;
|
||||
Market.OnDatabaseUpdated -= _menu.PopulateCategories;
|
||||
Orders.OnDatabaseUpdated -= _menu.PopulateOrders;
|
||||
_menu?.Dispose();
|
||||
_orderMenu?.Dispose();
|
||||
}
|
||||
|
||||
internal void AddOrder()
|
||||
{
|
||||
SendMessage(new SharedCargoConsoleComponent.CargoConsoleAddOrderMessage(_orderMenu.Requester.Text,
|
||||
_orderMenu.Reason.Text, _product.ID, _orderMenu.Amount.Value));
|
||||
}
|
||||
|
||||
internal void RemoveOrder(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
if (!(args.Button.Parent.Parent is CargoOrderRow row))
|
||||
return;
|
||||
SendMessage(new SharedCargoConsoleComponent.CargoConsoleRemoveOrderMessage(row.Order.OrderNumber));
|
||||
}
|
||||
|
||||
internal void ApproveOrder(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
if (!(args.Button.Parent.Parent is CargoOrderRow row))
|
||||
return;
|
||||
SendMessage(new SharedCargoConsoleComponent.CargoConsoleApproveOrderMessage(row.Order.OrderNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Content.Shared.GameObjects.Components.Cargo;
|
||||
using Content.Shared.Prototypes.Cargo;
|
||||
using Robust.Shared.GameObjects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Cargo
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class CargoOrderDatabaseComponent : SharedCargoOrderDatabaseComponent
|
||||
{
|
||||
private List<CargoOrderData> _orders = new List<CargoOrderData>();
|
||||
|
||||
public IReadOnlyList<CargoOrderData> Orders => _orders;
|
||||
/// <summary>
|
||||
/// Event called when the database is updated.
|
||||
/// </summary>
|
||||
public event Action OnDatabaseUpdated;
|
||||
|
||||
// TODO add account selector menu
|
||||
|
||||
/// <summary>
|
||||
/// Removes all orders from the database.
|
||||
/// </summary>
|
||||
public virtual void Clear()
|
||||
{
|
||||
_orders.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an order to the database.
|
||||
/// </summary>
|
||||
/// <param name="order">The order to be added.</param>
|
||||
public virtual void AddOrder(CargoOrderData order)
|
||||
{
|
||||
if (!_orders.Contains(order))
|
||||
_orders.Add(order);
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is CargoOrderDatabaseState state))
|
||||
return;
|
||||
Clear();
|
||||
if (state.Orders == null)
|
||||
return;
|
||||
foreach (var order in state.Orders)
|
||||
{
|
||||
AddOrder(order);
|
||||
}
|
||||
|
||||
OnDatabaseUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Shared.GameObjects.Components.Cargo;
|
||||
using Content.Shared.Prototypes.Cargo;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Cargo
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GalacticMarketComponent : SharedGalacticMarketComponent
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
[Dependency] private IPrototypeManager _prototypeManager;
|
||||
#pragma warning restore
|
||||
|
||||
/// <summary>
|
||||
/// Event called when the database is updated.
|
||||
/// </summary>
|
||||
public event Action OnDatabaseUpdated;
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is GalacticMarketState state))
|
||||
return;
|
||||
_products.Clear();
|
||||
foreach (var productId in state.Products)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex(productId, out CargoProductPrototype product))
|
||||
continue;
|
||||
_products.Add(product);
|
||||
}
|
||||
|
||||
OnDatabaseUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using static Content.Shared.GameObjects.Components.Chemistry.SharedReagentDispenserComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Chemistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="ReagentDispenserWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class ReagentDispenserBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private ReagentDispenserWindow _window;
|
||||
private ReagentDispenserBoundUserInterfaceState _lastState;
|
||||
|
||||
public ReagentDispenserBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a dispenser UI instance is opened. Generates the dispenser window and fills it with
|
||||
/// relevant info. Sets the actions for static buttons.
|
||||
/// <para>Buttons which can change like reagent dispense buttons have their actions set in <see cref="UpdateReagentsList"/>.</para>
|
||||
/// </summary>
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
//Setup window layout/elements
|
||||
_window = new ReagentDispenserWindow
|
||||
{
|
||||
Title = _localizationManager.GetString("Reagent dispenser"),
|
||||
};
|
||||
|
||||
_window.OpenCenteredMinSize();
|
||||
_window.OnClose += Close;
|
||||
|
||||
//Setup static button actions.
|
||||
_window.EjectButton.OnPressed += _ => ButtonPressed(UiButton.Eject);
|
||||
_window.ClearButton.OnPressed += _ => ButtonPressed(UiButton.Clear);
|
||||
_window.DispenseButton1.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount1);
|
||||
_window.DispenseButton5.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount5);
|
||||
_window.DispenseButton10.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount10);
|
||||
_window.DispenseButton25.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount25);
|
||||
_window.DispenseButton50.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount50);
|
||||
_window.DispenseButton100.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the ui each time new state data is sent from the server.
|
||||
/// </summary>
|
||||
/// <param name="state">
|
||||
/// Data of the <see cref="SharedReagentDispenserComponent"/> that this ui represents.
|
||||
/// Sent from the server.
|
||||
/// </param>
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
var castState = (ReagentDispenserBoundUserInterfaceState)state;
|
||||
_lastState = castState;
|
||||
|
||||
_window?.UpdateState(castState); //Update window state
|
||||
UpdateReagentsList(castState.Inventory); //Update reagents list & reagent button actions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the list of reagents that this dispenser can dispense on the UI.
|
||||
/// </summary>
|
||||
/// <param name="inventory">A list of the reagents which can be dispensed.</param>
|
||||
private void UpdateReagentsList(List<ReagentDispenserInventoryEntry> inventory)
|
||||
{
|
||||
_window.UpdateReagentsList(inventory);
|
||||
for (int i = 0; i < _window.ChemicalList.Children.Count(); i++)
|
||||
{
|
||||
var button = (Button)_window.ChemicalList.Children.ElementAt(i);
|
||||
var i1 = i;
|
||||
button.OnPressed += _ => ButtonPressed(UiButton.Dispense, i1);
|
||||
button.OnMouseEntered += _ =>
|
||||
{
|
||||
if (_lastState != null)
|
||||
{
|
||||
_window.UpdateContainerInfo(_lastState, inventory[i1].ID);
|
||||
}
|
||||
};
|
||||
button.OnMouseExited += _ =>
|
||||
{
|
||||
if (_lastState != null)
|
||||
{
|
||||
_window.UpdateContainerInfo(_lastState);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonPressed(UiButton button, int dispenseIndex = -1)
|
||||
{
|
||||
SendMessage(new UiButtonPressedMessage(button, dispenseIndex));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_window.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Content.Shared.GameObjects.Components.Chemistry.SharedReagentDispenserComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Chemistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side UI used to control a <see cref="SharedReagentDispenserComponent"/>
|
||||
/// </summary>
|
||||
public class ReagentDispenserWindow : SS14Window
|
||||
{
|
||||
/// <summary>Contains info about the reagent container such as it's contents, if one is loaded into the dispenser.</summary>
|
||||
private readonly VBoxContainer ContainerInfo;
|
||||
|
||||
/// <summary>Sets the dispense amount to 1 when pressed.</summary>
|
||||
public Button DispenseButton1 { get; }
|
||||
|
||||
/// <summary>Sets the dispense amount to 5 when pressed.</summary>
|
||||
public Button DispenseButton5 { get; }
|
||||
|
||||
/// <summary>Sets the dispense amount to 10 when pressed.</summary>
|
||||
public Button DispenseButton10 { get; }
|
||||
|
||||
/// <summary>Sets the dispense amount to 25 when pressed.</summary>
|
||||
public Button DispenseButton25 { get; }
|
||||
|
||||
/// <summary>Sets the dispense amount to 50 when pressed.</summary>
|
||||
public Button DispenseButton50 { get; }
|
||||
|
||||
/// <summary>Sets the dispense amount to 100 when pressed.</summary>
|
||||
public Button DispenseButton100 { get; }
|
||||
|
||||
/// <summary>Ejects the reagent container from the dispenser.</summary>
|
||||
public Button ClearButton { get; }
|
||||
|
||||
/// <summary>Removes all reagents from the reagent container.</summary>
|
||||
public Button EjectButton { get; }
|
||||
|
||||
/// <summary>A grid of buttons for each reagent which can be dispensed.</summary>
|
||||
public GridContainer ChemicalList { get; }
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
protected override Vector2? CustomSize => (500, 600);
|
||||
|
||||
/// <summary>
|
||||
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
|
||||
/// actual data isn't filled in until the server sends data about the dispenser.
|
||||
/// </summary>
|
||||
public ReagentDispenserWindow()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
var dispenseAmountGroup = new ButtonGroup();
|
||||
|
||||
Contents.AddChild(new VBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
//First, our dispense amount buttons
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label {Text = _localizationManager.GetString("Amount")},
|
||||
//Padding
|
||||
new Control {CustomMinimumSize = (20, 0)},
|
||||
(DispenseButton1 = new Button {Text = "1", Group = dispenseAmountGroup}),
|
||||
(DispenseButton5 = new Button {Text = "5", Group = dispenseAmountGroup}),
|
||||
(DispenseButton10 = new Button {Text = "10", Group = dispenseAmountGroup}),
|
||||
(DispenseButton25 = new Button {Text = "25", Group = dispenseAmountGroup}),
|
||||
(DispenseButton50 = new Button {Text = "50", Group = dispenseAmountGroup}),
|
||||
(DispenseButton100 = new Button {Text = "100", Group = dispenseAmountGroup}),
|
||||
}
|
||||
},
|
||||
//Padding
|
||||
new Control {CustomMinimumSize = (0.0f, 10.0f)},
|
||||
//Grid of which reagents can be dispensed.
|
||||
(ChemicalList = new GridContainer
|
||||
{
|
||||
Columns = 5
|
||||
}),
|
||||
//Padding
|
||||
new Control {CustomMinimumSize = (0.0f, 10.0f)},
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label {Text = _localizationManager.GetString("Container: ")},
|
||||
(ClearButton = new Button {Text = _localizationManager.GetString("Clear")}),
|
||||
(EjectButton = new Button {Text = _localizationManager.GetString("Eject")})
|
||||
}
|
||||
},
|
||||
//Wrap the container info in a PanelContainer so we can color it's background differently.
|
||||
new PanelContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsStretchRatio = 6,
|
||||
CustomMinimumSize = (0, 150),
|
||||
PanelOverride = new StyleBoxFlat
|
||||
{
|
||||
BackgroundColor = new Color(27, 27, 30)
|
||||
},
|
||||
Children =
|
||||
{
|
||||
//Currently empty, when server sends state data this will have container contents and fill volume.
|
||||
(ContainerInfo = new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = _localizationManager.GetString("No container loaded.")
|
||||
}
|
||||
}
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the button grid of reagents which can be dispensed.
|
||||
/// <para>The actions for these buttons are set in <see cref="ReagentDispenserBoundUserInterface.UpdateReagentsList"/>.</para>
|
||||
/// </summary>
|
||||
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
|
||||
public void UpdateReagentsList(List<ReagentDispenserInventoryEntry> inventory)
|
||||
{
|
||||
if (ChemicalList == null) return;
|
||||
if (inventory == null) return;
|
||||
|
||||
ChemicalList.Children.Clear();
|
||||
|
||||
foreach (var entry in inventory)
|
||||
{
|
||||
if (_prototypeManager.TryIndex(entry.ID, out ReagentPrototype proto))
|
||||
{
|
||||
ChemicalList.AddChild(new Button {Text = proto.Name});
|
||||
}
|
||||
else
|
||||
{
|
||||
ChemicalList.AddChild(new Button {Text = _localizationManager.GetString("Reagent name not found")});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the UI state when new state data is received from the server.
|
||||
/// </summary>
|
||||
/// <param name="state">State data sent by the server.</param>
|
||||
public void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
var castState = (ReagentDispenserBoundUserInterfaceState) state;
|
||||
Title = castState.DispenserName;
|
||||
UpdateContainerInfo(castState);
|
||||
|
||||
switch (castState.SelectedDispenseAmount)
|
||||
{
|
||||
case 1:
|
||||
DispenseButton1.Pressed = true;
|
||||
break;
|
||||
case 5:
|
||||
DispenseButton5.Pressed = true;
|
||||
break;
|
||||
case 10:
|
||||
DispenseButton10.Pressed = true;
|
||||
break;
|
||||
case 25:
|
||||
DispenseButton25.Pressed = true;
|
||||
break;
|
||||
case 50:
|
||||
DispenseButton50.Pressed = true;
|
||||
break;
|
||||
case 100:
|
||||
DispenseButton100.Pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the fill state and list of reagents held by the current reagent container, if applicable.
|
||||
/// <para>Also highlights a reagent if it's dispense button is being mouse hovered.</para>
|
||||
/// </summary>
|
||||
/// <param name="state">State data for the dispenser.</param>
|
||||
/// <param name="highlightedReagentId">Prototype id of the reagent whose dispense button is currently being mouse hovered.</param>
|
||||
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state,
|
||||
string highlightedReagentId = null)
|
||||
{
|
||||
ContainerInfo.Children.Clear();
|
||||
|
||||
if (!state.HasBeaker)
|
||||
{
|
||||
ContainerInfo.Children.Add(new Label {Text = _localizationManager.GetString("No container loaded.")});
|
||||
return;
|
||||
}
|
||||
|
||||
ContainerInfo.Children.Add(new HBoxContainer // Name of the container and its fill status (Ex: 44/100u)
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label {Text = $"{state.ContainerName}: "},
|
||||
new Label
|
||||
{
|
||||
Text = $"{state.BeakerCurrentVolume}/{state.BeakerMaxVolume}",
|
||||
StyleClasses = {NanoStyle.StyleClassLabelSecondaryColor}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (state.ContainerReagents == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var reagent in state.ContainerReagents)
|
||||
{
|
||||
var name = _localizationManager.GetString("Unknown reagent");
|
||||
//Try to the prototype for the given reagent. This gives us it's name.
|
||||
if (_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto))
|
||||
{
|
||||
name = proto.Name;
|
||||
}
|
||||
|
||||
//Check if the reagent is being moused over. If so, color it green.
|
||||
if (proto != null && proto.ID == highlightedReagentId)
|
||||
{
|
||||
ContainerInfo.Children.Add(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = $"{name}: ",
|
||||
StyleClasses = {NanoStyle.StyleClassPowerStateGood}
|
||||
},
|
||||
new Label
|
||||
{
|
||||
Text = $"{reagent.Quantity}u",
|
||||
StyleClasses = {NanoStyle.StyleClassPowerStateGood}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else //Otherwise, color it the normal colors.
|
||||
{
|
||||
ContainerInfo.Children.Add(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label {Text = $"{name}: "},
|
||||
new Label
|
||||
{
|
||||
Text = $"{reagent.Quantity}u",
|
||||
StyleClasses = {NanoStyle.StyleClassLabelSecondaryColor}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Clothing
|
||||
@@ -12,13 +12,27 @@ namespace Content.Client.GameObjects.Components.Clothing
|
||||
[ComponentReference(typeof(ItemComponent))]
|
||||
public class ClothingComponent : ItemComponent
|
||||
{
|
||||
private FemaleClothingMask _femaleMask;
|
||||
public override string Name => "Clothing";
|
||||
public override uint? NetID => ContentNetIDs.CLOTHING;
|
||||
public override Type StateType => typeof(ClothingComponentState);
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string ClothingEquippedPrefix { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public FemaleClothingMask FemaleMask
|
||||
{
|
||||
get => _femaleMask;
|
||||
set => _femaleMask = value;
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _femaleMask, "femaleMask", FemaleClothingMask.UniformFull);
|
||||
}
|
||||
|
||||
public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot)
|
||||
{
|
||||
if (RsiPath == null)
|
||||
@@ -47,4 +61,11 @@ namespace Content.Client.GameObjects.Components.Clothing
|
||||
EquippedPrefix = clothingComponentState.EquippedPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FemaleClothingMask
|
||||
{
|
||||
NoMask = 0,
|
||||
UniformFull,
|
||||
UniformTop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
public sealed class ComputerVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private string KeyboardState = "generic_key";
|
||||
private string ScreenState = "generic";
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
if (node.TryGetNode("key", out var scalar))
|
||||
{
|
||||
KeyboardState = scalar.AsString();
|
||||
}
|
||||
|
||||
if (node.TryGetNode("screen", out scalar))
|
||||
{
|
||||
ScreenState = scalar.AsString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
var sprite = entity.GetComponent<ISpriteComponent>();
|
||||
sprite.LayerSetState(Layers.Screen, ScreenState);
|
||||
sprite.LayerSetState(Layers.Keyboard, $"{KeyboardState}_off");
|
||||
sprite.LayerSetState(Layers.KeyboardOn, KeyboardState);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
if (!component.TryGetData(ComputerVisuals.Powered, out bool powered))
|
||||
{
|
||||
powered = true;
|
||||
}
|
||||
|
||||
component.TryGetData(ComputerVisuals.Broken, out bool broken);
|
||||
|
||||
if (broken)
|
||||
{
|
||||
sprite.LayerSetState(Layers.Body, "broken");
|
||||
sprite.LayerSetState(Layers.Screen, "computer_broken");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(Layers.Body, "computer");
|
||||
sprite.LayerSetState(Layers.Screen, ScreenState);
|
||||
}
|
||||
|
||||
sprite.LayerSetVisible(Layers.Screen, powered);
|
||||
sprite.LayerSetVisible(Layers.KeyboardOn, powered);
|
||||
}
|
||||
|
||||
public enum Layers
|
||||
{
|
||||
Body,
|
||||
Screen,
|
||||
Keyboard,
|
||||
KeyboardOn
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.Construction;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Construction
|
||||
@@ -14,18 +12,5 @@ namespace Content.Client.GameObjects.Components.Construction
|
||||
[ViewVariables] public ConstructionPrototype Prototype { get; set; }
|
||||
[ViewVariables] public ConstructorComponent Master { get; set; }
|
||||
[ViewVariables] public int GhostID { get; set; }
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||
IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case ClientEntityClickMsg clickMsg:
|
||||
Master.TryStartConstruction(GhostID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Content.Client.GameObjects.Components.Construction
|
||||
public void SpawnGhost(ConstructionPrototype prototype, GridCoordinates loc, Direction dir)
|
||||
{
|
||||
var entMgr = IoCManager.Resolve<IClientEntityManager>();
|
||||
var ghost = entMgr.SpawnEntityAt("constructionghost", loc);
|
||||
var ghost = entMgr.SpawnEntity("constructionghost", loc);
|
||||
var comp = ghost.GetComponent<ConstructionGhostComponent>();
|
||||
comp.Prototype = prototype;
|
||||
comp.Master = this;
|
||||
|
||||
@@ -20,9 +20,8 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
if(curState is DamageComponentState)
|
||||
if(curState is DamageComponentState damagestate)
|
||||
{
|
||||
var damagestate = (DamageComponentState)curState;
|
||||
CurrentDamage = damagestate.CurrentDamage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Client.GameObjects.Components.Wires;
|
||||
using Content.Shared.GameObjects.Components.Doors;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -16,6 +17,7 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
|
||||
private Animation CloseAnimation;
|
||||
private Animation OpenAnimation;
|
||||
private Animation DenyAnimation;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
@@ -23,6 +25,7 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
|
||||
var openSound = node.GetNode("open_sound").AsString();
|
||||
var closeSound = node.GetNode("close_sound").AsString();
|
||||
var denySound = node.GetNode("deny_sound").AsString();
|
||||
|
||||
CloseAnimation = new Animation {Length = TimeSpan.FromSeconds(1.2f)};
|
||||
{
|
||||
@@ -36,6 +39,11 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
flickUnlit.LayerKey = DoorVisualLayers.BaseUnlit;
|
||||
flickUnlit.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("closing_unlit", 0f));
|
||||
|
||||
var flickMaintenancePanel = new AnimationTrackSpriteFlick();
|
||||
CloseAnimation.AnimationTracks.Add(flickMaintenancePanel);
|
||||
flickMaintenancePanel.LayerKey = WiresVisualizer2D.WiresVisualLayers.MaintenancePanel;
|
||||
flickMaintenancePanel.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("panel_closing", 0f));
|
||||
|
||||
var sound = new AnimationTrackPlaySound();
|
||||
CloseAnimation.AnimationTracks.Add(sound);
|
||||
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(closeSound, 0));
|
||||
@@ -53,10 +61,27 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
flickUnlit.LayerKey = DoorVisualLayers.BaseUnlit;
|
||||
flickUnlit.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("opening_unlit", 0f));
|
||||
|
||||
var flickMaintenancePanel = new AnimationTrackSpriteFlick();
|
||||
OpenAnimation.AnimationTracks.Add(flickMaintenancePanel);
|
||||
flickMaintenancePanel.LayerKey = WiresVisualizer2D.WiresVisualLayers.MaintenancePanel;
|
||||
flickMaintenancePanel.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("panel_opening", 0f));
|
||||
|
||||
var sound = new AnimationTrackPlaySound();
|
||||
OpenAnimation.AnimationTracks.Add(sound);
|
||||
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(openSound, 0));
|
||||
}
|
||||
|
||||
DenyAnimation = new Animation {Length = TimeSpan.FromSeconds(0.45f)};
|
||||
{
|
||||
var flick = new AnimationTrackSpriteFlick();
|
||||
DenyAnimation.AnimationTracks.Add(flick);
|
||||
flick.LayerKey = DoorVisualLayers.Base;
|
||||
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("deny", 0f));
|
||||
|
||||
var sound = new AnimationTrackPlaySound();
|
||||
DenyAnimation.AnimationTracks.Add(sound);
|
||||
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(denySound, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
@@ -76,22 +101,21 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
state = DoorVisualState.Closed;
|
||||
}
|
||||
|
||||
var unlitVisible = true;
|
||||
switch (state)
|
||||
{
|
||||
case DoorVisualState.Closed:
|
||||
sprite.LayerSetState(DoorVisualLayers.Base, "closed");
|
||||
sprite.LayerSetState(DoorVisualLayers.BaseUnlit, "closed_unlit");
|
||||
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, true);
|
||||
sprite.LayerSetState(WiresVisualizer2D.WiresVisualLayers.MaintenancePanel, "panel_open");
|
||||
break;
|
||||
case DoorVisualState.Closing:
|
||||
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, true);
|
||||
if (!animPlayer.HasRunningAnimation(AnimationKey))
|
||||
{
|
||||
animPlayer.Play(CloseAnimation, AnimationKey);
|
||||
}
|
||||
break;
|
||||
case DoorVisualState.Opening:
|
||||
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, true);
|
||||
if (!animPlayer.HasRunningAnimation(AnimationKey))
|
||||
{
|
||||
animPlayer.Play(OpenAnimation, AnimationKey);
|
||||
@@ -100,11 +124,25 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
break;
|
||||
case DoorVisualState.Open:
|
||||
sprite.LayerSetState(DoorVisualLayers.Base, "open");
|
||||
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, false);
|
||||
unlitVisible = false;
|
||||
break;
|
||||
case DoorVisualState.Deny:
|
||||
unlitVisible = false;
|
||||
if (!animPlayer.HasRunningAnimation(AnimationKey))
|
||||
{
|
||||
animPlayer.Play(DenyAnimation, AnimationKey);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (component.TryGetData(DoorVisuals.Powered, out bool powered) && !powered)
|
||||
{
|
||||
unlitVisible = false;
|
||||
}
|
||||
|
||||
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
using Robust.Shared.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Clothing;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
|
||||
using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventoryMessage;
|
||||
@@ -28,10 +31,16 @@ namespace Content.Client.GameObjects
|
||||
|
||||
private ISpriteComponent _sprite;
|
||||
|
||||
private bool _playerAttached = false;
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
if (_playerAttached)
|
||||
{
|
||||
InterfaceController?.PlayerDetached();
|
||||
}
|
||||
InterfaceController?.Dispose();
|
||||
}
|
||||
|
||||
@@ -77,15 +86,12 @@ namespace Content.Client.GameObjects
|
||||
|
||||
foreach (var (slot, entityUid) in cast.Entities)
|
||||
{
|
||||
if (_slots.ContainsKey(slot))
|
||||
{
|
||||
_slots.Remove(slot);
|
||||
_clearSlot(slot);
|
||||
}
|
||||
|
||||
var entity = Owner.EntityManager.GetEntity(entityUid);
|
||||
_slots[slot] = entity;
|
||||
_setSlot(slot, entity);
|
||||
if (!_slots.ContainsKey(slot) || _slots[slot] != entity)
|
||||
{
|
||||
_slots[slot] = entity;
|
||||
_setSlot(slot, entity);
|
||||
}
|
||||
doneSlots.Add(slot);
|
||||
}
|
||||
|
||||
@@ -101,24 +107,55 @@ namespace Content.Client.GameObjects
|
||||
|
||||
private void _setSlot(Slots slot, IEntity entity)
|
||||
{
|
||||
if (_sprite != null && entity.TryGetComponent(out ClothingComponent clothing))
|
||||
SetSlotVisuals(slot, entity);
|
||||
|
||||
InterfaceController?.AddToSlot(slot, entity);
|
||||
}
|
||||
|
||||
internal void SetSlotVisuals(Slots slot, IEntity entity)
|
||||
{
|
||||
if (_sprite == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity != null && entity.TryGetComponent(out ClothingComponent clothing))
|
||||
{
|
||||
var flag = SlotMasks[slot];
|
||||
var data = clothing.GetEquippedStateInfo(flag);
|
||||
if (data == null)
|
||||
{
|
||||
_sprite.LayerSetVisible(slot, false);
|
||||
}
|
||||
else
|
||||
if (data != null)
|
||||
{
|
||||
var (rsi, state) = data.Value;
|
||||
_sprite.LayerSetVisible(slot, true);
|
||||
_sprite.LayerSetRSI(slot, rsi);
|
||||
_sprite.LayerSetState(slot, state);
|
||||
|
||||
if (slot == Slots.INNERCLOTHING)
|
||||
{
|
||||
_sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothing.FemaleMask switch
|
||||
{
|
||||
FemaleClothingMask.NoMask => "female_none",
|
||||
FemaleClothingMask.UniformTop => "female_top",
|
||||
_ => "female_full",
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
InterfaceController?.AddToSlot(slot, entity);
|
||||
_sprite.LayerSetVisible(slot, false);
|
||||
}
|
||||
|
||||
internal void ClearAllSlotVisuals()
|
||||
{
|
||||
foreach (var slot in InventoryInstance.SlotMasks)
|
||||
{
|
||||
if (slot != Slots.NONE)
|
||||
{
|
||||
_sprite.LayerSetVisible(slot, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _clearSlot(Slots slot)
|
||||
@@ -127,18 +164,23 @@ namespace Content.Client.GameObjects
|
||||
_sprite?.LayerSetVisible(slot, false);
|
||||
}
|
||||
|
||||
public void SendUnequipMessage(Slots slot)
|
||||
{
|
||||
var unequipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Unequip);
|
||||
SendNetworkMessage(unequipmessage);
|
||||
}
|
||||
|
||||
public void SendEquipMessage(Slots slot)
|
||||
{
|
||||
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip);
|
||||
SendNetworkMessage(equipmessage);
|
||||
}
|
||||
|
||||
public void SendUseMessage(Slots slot)
|
||||
{
|
||||
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Use);
|
||||
SendNetworkMessage(equipmessage);
|
||||
}
|
||||
|
||||
public void SendOpenStorageUIMessage(Slots slot)
|
||||
{
|
||||
SendNetworkMessage(new OpenSlotStorageUIMessage(slot));
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||
IComponent component = null)
|
||||
{
|
||||
@@ -148,12 +190,19 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
InterfaceController.PlayerAttached();
|
||||
_playerAttached = true;
|
||||
break;
|
||||
|
||||
case PlayerDetachedMsg _:
|
||||
InterfaceController.PlayerDetached();
|
||||
_playerAttached = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetSlot(Slots slot, out IEntity item)
|
||||
{
|
||||
return _slots.TryGetValue(slot, out item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
using Content.Client.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -10,8 +10,9 @@ using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
|
||||
using Content.Client.UserInterface;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
{
|
||||
@@ -22,15 +23,17 @@ namespace Content.Client.GameObjects
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ILocalizationManager _loc;
|
||||
[Dependency] private readonly IResourceCache _resourceCache;
|
||||
[Dependency] private readonly IItemSlotManager _itemSlotManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private readonly Dictionary<Slots, List<InventoryButton>> _inventoryButtons
|
||||
= new Dictionary<Slots, List<InventoryButton>>();
|
||||
private readonly Dictionary<Slots, List<ItemSlotButton>> _inventoryButtons
|
||||
= new Dictionary<Slots, List<ItemSlotButton>>();
|
||||
|
||||
private InventoryButton _hudButtonPocket1;
|
||||
private InventoryButton _hudButtonPocket2;
|
||||
private InventoryButton _hudButtonBelt;
|
||||
private InventoryButton _hudButtonBack;
|
||||
private ItemSlotButton _hudButtonPocket1;
|
||||
private ItemSlotButton _hudButtonPocket2;
|
||||
private ItemSlotButton _hudButtonBelt;
|
||||
private ItemSlotButton _hudButtonBack;
|
||||
private ItemSlotButton _hudButtonId;
|
||||
private Control _quickButtonsContainer;
|
||||
|
||||
public HumanInventoryInterfaceController(ClientInventoryComponent owner) : base(owner)
|
||||
@@ -42,19 +45,22 @@ namespace Content.Client.GameObjects
|
||||
base.Initialize();
|
||||
|
||||
_window = new HumanInventoryWindow(_loc, _resourceCache);
|
||||
|
||||
_window.OnClose += () => _gameHud.InventoryButtonDown = false;
|
||||
foreach (var (slot, button) in _window.Buttons)
|
||||
{
|
||||
button.OnPressed = AddToInventory;
|
||||
_inventoryButtons.Add(slot, new List<InventoryButton> {button});
|
||||
button.OnPressed = (e) => AddToInventory(e, slot);
|
||||
button.OnStoragePressed = (e) => OpenStorage(e, slot);
|
||||
_inventoryButtons.Add(slot, new List<ItemSlotButton> {button});
|
||||
}
|
||||
|
||||
void AddButton(out InventoryButton variable, Slots slot, string textureName)
|
||||
void AddButton(out ItemSlotButton variable, Slots slot, string textureName)
|
||||
{
|
||||
var texture = _resourceCache.GetTexture($"/Textures/UserInterface/Inventory/{textureName}.png");
|
||||
variable = new InventoryButton(slot, texture)
|
||||
var storageTexture = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/back.png");
|
||||
variable = new ItemSlotButton(texture, storageTexture)
|
||||
{
|
||||
OnPressed = AddToInventory
|
||||
OnPressed = (e) => AddToInventory(e, slot),
|
||||
OnStoragePressed = (e) => OpenStorage(e, slot)
|
||||
};
|
||||
_inventoryButtons[slot].Add(variable);
|
||||
}
|
||||
@@ -63,11 +69,13 @@ namespace Content.Client.GameObjects
|
||||
AddButton(out _hudButtonPocket2, Slots.POCKET2, "pocket");
|
||||
AddButton(out _hudButtonBack, Slots.BACKPACK, "back");
|
||||
AddButton(out _hudButtonBelt, Slots.BELT, "belt");
|
||||
AddButton(out _hudButtonId, Slots.IDCARD, "id");
|
||||
|
||||
_quickButtonsContainer = new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_hudButtonId,
|
||||
_hudButtonBelt,
|
||||
_hudButtonBack,
|
||||
_hudButtonPocket1,
|
||||
@@ -84,16 +92,12 @@ namespace Content.Client.GameObjects
|
||||
base.AddToSlot(slot, entity);
|
||||
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entity.TryGetComponent(out ISpriteComponent sprite);
|
||||
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.SpriteView.Sprite = sprite;
|
||||
button.OnPressed = RemoveFromInventory;
|
||||
_itemSlotManager.SetItemSlot(button, entity);
|
||||
button.OnPressed = (e) => HandleInventoryKeybind(e, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,23 +112,48 @@ namespace Content.Client.GameObjects
|
||||
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.SpriteView.Sprite = null;
|
||||
button.OnPressed = AddToInventory;
|
||||
ClearButton(button, slot);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleInventoryKeybind(BaseButton.ButtonEventArgs args, Slots slot)
|
||||
{
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
return;
|
||||
if (!Owner.TryGetSlot(slot, out var item))
|
||||
return;
|
||||
if (_itemSlotManager.OnButtonPressed(args.Event, item))
|
||||
return;
|
||||
|
||||
base.HandleInventoryKeybind(args, slot);
|
||||
}
|
||||
|
||||
private void ClearButton(ItemSlotButton button, Slots slot)
|
||||
{
|
||||
button.OnPressed = (e) => AddToInventory(e, slot);
|
||||
_itemSlotManager.SetItemSlot(button, null);
|
||||
}
|
||||
|
||||
public override void PlayerAttached()
|
||||
{
|
||||
base.PlayerAttached();
|
||||
|
||||
GameHud.InventoryQuickButtonContainer.AddChild(_quickButtonsContainer);
|
||||
_gameHud.InventoryQuickButtonContainer.AddChild(_quickButtonsContainer);
|
||||
}
|
||||
|
||||
public override void PlayerDetached()
|
||||
{
|
||||
base.PlayerDetached();
|
||||
|
||||
GameHud.InventoryQuickButtonContainer.RemoveChild(_quickButtonsContainer);
|
||||
_gameHud.InventoryQuickButtonContainer.RemoveChild(_quickButtonsContainer);
|
||||
|
||||
foreach (var (slot, list) in _inventoryButtons)
|
||||
{
|
||||
foreach (var button in list)
|
||||
{
|
||||
ClearButton(button, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HumanInventoryWindow : SS14Window
|
||||
@@ -133,29 +162,29 @@ namespace Content.Client.GameObjects
|
||||
private const int ButtonSeparation = 2;
|
||||
private const int RightSeparation = 2;
|
||||
|
||||
public IReadOnlyDictionary<Slots, InventoryButton> Buttons { get; }
|
||||
public IReadOnlyDictionary<Slots, ItemSlotButton> Buttons { get; }
|
||||
|
||||
public HumanInventoryWindow(ILocalizationManager loc, IResourceCache resourceCache)
|
||||
{
|
||||
Title = loc.GetString("Your Inventory");
|
||||
Resizable = false;
|
||||
|
||||
var buttonDict = new Dictionary<Slots, InventoryButton>();
|
||||
var buttonDict = new Dictionary<Slots, ItemSlotButton>();
|
||||
Buttons = buttonDict;
|
||||
|
||||
const int width = ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation;
|
||||
const int height = ButtonSize * 4 + ButtonSeparation * 3;
|
||||
|
||||
var windowContents = new Control {CustomMinimumSize = (width, height)};
|
||||
var windowContents = new LayoutContainer {CustomMinimumSize = (width, height)};
|
||||
Contents.AddChild(windowContents);
|
||||
|
||||
void AddButton(Slots slot, string textureName, Vector2 position)
|
||||
{
|
||||
var texture = resourceCache.GetTexture($"/Textures/UserInterface/Inventory/{textureName}.png");
|
||||
var button = new InventoryButton(slot, texture)
|
||||
{
|
||||
Position = position
|
||||
};
|
||||
var storageTexture = resourceCache.GetTexture("/Textures/UserInterface/Inventory/back.png");
|
||||
var button = new ItemSlotButton(texture, storageTexture);
|
||||
|
||||
LayoutContainer.SetPosition(button, position);
|
||||
|
||||
windowContents.AddChild(button);
|
||||
buttonDict.Add(slot, button);
|
||||
@@ -178,7 +207,7 @@ namespace Content.Client.GameObjects
|
||||
|
||||
// Right column
|
||||
AddButton(Slots.EARS, "ears", (2 * (size + sep), 0));
|
||||
AddButton(Slots.IDCARD, "mask", (2 * (size + sep), size + sep));
|
||||
AddButton(Slots.IDCARD, "id", (2 * (size + sep), size + sep));
|
||||
AddButton(Slots.GLOVES, "gloves", (2 * (size + sep), 2 * (size + sep)));
|
||||
|
||||
// Far right column.
|
||||
@@ -186,8 +215,6 @@ namespace Content.Client.GameObjects
|
||||
AddButton(Slots.BELT, "belt", (rSep + 3 * (size + sep), size + sep));
|
||||
AddButton(Slots.POCKET1, "pocket", (rSep + 3 * (size + sep), 2 * (size + sep)));
|
||||
AddButton(Slots.POCKET2, "pocket", (rSep + 3 * (size + sep), 3 * (size + sep)));
|
||||
|
||||
Size = CombinedMinimumSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
{
|
||||
public sealed class InventoryButton : MarginContainer
|
||||
{
|
||||
public EquipmentSlotDefines.Slots Slot { get; }
|
||||
public EntityUid EntityUid { get; set; }
|
||||
|
||||
public BaseButton Button { get; }
|
||||
public SpriteView SpriteView { get; }
|
||||
|
||||
public Action<BaseButton.ButtonEventArgs> OnPressed { get; set; }
|
||||
|
||||
public InventoryButton(EquipmentSlotDefines.Slots slot, Texture texture)
|
||||
{
|
||||
Slot = slot;
|
||||
|
||||
CustomMinimumSize = (64, 64);
|
||||
|
||||
AddChild(Button = new TextureButton
|
||||
{
|
||||
TextureNormal = texture,
|
||||
Scale = (2, 2),
|
||||
});
|
||||
|
||||
Button.OnPressed += e => OnPressed?.Invoke(e);
|
||||
|
||||
AddChild(SpriteView = new SpriteView
|
||||
{
|
||||
MouseFilter = MouseFilterMode.Ignore,
|
||||
Scale = (2, 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -10,8 +11,9 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
public abstract class InventoryInterfaceController : IDisposable
|
||||
{
|
||||
// ReSharper disable once UnassignedGetOnlyAutoProperty
|
||||
[field: Dependency] protected IGameHud GameHud { get; }
|
||||
#pragma warning disable 649
|
||||
[Dependency] protected readonly IGameHud _gameHud;
|
||||
#pragma warning restore 649
|
||||
|
||||
protected InventoryInterfaceController(ClientInventoryComponent owner)
|
||||
{
|
||||
@@ -28,8 +30,8 @@ namespace Content.Client.GameObjects
|
||||
|
||||
public virtual void PlayerAttached()
|
||||
{
|
||||
GameHud.InventoryButtonVisible = true;
|
||||
GameHud.InventoryButtonToggled = b =>
|
||||
_gameHud.InventoryButtonVisible = true;
|
||||
_gameHud.InventoryButtonToggled = b =>
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
@@ -44,7 +46,7 @@ namespace Content.Client.GameObjects
|
||||
|
||||
public virtual void PlayerDetached()
|
||||
{
|
||||
GameHud.InventoryButtonVisible = false;
|
||||
_gameHud.InventoryButtonVisible = false;
|
||||
Window.Close();
|
||||
}
|
||||
|
||||
@@ -60,20 +62,41 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
}
|
||||
|
||||
protected void RemoveFromInventory(BaseButton.ButtonEventArgs args)
|
||||
protected virtual void HandleInventoryKeybind(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
args.Button.Pressed = false;
|
||||
var control = (InventoryButton) args.Button.Parent;
|
||||
|
||||
Owner.SendUnequipMessage(control.Slot);
|
||||
if (args.Event.CanFocus)
|
||||
{
|
||||
UseItemOnInventory(args, slot);
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddToInventory(BaseButton.ButtonEventArgs args)
|
||||
protected void AddToInventory(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (!args.Event.CanFocus)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Button.Pressed = false;
|
||||
|
||||
Owner.SendEquipMessage(slot);
|
||||
}
|
||||
|
||||
protected void UseItemOnInventory(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
args.Button.Pressed = false;
|
||||
var control = (InventoryButton) args.Button.Parent;
|
||||
|
||||
Owner.SendEquipMessage(control.Slot);
|
||||
Owner.SendUseMessage(slot);
|
||||
}
|
||||
|
||||
protected void OpenStorage(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (!args.Event.CanFocus && args.Event.Function != ContentKeyFunctions.ActivateItemInWorld)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Button.Pressed = false;
|
||||
|
||||
Owner.SendOpenStorageUIMessage(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
106
Content.Client/GameObjects/Components/HandheldLightComponent.cs
Normal file
106
Content.Client/GameObjects/Components/HandheldLightComponent.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class HandheldLightComponent : SharedHandheldLightComponent, IItemStatus
|
||||
{
|
||||
[ViewVariables] public float? Charge { get; private set; }
|
||||
|
||||
public Control MakeControl()
|
||||
{
|
||||
return new StatusControl(this);
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
var cast = (HandheldLightComponentState) curState;
|
||||
|
||||
Charge = cast.Charge;
|
||||
}
|
||||
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private const float TimerCycle = 1;
|
||||
|
||||
private readonly HandheldLightComponent _parent;
|
||||
private readonly PanelContainer[] _sections = new PanelContainer[5];
|
||||
|
||||
private float _timer;
|
||||
|
||||
private static readonly StyleBoxFlat _styleBoxLit = new StyleBoxFlat
|
||||
{
|
||||
BackgroundColor = Color.Green
|
||||
};
|
||||
|
||||
private static readonly StyleBoxFlat _styleBoxUnlit = new StyleBoxFlat
|
||||
{
|
||||
BackgroundColor = Color.Black
|
||||
};
|
||||
|
||||
public StatusControl(HandheldLightComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
var wrapper = new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 4,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter
|
||||
};
|
||||
|
||||
AddChild(wrapper);
|
||||
|
||||
for (var i = 0; i < _sections.Length; i++)
|
||||
{
|
||||
var panel = new PanelContainer {CustomMinimumSize = (20, 20)};
|
||||
wrapper.AddChild(panel);
|
||||
_sections[i] = panel;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update(FrameEventArgs args)
|
||||
{
|
||||
base.Update(args);
|
||||
|
||||
_timer += args.DeltaSeconds;
|
||||
_timer %= TimerCycle;
|
||||
|
||||
var charge = _parent.Charge ?? 0;
|
||||
|
||||
int level;
|
||||
|
||||
if (FloatMath.CloseTo(charge, 0))
|
||||
{
|
||||
level = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = 1 + (int) MathF.Round(charge * 6);
|
||||
}
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
// Flash the last light.
|
||||
_sections[0].PanelOverride = _timer > TimerCycle / 2 ? _styleBoxLit : _styleBoxUnlit;
|
||||
}
|
||||
else
|
||||
{
|
||||
_sections[0].PanelOverride = level > 2 ? _styleBoxLit : _styleBoxUnlit;
|
||||
}
|
||||
|
||||
_sections[1].PanelOverride = level > 3 ? _styleBoxLit : _styleBoxUnlit;
|
||||
_sections[2].PanelOverride = level > 4 ? _styleBoxLit : _styleBoxUnlit;
|
||||
_sections[3].PanelOverride = level > 5 ? _styleBoxLit : _styleBoxUnlit;
|
||||
_sections[4].PanelOverride = level > 6 ? _styleBoxLit : _styleBoxUnlit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Content.Client/GameObjects/Components/IItemStatus.cs
Normal file
33
Content.Client/GameObjects/Components/IItemStatus.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows a component to provide status tooltips next to the hands interface.
|
||||
/// </summary>
|
||||
public interface IItemStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Called to get a control that represents the status for this component.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The control to render as status.
|
||||
/// </returns>
|
||||
public Control MakeControl();
|
||||
|
||||
/// <summary>
|
||||
/// Called when the item no longer needs this status (say, dropped from hand)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Useful to allow you to drop the control for the GC, if you need to.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that this may be called after a second invocation of <see cref="MakeControl"/> (for example if the user switches the item between two hands).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void DestroyControl(Control control)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,12 +75,13 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
|
||||
serializer.DataFieldCached(ref _mode, "mode", IconSmoothingMode.Corners);
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
/// <inheritdoc />
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
SnapGrid.OnPositionChanged += SnapGridOnPositionChanged;
|
||||
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode));
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode));
|
||||
if (Mode == IconSmoothingMode.Corners)
|
||||
{
|
||||
var state0 = $"{StateBase}0";
|
||||
@@ -196,17 +197,18 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
|
||||
Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}");
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
/// <inheritdoc />
|
||||
protected override void Shutdown()
|
||||
{
|
||||
SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
|
||||
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
|
||||
|
||||
base.Shutdown();
|
||||
|
||||
SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
|
||||
}
|
||||
|
||||
private void SnapGridOnPositionChanged()
|
||||
{
|
||||
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
|
||||
_lastPosition = (Owner.Transform.GridID, SnapGrid.Position);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using Content.Client.Instruments;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Instruments
|
||||
{
|
||||
public class InstrumentBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private InstrumentMenu _instrumentMenu;
|
||||
|
||||
public InstrumentComponent Instrument { get; set; }
|
||||
|
||||
public InstrumentBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
if (!Owner.Owner.TryGetComponent<InstrumentComponent>(out var instrument)) return;
|
||||
|
||||
Instrument = instrument;
|
||||
_instrumentMenu = new InstrumentMenu(this);
|
||||
_instrumentMenu.OnClose += Close;
|
||||
|
||||
_instrumentMenu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
_instrumentMenu?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.Components.Instruments;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Client.Audio.Midi;
|
||||
using Robust.Shared.Audio.Midi;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Timer = Robust.Shared.Timers.Timer;
|
||||
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Instruments
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class InstrumentComponent : SharedInstrumentComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when a midi song stops playing.
|
||||
/// </summary>
|
||||
public event Action OnMidiPlaybackEnded;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private IMidiManager _midiManager;
|
||||
[Dependency] private readonly IGameTiming _timing;
|
||||
#pragma warning restore 649
|
||||
|
||||
private IMidiRenderer _renderer;
|
||||
private int _instrumentProgram = 1;
|
||||
|
||||
/// <summary>
|
||||
/// A queue of MidiEvents to be sent to the server.
|
||||
/// </summary>
|
||||
private Queue<MidiEvent> _eventQueue = new Queue<MidiEvent>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether a midi song will loop or not.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool LoopMidi
|
||||
{
|
||||
get => _renderer.LoopMidi;
|
||||
set => _renderer.LoopMidi = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the instrument the midi renderer will play.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int InstrumentProgram
|
||||
{
|
||||
get => _instrumentProgram;
|
||||
set {
|
||||
_instrumentProgram = value;
|
||||
_renderer.MidiProgram = _instrumentProgram;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether there's a midi song being played or not.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsMidiOpen => _renderer.Status == MidiRendererStatus.File;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the midi renderer is listening for midi input or not.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsInputOpen => _renderer.Status == MidiRendererStatus.Input;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
IoCManager.InjectDependencies(this);
|
||||
_renderer = _midiManager.GetNewRenderer();
|
||||
_renderer.MidiProgram = _instrumentProgram;
|
||||
_renderer.TrackingEntity = Owner;
|
||||
_renderer.OnMidiPlayerFinished += () => { OnMidiPlaybackEnded?.Invoke(); };
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_renderer?.Dispose();
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(ref _instrumentProgram, "program", 1);
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
switch (message)
|
||||
{
|
||||
case InstrumentMidiEventMessage midiEventMessage:
|
||||
// If we're the ones sending the MidiEvents, we ignore this message.
|
||||
if (IsInputOpen || IsMidiOpen) break;
|
||||
Timer.Spawn((int) (500 + _timing.CurTime.TotalMilliseconds - midiEventMessage.Timestamp),
|
||||
() => _renderer.SendMidiEvent(midiEventMessage.MidiEvent));
|
||||
break;
|
||||
|
||||
case InstrumentStopMidiMessage _:
|
||||
_renderer.StopAllNotes();
|
||||
if(IsInputOpen) CloseInput();
|
||||
if(IsMidiOpen) CloseMidi();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MidiRenderer.OpenInput"/>
|
||||
public bool OpenInput()
|
||||
{
|
||||
if (_renderer.OpenInput())
|
||||
{
|
||||
_renderer.OnMidiEvent += RendererOnMidiEvent;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MidiRenderer.CloseInput"/>
|
||||
public bool CloseInput()
|
||||
{
|
||||
if (!_renderer.CloseInput()) return false;
|
||||
_renderer.OnMidiEvent -= RendererOnMidiEvent;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MidiRenderer.OpenMidi(string)"/>
|
||||
public bool OpenMidi(string filename)
|
||||
{
|
||||
if (!_renderer.OpenMidi(filename)) return false;
|
||||
_renderer.OnMidiEvent += RendererOnMidiEvent;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MidiRenderer.CloseMidi"/>
|
||||
public bool CloseMidi()
|
||||
{
|
||||
if (!_renderer.CloseMidi()) return false;
|
||||
_renderer.OnMidiEvent -= RendererOnMidiEvent;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever the renderer receives a midi event.
|
||||
/// </summary>
|
||||
/// <param name="midiEvent">The received midi event</param>
|
||||
private void RendererOnMidiEvent(MidiEvent midiEvent)
|
||||
{
|
||||
SendNetworkMessage(new InstrumentMidiEventMessage(midiEvent, _timing.CurTime.TotalMilliseconds));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class InteractionOutlineComponent : Component
|
||||
{
|
||||
private const string ShaderInRange = "selection_outline_inrange";
|
||||
private const string ShaderOutOfRange = "selection_outline";
|
||||
|
||||
public override string Name => "InteractionOutline";
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private ShaderInstance _selectionShaderInstance;
|
||||
private ShaderInstance _selectionShaderInRangeInstance;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_selectionShaderInRangeInstance = _prototypeManager.Index<ShaderPrototype>(ShaderInRange).Instance();
|
||||
_selectionShaderInstance = _prototypeManager.Index<ShaderPrototype>(ShaderOutOfRange).Instance();
|
||||
}
|
||||
|
||||
public void OnMouseEnter(bool inInteractionRange)
|
||||
{
|
||||
if (Owner.TryGetComponent(out ISpriteComponent sprite))
|
||||
{
|
||||
sprite.PostShader = inInteractionRange ? _selectionShaderInRangeInstance : _selectionShaderInstance;
|
||||
sprite.RenderOrder = Owner.EntityManager.CurrentTick.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMouseLeave()
|
||||
{
|
||||
if (Owner.TryGetComponent(out ISpriteComponent sprite))
|
||||
{
|
||||
sprite.PostShader = null;
|
||||
sprite.RenderOrder = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateInRange(bool inInteractionRange)
|
||||
{
|
||||
if (Owner.TryGetComponent(out ISpriteComponent sprite))
|
||||
{
|
||||
sprite.PostShader = inInteractionRange ? _selectionShaderInRangeInstance : _selectionShaderInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
using Robust.Shared.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using Content.Client.UserInterface;
|
||||
@@ -10,7 +13,6 @@ using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
@@ -183,8 +185,15 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
if (GetEntity(ActiveIndex) != null)
|
||||
{
|
||||
SendNetworkMessage(new ActivateInhandMsg());
|
||||
SendNetworkMessage(new UseInHandMsg());
|
||||
}
|
||||
}
|
||||
|
||||
public void ActivateItemInHand(string handIndex)
|
||||
{
|
||||
if (GetEntity(handIndex) == null)
|
||||
return;
|
||||
SendNetworkMessage(new ActivateInHandMsg(handIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
@@ -18,7 +17,6 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
public override string Name => "Item";
|
||||
public override uint? NetID => ContentNetIDs.ITEM;
|
||||
public override Type StateType => typeof(ItemComponentState);
|
||||
|
||||
[ViewVariables] protected ResourcePath RsiPath;
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ItemStatusComponent : Component
|
||||
{
|
||||
public override string Name => "ItemStatus";
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using Content.Client.GameObjects.Components.IconSmoothing;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.GameObjects.SpriteComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
@@ -26,19 +29,35 @@ namespace Content.Client.GameObjects.Components
|
||||
public CornerFill LastCornerSW { get; private set; }
|
||||
public CornerFill LastCornerNW { get; private set; }
|
||||
|
||||
public override void Startup()
|
||||
[ViewVariables]
|
||||
private IEntity _overlayEntity;
|
||||
private ISpriteComponent _overlaySprite;
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
_overlayEntity = Owner.EntityManager.SpawnEntity("low_wall_overlay", Owner.Transform.GridPosition);
|
||||
_overlayEntity.Transform.AttachParent(Owner);
|
||||
|
||||
_overlaySprite = _overlayEntity.GetComponent<ISpriteComponent>();
|
||||
|
||||
var overState0 = $"{StateBase}over_0";
|
||||
Sprite.LayerMapSet(OverCornerLayers.SE, Sprite.AddLayerState(overState0));
|
||||
Sprite.LayerSetDirOffset(OverCornerLayers.SE, DirectionOffset.None);
|
||||
Sprite.LayerMapSet(OverCornerLayers.NE, Sprite.AddLayerState(overState0));
|
||||
Sprite.LayerSetDirOffset(OverCornerLayers.NE, DirectionOffset.CounterClockwise);
|
||||
Sprite.LayerMapSet(OverCornerLayers.NW, Sprite.AddLayerState(overState0));
|
||||
Sprite.LayerSetDirOffset(OverCornerLayers.NW, DirectionOffset.Flip);
|
||||
Sprite.LayerMapSet(OverCornerLayers.SW, Sprite.AddLayerState(overState0));
|
||||
Sprite.LayerSetDirOffset(OverCornerLayers.SW, DirectionOffset.Clockwise);
|
||||
_overlaySprite.LayerMapSet(OverCornerLayers.SE, _overlaySprite.AddLayerState(overState0));
|
||||
_overlaySprite.LayerSetDirOffset(OverCornerLayers.SE, DirectionOffset.None);
|
||||
_overlaySprite.LayerMapSet(OverCornerLayers.NE, _overlaySprite.AddLayerState(overState0));
|
||||
_overlaySprite.LayerSetDirOffset(OverCornerLayers.NE, DirectionOffset.CounterClockwise);
|
||||
_overlaySprite.LayerMapSet(OverCornerLayers.NW, _overlaySprite.AddLayerState(overState0));
|
||||
_overlaySprite.LayerSetDirOffset(OverCornerLayers.NW, DirectionOffset.Flip);
|
||||
_overlaySprite.LayerMapSet(OverCornerLayers.SW, _overlaySprite.AddLayerState(overState0));
|
||||
_overlaySprite.LayerSetDirOffset(OverCornerLayers.SW, DirectionOffset.Clockwise);
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_overlayEntity.Delete();
|
||||
}
|
||||
|
||||
internal override void CalculateNewSprite()
|
||||
@@ -159,10 +178,10 @@ namespace Content.Client.GameObjects.Components
|
||||
Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}");
|
||||
Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}");
|
||||
|
||||
Sprite.LayerSetState(OverCornerLayers.NE, $"{StateBase}over_{(int) lowCornerNE}");
|
||||
Sprite.LayerSetState(OverCornerLayers.SE, $"{StateBase}over_{(int) lowCornerSE}");
|
||||
Sprite.LayerSetState(OverCornerLayers.SW, $"{StateBase}over_{(int) lowCornerSW}");
|
||||
Sprite.LayerSetState(OverCornerLayers.NW, $"{StateBase}over_{(int) lowCornerNW}");
|
||||
_overlaySprite.LayerSetState(OverCornerLayers.NE, $"{StateBase}over_{(int) lowCornerNE}");
|
||||
_overlaySprite.LayerSetState(OverCornerLayers.SE, $"{StateBase}over_{(int) lowCornerSE}");
|
||||
_overlaySprite.LayerSetState(OverCornerLayers.SW, $"{StateBase}over_{(int) lowCornerSW}");
|
||||
_overlaySprite.LayerSetState(OverCornerLayers.NW, $"{StateBase}over_{(int) lowCornerNW}");
|
||||
|
||||
LastCornerNE = cornerNE;
|
||||
LastCornerSE = cornerSE;
|
||||
@@ -178,7 +197,7 @@ namespace Content.Client.GameObjects.Components
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.Contracts.Pure]
|
||||
[Pure]
|
||||
private (bool connected, bool lowWall) MatchingWall(IEnumerable<IEntity> candidates)
|
||||
{
|
||||
foreach (var entity in candidates)
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using static Content.Shared.GameObjects.Components.SharedMagicMirrorComponent;
|
||||
using static Content.Client.StaticIoC;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class MagicMirrorBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private MagicMirrorWindow _window;
|
||||
|
||||
public MagicMirrorBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new MagicMirrorWindow(this);
|
||||
_window.OnClose += Close;
|
||||
_window.Open();
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case MagicMirrorInitialDataMessage initialData:
|
||||
_window.SetInitialData(initialData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void HairSelected(string name, bool isFacialHair)
|
||||
{
|
||||
SendMessage(new HairSelectedMessage(name, isFacialHair));
|
||||
}
|
||||
|
||||
internal void HairColorSelected(Color color, bool isFacialHair)
|
||||
{
|
||||
SendMessage(new HairColorSelectedMessage((color.RByte, color.GByte, color.BByte),
|
||||
isFacialHair));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_window.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FacialHairStylePicker : HairStylePicker
|
||||
{
|
||||
public override void Populate()
|
||||
{
|
||||
var humanFacialHairRSIPath = SharedSpriteComponent.TextureRoot / "Mob/human_facial_hair.rsi";
|
||||
var humanFacialHairRSI = ResC.GetResource<RSIResource>(humanFacialHairRSIPath).RSI;
|
||||
|
||||
var styles = HairStyles.FacialHairStylesMap.ToList();
|
||||
styles.Sort(HairStyles.FacialHairStyleComparer);
|
||||
|
||||
foreach (var (styleName, styleState) in HairStyles.FacialHairStylesMap)
|
||||
{
|
||||
Items.AddItem(styleName, humanFacialHairRSI[styleState].Frame0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HairStylePicker : Control
|
||||
{
|
||||
public event Action<Color> OnHairColorPicked;
|
||||
public event Action<string> OnHairStylePicked;
|
||||
|
||||
protected readonly ItemList Items;
|
||||
|
||||
private readonly ColorSlider _colorSliderR;
|
||||
private readonly ColorSlider _colorSliderG;
|
||||
private readonly ColorSlider _colorSliderB;
|
||||
|
||||
private Color _lastColor;
|
||||
|
||||
public void SetData(Color color, string styleName)
|
||||
{
|
||||
_lastColor = color;
|
||||
|
||||
_colorSliderR.ColorValue = color.RByte;
|
||||
_colorSliderG.ColorValue = color.GByte;
|
||||
_colorSliderB.ColorValue = color.BByte;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.Selected = item.Text == styleName;
|
||||
}
|
||||
|
||||
UpdateStylePickerColor();
|
||||
}
|
||||
|
||||
private void UpdateStylePickerColor()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.IconModulate = _lastColor;
|
||||
}
|
||||
}
|
||||
|
||||
public HairStylePicker()
|
||||
{
|
||||
var vBox = new VBoxContainer();
|
||||
AddChild(vBox);
|
||||
|
||||
vBox.AddChild(_colorSliderR = new ColorSlider(NanoStyle.StyleClassSliderRed));
|
||||
vBox.AddChild(_colorSliderG = new ColorSlider(NanoStyle.StyleClassSliderGreen));
|
||||
vBox.AddChild(_colorSliderB = new ColorSlider(NanoStyle.StyleClassSliderBlue));
|
||||
|
||||
Action colorValueChanged = ColorValueChanged;
|
||||
_colorSliderR.OnValueChanged += colorValueChanged;
|
||||
_colorSliderG.OnValueChanged += colorValueChanged;
|
||||
_colorSliderB.OnValueChanged += colorValueChanged;
|
||||
|
||||
Items = new ItemList
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
CustomMinimumSize = (300, 250)
|
||||
};
|
||||
vBox.AddChild(Items);
|
||||
Items.OnItemSelected += ItemSelected;
|
||||
}
|
||||
|
||||
private void ColorValueChanged()
|
||||
{
|
||||
var newColor = new Color(
|
||||
_colorSliderR.ColorValue,
|
||||
_colorSliderG.ColorValue,
|
||||
_colorSliderB.ColorValue
|
||||
);
|
||||
|
||||
OnHairColorPicked?.Invoke(newColor);
|
||||
_lastColor = newColor;
|
||||
UpdateStylePickerColor();
|
||||
}
|
||||
|
||||
public virtual void Populate()
|
||||
{
|
||||
var humanHairRSIPath = SharedSpriteComponent.TextureRoot / "Mob/human_hair.rsi";
|
||||
var humanHairRSI = ResC.GetResource<RSIResource>(humanHairRSIPath).RSI;
|
||||
|
||||
var styles = HairStyles.HairStylesMap.ToList();
|
||||
styles.Sort(HairStyles.HairStyleComparer);
|
||||
|
||||
foreach (var (styleName, styleState) in styles)
|
||||
{
|
||||
Items.AddItem(styleName, humanHairRSI[styleState].Frame0);
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemSelected(ItemList.ItemListSelectedEventArgs args)
|
||||
{
|
||||
OnHairStylePicked?.Invoke(Items[args.ItemIndex].Text);
|
||||
}
|
||||
|
||||
private sealed class ColorSlider : Control
|
||||
{
|
||||
private readonly Slider _slider;
|
||||
private readonly LineEdit _textBox;
|
||||
private byte _colorValue;
|
||||
private bool _ignoreEvents;
|
||||
|
||||
public event Action OnValueChanged;
|
||||
|
||||
public byte ColorValue
|
||||
{
|
||||
get => _colorValue;
|
||||
set
|
||||
{
|
||||
_ignoreEvents = true;
|
||||
_colorValue = value;
|
||||
_slider.Value = value;
|
||||
_textBox.Text = value.ToString();
|
||||
_ignoreEvents = false;
|
||||
}
|
||||
}
|
||||
|
||||
public ColorSlider(string styleClass)
|
||||
{
|
||||
_slider = new Slider
|
||||
{
|
||||
StyleClasses = {styleClass},
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
MaxValue = byte.MaxValue
|
||||
};
|
||||
_textBox = new LineEdit
|
||||
{
|
||||
CustomMinimumSize = (50, 0)
|
||||
};
|
||||
|
||||
AddChild(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_slider,
|
||||
_textBox
|
||||
}
|
||||
});
|
||||
|
||||
_slider.OnValueChanged += _ =>
|
||||
{
|
||||
if (_ignoreEvents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_colorValue = (byte) _slider.Value;
|
||||
_textBox.Text = _colorValue.ToString();
|
||||
|
||||
OnValueChanged?.Invoke();
|
||||
};
|
||||
|
||||
_textBox.OnTextChanged += ev =>
|
||||
{
|
||||
if (_ignoreEvents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(ev.Text, out var result))
|
||||
{
|
||||
result = result.Clamp(0, byte.MaxValue);
|
||||
|
||||
_ignoreEvents = true;
|
||||
_colorValue = (byte) result;
|
||||
_slider.Value = result;
|
||||
_ignoreEvents = false;
|
||||
|
||||
OnValueChanged?.Invoke();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MagicMirrorWindow : SS14Window
|
||||
{
|
||||
private readonly HairStylePicker _hairStylePicker;
|
||||
private readonly FacialHairStylePicker _facialHairStylePicker;
|
||||
|
||||
protected override Vector2? CustomSize => (500, 360);
|
||||
|
||||
public MagicMirrorWindow(MagicMirrorBoundUserInterface owner)
|
||||
{
|
||||
Title = Loc.GetString("Magic Mirror");
|
||||
|
||||
_hairStylePicker = new HairStylePicker {SizeFlagsHorizontal = SizeFlags.FillExpand};
|
||||
_hairStylePicker.Populate();
|
||||
_hairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, false);
|
||||
_hairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, false);
|
||||
|
||||
_facialHairStylePicker = new FacialHairStylePicker {SizeFlagsHorizontal = SizeFlags.FillExpand};
|
||||
_facialHairStylePicker.Populate();
|
||||
_facialHairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, true);
|
||||
_facialHairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, true);
|
||||
|
||||
Contents.AddChild(new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 8,
|
||||
Children = {_hairStylePicker, _facialHairStylePicker}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_hairStylePicker.Dispose();
|
||||
_facialHairStylePicker.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInitialData(MagicMirrorInitialDataMessage initialData)
|
||||
{
|
||||
_facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairName);
|
||||
_hairStylePicker.SetData(initialData.HairColor, initialData.HairName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
{
|
||||
public class MedicalScannerBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
public MedicalScannerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
private MedicalScannerWindow _window;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_window = new MedicalScannerWindow
|
||||
{
|
||||
Title = Owner.Owner.Name,
|
||||
};
|
||||
_window.OnClose += Close;
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
_window.Populate((MedicalScannerBoundUserInterfaceState) state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent;
|
||||
using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent.MedicalScannerStatus;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
{
|
||||
public class MedicalScannerVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
if (!component.TryGetData(MedicalScannerVisuals.Status, out MedicalScannerStatus status)) return;
|
||||
sprite.LayerSetState(MedicalScannerVisualLayers.Machine, StatusToMachineStateId(status));
|
||||
sprite.LayerSetState(MedicalScannerVisualLayers.Terminal, StatusToTerminalStateId(status));
|
||||
}
|
||||
|
||||
private string StatusToMachineStateId(MedicalScannerStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Off: return "scanner_off";
|
||||
case Open: return "scanner_open";
|
||||
case Red: return "scanner_red";
|
||||
case Death: return "scanner_death";
|
||||
case Green: return "scanner_green";
|
||||
case Yellow: return "scanner_yellow";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus");
|
||||
}
|
||||
}
|
||||
|
||||
private string StatusToTerminalStateId(MedicalScannerStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Off: return "scanner_terminal_off";
|
||||
case Open: return "scanner_terminal_blue";
|
||||
case Red: return "scanner_terminal_red";
|
||||
case Death: return "scanner_terminal_dead";
|
||||
case Green: return "scanner_terminal_green";
|
||||
case Yellow: return "scanner_terminal_blue";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus");
|
||||
}
|
||||
}
|
||||
|
||||
public enum MedicalScannerVisualLayers
|
||||
{
|
||||
Machine,
|
||||
Terminal,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
using Robust.Shared.Utility;
|
||||
using System.Text;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Maths;
|
||||
using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
{
|
||||
public class MedicalScannerWindow : SS14Window
|
||||
{
|
||||
protected override Vector2? CustomSize => (485, 90);
|
||||
|
||||
public void Populate(MedicalScannerBoundUserInterfaceState state)
|
||||
{
|
||||
Contents.RemoveAllChildren();
|
||||
var text = new StringBuilder();
|
||||
if (state.MaxHealth == 0)
|
||||
{
|
||||
text.Append("No patient data.");
|
||||
} else
|
||||
{
|
||||
text.Append($"Patient's health: {state.CurrentHealth}/{state.MaxHealth}\n");
|
||||
|
||||
if (state.DamageDictionary != null)
|
||||
{
|
||||
foreach (var (dmgType, amount) in state.DamageDictionary)
|
||||
{
|
||||
text.Append($"\n{dmgType}: {amount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Contents.AddChild(new Label(){Text = text.ToString()});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,10 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
public sealed class CameraRecoilComponent : SharedCameraRecoilComponent
|
||||
{
|
||||
// Maximum rate of magnitude restore towards 0 kick.
|
||||
private const float RestoreRateMax = 1.5f;
|
||||
private const float RestoreRateMax = 2f;
|
||||
|
||||
// Minimum rate of magnitude restore towards 0 kick.
|
||||
private const float RestoreRateMin = 0.5f;
|
||||
private const float RestoreRateMin = 1f;
|
||||
|
||||
// Time in seconds since the last kick that lerps RestoreRateMin and RestoreRateMax
|
||||
private const float RestoreRateRamp = 0.05f;
|
||||
@@ -29,6 +29,10 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
|
||||
private EyeComponent _eye;
|
||||
|
||||
// Basically I needed a way to chain this effect for the attack lunge animation.
|
||||
// Sorry!
|
||||
public Vector2 BaseOffset { get; set; }
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -77,13 +81,25 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
var normalized = _currentKick.Normalized;
|
||||
var restoreRate = FloatMath.Lerp(RestoreRateMin, RestoreRateMax, Math.Min(1, _lastKickTime/RestoreRateRamp));
|
||||
var restore = normalized * restoreRate * frameTime;
|
||||
_currentKick -= restore;
|
||||
var (x, y) = _currentKick - restore;
|
||||
if (Math.Sign(x) != Math.Sign(_currentKick.X))
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (Math.Sign(y) != Math.Sign(_currentKick.Y))
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
|
||||
_currentKick = (x, y);
|
||||
|
||||
_updateEye();
|
||||
}
|
||||
|
||||
private void _updateEye()
|
||||
{
|
||||
_eye.Offset = _currentKick;
|
||||
_eye.Offset = BaseOffset + _currentKick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Graphics.Overlays;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// A character UI component which shows the current damage state of the mob (living/dead)
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedOverlayEffectsComponent))]
|
||||
public sealed class ClientOverlayEffectsComponent : SharedOverlayEffectsComponent//, ICharacterUI
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// An enum representing the current state being applied to the user
|
||||
/// </summary>
|
||||
private ScreenEffects _currentEffect = ScreenEffects.None;
|
||||
|
||||
#pragma warning disable 649
|
||||
// Required dependencies
|
||||
[Dependency] private readonly IOverlayManager _overlayManager;
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <summary>
|
||||
/// Holds the screen effects that can be applied mapped ot their relevant overlay
|
||||
/// </summary>
|
||||
private Dictionary<ScreenEffects, Overlay> _effectsDictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
||||
/// </summary>
|
||||
private bool CurrentlyControlled => _playerManager.LocalPlayer.ControlledEntity == Owner;
|
||||
|
||||
public override void OnAdd()
|
||||
{
|
||||
base.OnAdd();
|
||||
|
||||
_effectsDictionary = new Dictionary<ScreenEffects, Overlay>()
|
||||
{
|
||||
{ ScreenEffects.CircleMask, new CircleMaskOverlay() },
|
||||
{ ScreenEffects.GradientCircleMask, new GradientCircleMask() }
|
||||
};
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
SetOverlay(_currentEffect);
|
||||
break;
|
||||
case PlayerDetachedMsg _:
|
||||
RemoveOverlay();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is OverlayEffectComponentState state) || _currentEffect == state.ScreenEffect) return;
|
||||
SetOverlay(state.ScreenEffect);
|
||||
}
|
||||
|
||||
private void SetOverlay(ScreenEffects effect)
|
||||
{
|
||||
RemoveOverlay();
|
||||
|
||||
_currentEffect = effect;
|
||||
|
||||
ApplyOverlay();
|
||||
}
|
||||
|
||||
private void RemoveOverlay()
|
||||
{
|
||||
if (CurrentlyControlled && _currentEffect != ScreenEffects.None)
|
||||
{
|
||||
var appliedEffect = _effectsDictionary[_currentEffect];
|
||||
_overlayManager.RemoveOverlay(appliedEffect.ID);
|
||||
}
|
||||
|
||||
_currentEffect = ScreenEffects.None;
|
||||
}
|
||||
|
||||
private void ApplyOverlay()
|
||||
{
|
||||
if (CurrentlyControlled && _currentEffect != ScreenEffects.None)
|
||||
{
|
||||
var overlay = _effectsDictionary[_currentEffect];
|
||||
if (_overlayManager.HasOverlay(overlay.ID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_overlayManager.AddOverlay(overlay);
|
||||
Logger.InfoS("overlay", $"Changed overlay to {overlay}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[RegisterComponent]
|
||||
public sealed class ClientStatusEffectsComponent : SharedStatusEffectsComponent
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IResourceCache _resourceCache;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private StatusEffectsUI _ui;
|
||||
private IDictionary<StatusEffect, string> _icons = new Dictionary<StatusEffect, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
||||
/// </summary>
|
||||
private bool CurrentlyControlled => _playerManager.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity == Owner;
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
PlayerDetached();
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||
IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
PlayerAttached();
|
||||
break;
|
||||
case PlayerDetachedMsg _:
|
||||
PlayerDetached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is StatusEffectComponentState state) || _icons == state.StatusEffects) return;
|
||||
_icons = state.StatusEffects;
|
||||
UpdateIcons();
|
||||
}
|
||||
|
||||
private void PlayerAttached()
|
||||
{
|
||||
if (!CurrentlyControlled || _ui != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ui = new StatusEffectsUI();
|
||||
_userInterfaceManager.StateRoot.AddChild(_ui);
|
||||
UpdateIcons();
|
||||
}
|
||||
|
||||
private void PlayerDetached()
|
||||
{
|
||||
if (!CurrentlyControlled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ui?.Dispose();
|
||||
}
|
||||
|
||||
public void UpdateIcons()
|
||||
{
|
||||
if (!CurrentlyControlled || _ui == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ui.VBox.DisposeAllChildren();
|
||||
|
||||
foreach (var effect in _icons.OrderBy(x => (int) x.Key))
|
||||
{
|
||||
TextureRect newIcon = new TextureRect
|
||||
{
|
||||
TextureScale = (2, 2),
|
||||
Texture = _resourceCache.GetTexture(effect.Value)
|
||||
};
|
||||
|
||||
newIcon.Texture = _resourceCache.GetTexture(effect.Value);
|
||||
_ui.VBox.AddChild(newIcon);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveIcon(StatusEffect name)
|
||||
{
|
||||
_icons.Remove(name);
|
||||
UpdateIcons();
|
||||
Logger.InfoS("statuseffects", $"Removed icon {name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class CombatModeComponent : SharedCombatModeComponent
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool IsInCombatMode { get; private set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public TargetingZone ActiveZone { get; private set; }
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IGameHud _gameHud;
|
||||
#pragma warning restore 649
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
var state = (CombatModeComponentState) curState;
|
||||
|
||||
IsInCombatMode = state.IsInCombatMode;
|
||||
ActiveZone = state.TargetingZone;
|
||||
UpdateHud();
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
_gameHud.CombatPanelVisible = true;
|
||||
UpdateHud();
|
||||
break;
|
||||
|
||||
case PlayerDetachedMsg _:
|
||||
_gameHud.CombatPanelVisible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateHud()
|
||||
{
|
||||
_gameHud.CombatModeActive = IsInCombatMode;
|
||||
_gameHud.TargetingZone = ActiveZone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class HumanoidAppearanceComponent : SharedHumanoidAppearanceComponent
|
||||
{
|
||||
public override HumanoidCharacterAppearance Appearance
|
||||
{
|
||||
get => base.Appearance;
|
||||
set
|
||||
{
|
||||
base.Appearance = value;
|
||||
UpdateLooks();
|
||||
}
|
||||
}
|
||||
|
||||
public override Sex Sex
|
||||
{
|
||||
get => base.Sex;
|
||||
set
|
||||
{
|
||||
base.Sex = value;
|
||||
UpdateLooks();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
UpdateLooks();
|
||||
}
|
||||
|
||||
private void UpdateLooks()
|
||||
{
|
||||
if (Appearance is null) return;
|
||||
var sprite = Owner.GetComponent<SpriteComponent>();
|
||||
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.Hair, Appearance.HairColor);
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, Appearance.FacialHairColor);
|
||||
|
||||
sprite.LayerSetState(HumanoidVisualLayers.Chest, Sex == Sex.Male ? "human_chest_m" : "human_chest_f");
|
||||
sprite.LayerSetState(HumanoidVisualLayers.Head, Sex == Sex.Male ? "human_head_m" : "human_head_f");
|
||||
|
||||
sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, Sex == Sex.Female);
|
||||
|
||||
var hairStyle = Appearance.HairStyleName;
|
||||
if (string.IsNullOrWhiteSpace(hairStyle) || !HairStyles.HairStylesMap.ContainsKey(hairStyle))
|
||||
hairStyle = HairStyles.DefaultHairStyle;
|
||||
sprite.LayerSetState(HumanoidVisualLayers.Hair,
|
||||
HairStyles.HairStylesMap[hairStyle]);
|
||||
|
||||
var facialHairStyle = Appearance.FacialHairStyleName;
|
||||
if (string.IsNullOrWhiteSpace(facialHairStyle) || !HairStyles.FacialHairStylesMap.ContainsKey(facialHairStyle))
|
||||
facialHairStyle = HairStyles.DefaultFacialHairStyle;
|
||||
sprite.LayerSetState(HumanoidVisualLayers.FacialHair,
|
||||
HairStyles.FacialHairStylesMap[facialHairStyle]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class MeleeLungeComponent : Component
|
||||
{
|
||||
public override string Name => "MeleeLunge";
|
||||
|
||||
private const float ResetTime = 0.3f;
|
||||
private const float BaseOffset = 0.25f;
|
||||
|
||||
private Angle _angle;
|
||||
private float _time;
|
||||
|
||||
public void SetData(Angle angle)
|
||||
{
|
||||
_angle = angle;
|
||||
_time = 0;
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
_time += frameTime;
|
||||
|
||||
var offset = Vector2.Zero;
|
||||
var deleteSelf = false;
|
||||
|
||||
if (_time > ResetTime)
|
||||
{
|
||||
deleteSelf = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = _angle.RotateVec((BaseOffset, 0));
|
||||
offset *= (ResetTime - _time) / ResetTime;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out CameraRecoilComponent recoilComponent))
|
||||
{
|
||||
recoilComponent.BaseOffset = offset;
|
||||
}
|
||||
else if (Owner.TryGetComponent(out EyeComponent eyeComponent))
|
||||
{
|
||||
eyeComponent.Offset = offset;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out ISpriteComponent spriteComponent))
|
||||
{
|
||||
// We have to account for rotation so the offset still checks out.
|
||||
// SpriteComponent.Offset is applied before transform rotation (as expected).
|
||||
var worldRotation = Owner.Transform.WorldRotation;
|
||||
spriteComponent.Offset = new Angle(-worldRotation).RotateVec(offset);
|
||||
}
|
||||
|
||||
if (deleteSelf)
|
||||
{
|
||||
Owner.RemoveComponent<MeleeLungeComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.GameObjects.Components.Actor;
|
||||
using Content.Client.Graphics.Overlays;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// A character UI component which shows the current damage state of the mob (living/dead)
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class SpeciesUI : SharedSpeciesComponent//, ICharacterUI
|
||||
{
|
||||
private StatusEffectsUI _ui;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the godot control for the species window
|
||||
/// </summary>
|
||||
private SpeciesWindow _window;
|
||||
|
||||
/// <summary>
|
||||
/// An enum representing the current state being applied to the user
|
||||
/// </summary>
|
||||
private ScreenEffects _currentEffect = ScreenEffects.None;
|
||||
|
||||
#pragma warning disable 649
|
||||
// Required dependencies
|
||||
[Dependency] private readonly IOverlayManager _overlayManager;
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
|
||||
[Dependency] private readonly IResourceCache _resourceCache;
|
||||
#pragma warning restore 649
|
||||
|
||||
//Relevant interface implementation for the character UI controller
|
||||
public Control Scene => _window;
|
||||
public UIPriority Priority => UIPriority.Species;
|
||||
|
||||
/// <summary>
|
||||
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
||||
/// </summary>
|
||||
private bool CurrentlyControlled => _playerManager.LocalPlayer.ControlledEntity == Owner;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the screen effects that can be applied mapped ot their relevant overlay
|
||||
/// </summary>
|
||||
private Dictionary<ScreenEffects, Overlay> EffectsDictionary;
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
_window.Dispose();
|
||||
}
|
||||
|
||||
public override void OnAdd()
|
||||
{
|
||||
base.OnAdd();
|
||||
|
||||
_window = new SpeciesWindow();
|
||||
_ui = new StatusEffectsUI();
|
||||
|
||||
EffectsDictionary = new Dictionary<ScreenEffects, Overlay>()
|
||||
{
|
||||
{ ScreenEffects.CircleMask, new CircleMaskOverlay() },
|
||||
{ ScreenEffects.GradientCircleMask, new GradientCircleMask() }
|
||||
};
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case HudStateChange msg:
|
||||
if (CurrentlyControlled)
|
||||
{
|
||||
ChangeHudIcon(msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case PlayerAttachedMsg _:
|
||||
_ui.Parent?.RemoveChild(_ui);
|
||||
|
||||
_userInterfaceManager.StateRoot.AddChild(_ui);
|
||||
ApplyOverlay();
|
||||
break;
|
||||
|
||||
case PlayerDetachedMsg _:
|
||||
_ui.Parent?.RemoveChild(_ui);
|
||||
RemoveOverlay();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeHudIcon(HudStateChange changeMessage)
|
||||
{
|
||||
var path = SharedSpriteComponent.TextureRoot / changeMessage.StateSprite;
|
||||
var texture = _resourceCache.GetTexture(path);
|
||||
|
||||
_window.SetIcon(texture);
|
||||
_ui.SetHealthIcon(texture);
|
||||
|
||||
SetOverlay(changeMessage);
|
||||
}
|
||||
|
||||
private void SetOverlay(HudStateChange message)
|
||||
{
|
||||
RemoveOverlay();
|
||||
|
||||
_currentEffect = message.effect;
|
||||
|
||||
ApplyOverlay();
|
||||
}
|
||||
|
||||
private void RemoveOverlay()
|
||||
{
|
||||
if (_currentEffect != ScreenEffects.None)
|
||||
{
|
||||
var appliedEffect = EffectsDictionary[_currentEffect];
|
||||
_overlayManager.RemoveOverlay(appliedEffect.ID);
|
||||
}
|
||||
|
||||
_currentEffect = ScreenEffects.None;
|
||||
}
|
||||
|
||||
private void ApplyOverlay()
|
||||
{
|
||||
if (_currentEffect != ScreenEffects.None)
|
||||
{
|
||||
var overlay = EffectsDictionary[_currentEffect];
|
||||
if (_overlayManager.HasOverlay(overlay.ID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_overlayManager.AddOverlay(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
private class SpeciesWindow : TextureRect
|
||||
{
|
||||
public SpeciesWindow()
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter;
|
||||
SizeFlagsVertical = SizeFlags.None;
|
||||
|
||||
Texture = IoCManager.Resolve<IResourceCache>().GetTexture("/Textures/Mob/UI/Human/human0.png");
|
||||
}
|
||||
|
||||
public void SetIcon(Texture texture)
|
||||
{
|
||||
Texture = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,12 @@
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
public class SpeciesVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
@@ -20,7 +14,7 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
if (component.TryGetData<SharedSpeciesComponent.MobState>(SharedSpeciesComponent.MobVisuals.RotationState, out var state))
|
||||
{
|
||||
switch (state)
|
||||
switch (state)
|
||||
{
|
||||
case SharedSpeciesComponent.MobState.Stand:
|
||||
sprite.Rotation = 0;
|
||||
@@ -32,4 +26,4 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Nutrition
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class DrinkFoodContainerVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private string _baseState;
|
||||
private int _steps;
|
||||
private DrinkFoodContainerVisualMode _mode;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
_baseState = node.GetNode("base_state").AsString();
|
||||
_steps = node.GetNode("steps").AsInt();
|
||||
try
|
||||
{
|
||||
_mode = node.GetNode("mode").AsEnum<DrinkFoodContainerVisualMode>();
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
_mode = DrinkFoodContainerVisualMode.Rounded;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
if (!component.TryGetData<int>(DrinkFoodContainerVisuals.Current, out var current))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!component.TryGetData<int>(DrinkFoodContainerVisuals.Capacity, out var capacity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int step;
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case DrinkFoodContainerVisualMode.Discrete:
|
||||
step = Math.Min(_steps - 1, current);
|
||||
break;
|
||||
case DrinkFoodContainerVisualMode.Rounded:
|
||||
step = ContentHelpers.RoundToLevels(current, capacity, _steps);
|
||||
break;
|
||||
default:
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
|
||||
sprite.LayerSetState(0, $"{_baseState}-{step}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Nutrition
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class DrinkFoodVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private int _steps;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
_steps = node.GetNode("steps").AsInt();
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
if (!component.TryGetData<int>(SharedFoodComponent.FoodVisuals.MaxUses, out var maxUses))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.TryGetData<int>(SharedFoodComponent.FoodVisuals.Visual, out var usesLeft))
|
||||
{
|
||||
var step = ContentHelpers.RoundToLevels(usesLeft, maxUses, _steps);
|
||||
sprite.LayerSetState(0, $"icon-{step}");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(0, "icon-0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,12 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using NJsonSchema.Validation;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Power
|
||||
{
|
||||
@@ -27,10 +21,7 @@ namespace Content.Client.GameObjects.Components.Power
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new ApcWindow
|
||||
{
|
||||
MarginRight = 426.0f, MarginBottom = 270.0f
|
||||
};
|
||||
_window = new ApcWindow();
|
||||
_window.OnClose += Close;
|
||||
_window.OpenCenteredMinSize();
|
||||
|
||||
@@ -72,34 +63,34 @@ namespace Content.Client.GameObjects.Components.Power
|
||||
|
||||
_chargeBar.Value = castState.Charge;
|
||||
UpdateChargeBarColor(castState.Charge);
|
||||
float ChargePercentage = (castState.Charge / _chargeBar.MaxValue) * 100.0f;
|
||||
_window.ChargePercentage.Text = " " + ChargePercentage.ToString("0.00") + "%";
|
||||
var chargePercentage = (castState.Charge / _chargeBar.MaxValue) * 100.0f;
|
||||
_window.ChargePercentage.Text = " " + chargePercentage.ToString("0.00") + "%";
|
||||
}
|
||||
|
||||
private void UpdateChargeBarColor(float charge)
|
||||
{
|
||||
float normalizedCharge = charge / _chargeBar.MaxValue;
|
||||
var normalizedCharge = charge / _chargeBar.MaxValue;
|
||||
|
||||
float leftHue = 0.0f;// Red
|
||||
float middleHue = 0.066f;// Orange
|
||||
float rightHue = 0.33f;// Green
|
||||
float saturation = 1.0f;// Uniform saturation
|
||||
float value = 0.8f;// Uniform value / brightness
|
||||
float alpha = 1.0f;// Uniform alpha
|
||||
const float leftHue = 0.0f; // Red
|
||||
const float middleHue = 0.066f; // Orange
|
||||
const float rightHue = 0.33f; // Green
|
||||
const float saturation = 1.0f; // Uniform saturation
|
||||
const float value = 0.8f; // Uniform value / brightness
|
||||
const float alpha = 1.0f; // Uniform alpha
|
||||
|
||||
// These should add up to 1.0 or your transition won't be smooth
|
||||
float leftSideSize = 0.5f;// Fraction of _chargeBar lerped from leftHue to middleHue
|
||||
float rightSideSize = 0.5f;// Fraction of _chargeBar lerped from middleHue to rightHue
|
||||
const float leftSideSize = 0.5f; // Fraction of _chargeBar lerped from leftHue to middleHue
|
||||
const float rightSideSize = 0.5f; // Fraction of _chargeBar lerped from middleHue to rightHue
|
||||
|
||||
float finalHue;
|
||||
if (normalizedCharge <= leftSideSize)
|
||||
{
|
||||
normalizedCharge /= leftSideSize;// Adjust range to 0.0 to 1.0
|
||||
normalizedCharge /= leftSideSize; // Adjust range to 0.0 to 1.0
|
||||
finalHue = FloatMath.Lerp(leftHue, middleHue, normalizedCharge);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalizedCharge = (normalizedCharge - leftSideSize) / rightSideSize;// Adjust range to 0.0 to 1.0.
|
||||
normalizedCharge = (normalizedCharge - leftSideSize) / rightSideSize; // Adjust range to 0.0 to 1.0.
|
||||
finalHue = FloatMath.Lerp(middleHue, rightHue, normalizedCharge);
|
||||
}
|
||||
|
||||
@@ -109,7 +100,7 @@ namespace Content.Client.GameObjects.Components.Power
|
||||
_chargeBar.ForegroundStyleBoxOverride = new StyleBoxFlat();
|
||||
}
|
||||
|
||||
var foregroundStyleBoxOverride = (StyleBoxFlat)_chargeBar.ForegroundStyleBoxOverride;
|
||||
var foregroundStyleBoxOverride = (StyleBoxFlat) _chargeBar.ForegroundStyleBoxOverride;
|
||||
foregroundStyleBoxOverride.BackgroundColor =
|
||||
Color.FromHsv(new Vector4(finalHue, saturation, value, alpha));
|
||||
}
|
||||
@@ -134,37 +125,37 @@ namespace Content.Client.GameObjects.Components.Power
|
||||
public ApcWindow()
|
||||
{
|
||||
Title = "APC";
|
||||
var rows = new VBoxContainer("Rows");
|
||||
var rows = new VBoxContainer();
|
||||
|
||||
var statusHeader = new Label("StatusHeader") { Text = "Power Status: " };
|
||||
var statusHeader = new Label {Text = "Power Status: "};
|
||||
rows.AddChild(statusHeader);
|
||||
|
||||
var breaker = new HBoxContainer("Breaker");
|
||||
var breakerLabel = new Label("Label") { Text = "Main Breaker: " };
|
||||
BreakerButton = new CheckButton {Name = "Breaker", Text = "Toggle"};
|
||||
var breaker = new HBoxContainer();
|
||||
var breakerLabel = new Label {Text = "Main Breaker: "};
|
||||
BreakerButton = new CheckButton {Text = "Toggle"};
|
||||
breaker.AddChild(breakerLabel);
|
||||
breaker.AddChild(BreakerButton);
|
||||
rows.AddChild(breaker);
|
||||
|
||||
var externalStatus = new HBoxContainer("ExternalStatus");
|
||||
var externalStatusLabel = new Label("Label") { Text = "External Power: " };
|
||||
ExternalPowerStateLabel = new Label("Status") { Text = "Good" };
|
||||
var externalStatus = new HBoxContainer();
|
||||
var externalStatusLabel = new Label {Text = "External Power: "};
|
||||
ExternalPowerStateLabel = new Label {Text = "Good"};
|
||||
ExternalPowerStateLabel.SetOnlyStyleClass(NanoStyle.StyleClassPowerStateGood);
|
||||
externalStatus.AddChild(externalStatusLabel);
|
||||
externalStatus.AddChild(ExternalPowerStateLabel);
|
||||
rows.AddChild(externalStatus);
|
||||
|
||||
var charge = new HBoxContainer("Charge");
|
||||
var chargeLabel = new Label("Label") { Text = "Charge:" };
|
||||
ChargeBar = new ProgressBar("Charge")
|
||||
var charge = new HBoxContainer();
|
||||
var chargeLabel = new Label {Text = "Charge:"};
|
||||
ChargeBar = new ProgressBar
|
||||
{
|
||||
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
MinValue = 0.0f,
|
||||
MaxValue = 1.0f,
|
||||
Page = 0.0f,
|
||||
Value = 0.5f
|
||||
};
|
||||
ChargePercentage = new Label("ChargePercentage");
|
||||
ChargePercentage = new Label();
|
||||
charge.AddChild(chargeLabel);
|
||||
charge.AddChild(ChargeBar);
|
||||
charge.AddChild(ChargePercentage);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Power
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class PowerChargerVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
var sprite = entity.GetComponent<ISpriteComponent>();
|
||||
|
||||
// Base item
|
||||
sprite.LayerMapSet(Layers.Base, sprite.AddLayerState("empty"));
|
||||
|
||||
// Light
|
||||
sprite.LayerMapSet(Layers.Light, sprite.AddLayerState("light-off"));
|
||||
sprite.LayerSetShader(Layers.Light, "unshaded");
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
// Update base item
|
||||
if (component.TryGetData(CellVisual.Occupied, out bool occupied))
|
||||
{
|
||||
// TODO: don't throw if it doesn't have a full state
|
||||
sprite.LayerSetState(Layers.Base, occupied ? "full" : "empty");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(Layers.Base, "empty");
|
||||
}
|
||||
|
||||
// Update lighting
|
||||
if (component.TryGetData(CellVisual.Light, out CellChargerStatus status))
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case CellChargerStatus.Off:
|
||||
sprite.LayerSetState(Layers.Light, "light-off");
|
||||
break;
|
||||
case CellChargerStatus.Empty:
|
||||
sprite.LayerSetState(Layers.Light, "light-empty");
|
||||
break;
|
||||
case CellChargerStatus.Charging:
|
||||
sprite.LayerSetState(Layers.Light, "light-charging");
|
||||
break;
|
||||
case CellChargerStatus.Charged:
|
||||
sprite.LayerSetState(Layers.Light, "light-charged");
|
||||
break;
|
||||
default:
|
||||
sprite.LayerSetState(Layers.Light, "light-off");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(Layers.Light, "light-off");
|
||||
}
|
||||
}
|
||||
|
||||
enum Layers
|
||||
{
|
||||
Base,
|
||||
Light,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Power
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class PowerDeviceVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
var powered = component.TryGetData(PowerDeviceVisuals.Powered, out bool poweredVar) && poweredVar;
|
||||
sprite.LayerSetVisible(PowerDeviceVisualLayers.Powered, powered);
|
||||
}
|
||||
}
|
||||
|
||||
public enum PowerDeviceVisualLayers
|
||||
{
|
||||
Powered
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,6 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Power
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Content.Client.GameObjects.Components.Research
|
||||
|
||||
public MaterialStorageComponent Storage { get; private set; }
|
||||
public SharedLatheComponent Lathe { get; private set; }
|
||||
public LatheDatabaseComponent Database { get; private set; }
|
||||
public SharedLatheDatabaseComponent Database { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public Queue<LatheRecipePrototype> QueuedRecipes => _queuedRecipes;
|
||||
@@ -37,17 +37,18 @@ namespace Content.Client.GameObjects.Components.Research
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
if (!Owner.Owner.TryGetComponent(out MaterialStorageComponent storage)
|
||||
|| !Owner.Owner.TryGetComponent(out SharedLatheComponent lathe)
|
||||
|| !Owner.Owner.TryGetComponent(out LatheDatabaseComponent database)) return;
|
||||
|| !Owner.Owner.TryGetComponent(out SharedLatheDatabaseComponent database)) return;
|
||||
|
||||
|
||||
|
||||
Storage = storage;
|
||||
Lathe = lathe;
|
||||
Database = database;
|
||||
|
||||
menu = new LatheMenu {Owner = this};
|
||||
menu = new LatheMenu(this);
|
||||
queueMenu = new LatheQueueMenu { Owner = this };
|
||||
|
||||
menu.OnClose += Close;
|
||||
@@ -57,6 +58,16 @@ namespace Content.Client.GameObjects.Components.Research
|
||||
|
||||
menu.QueueButton.OnPressed += (args) => { queueMenu.OpenCentered(); };
|
||||
|
||||
menu.ServerConnectButton.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedLatheComponent.LatheServerSelectionMessage());
|
||||
};
|
||||
|
||||
menu.ServerSyncButton.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedLatheComponent.LatheServerSyncMessage());
|
||||
};
|
||||
|
||||
storage.OnMaterialStorageChanged += menu.PopulateDisabled;
|
||||
storage.OnMaterialStorageChanged += menu.PopulateMaterials;
|
||||
|
||||
@@ -74,10 +85,10 @@ namespace Content.Client.GameObjects.Components.Research
|
||||
{
|
||||
case SharedLatheComponent.LatheProducingRecipeMessage msg:
|
||||
if (!_prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe)) break;
|
||||
queueMenu.SetInfo(recipe);
|
||||
queueMenu?.SetInfo(recipe);
|
||||
break;
|
||||
case SharedLatheComponent.LatheStoppedProducingRecipeMessage msg:
|
||||
queueMenu.ClearInfo();
|
||||
case SharedLatheComponent.LatheStoppedProducingRecipeMessage _:
|
||||
queueMenu?.ClearInfo();
|
||||
break;
|
||||
case SharedLatheComponent.LatheFullQueueMessage msg:
|
||||
_queuedRecipes.Clear();
|
||||
@@ -86,7 +97,7 @@ namespace Content.Client.GameObjects.Components.Research
|
||||
if (!_prototypeManager.TryIndex(id, out LatheRecipePrototype recipePrototype)) break;
|
||||
_queuedRecipes.Enqueue(recipePrototype);
|
||||
}
|
||||
queueMenu.PopulateList();
|
||||
queueMenu?.PopulateList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.Research;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Research
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedLatheDatabaseComponent))]
|
||||
public class ProtolatheDatabaseComponent : SharedProtolatheDatabaseComponent
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
[Dependency]
|
||||
private IPrototypeManager _prototypeManager;
|
||||
#pragma warning restore
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the database gets updated.
|
||||
/// </summary>
|
||||
public event Action OnDatabaseUpdated;
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is ProtolatheDatabaseState state)) return;
|
||||
Clear();
|
||||
foreach (var ID in state.Recipes)
|
||||
{
|
||||
if(!_prototypeManager.TryIndex(ID, out LatheRecipePrototype recipe)) continue;
|
||||
AddRecipe(recipe);
|
||||
}
|
||||
|
||||
OnDatabaseUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Research
|
||||
{
|
||||
public class ResearchClientBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private ResearchClientServerSelectionMenu _menu;
|
||||
|
||||
public ResearchClientBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
SendMessage(new SharedResearchClientComponent.ResearchClientSyncMessage());
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = new ResearchClientServerSelectionMenu() { Owner = this };
|
||||
|
||||
_menu.OnClose += Close;
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
public void SelectServer(int serverId)
|
||||
{
|
||||
SendMessage(new SharedResearchClientComponent.ResearchClientServerSelectedMessage(serverId));
|
||||
}
|
||||
|
||||
public void DeselectServer()
|
||||
{
|
||||
SendMessage(new SharedResearchClientComponent.ResearchClientServerDeselectedMessage());
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (!(state is SharedResearchClientComponent.ResearchClientBoundInterfaceState rstate)) return;
|
||||
_menu.Populate(rstate.ServerCount, rstate.ServerNames, rstate.ServerIds, rstate.SelectedServerId);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Research
|
||||
{
|
||||
public class ResearchClientServerSelectionMenu : SS14Window
|
||||
{
|
||||
private ItemList _servers;
|
||||
private int _serverCount = 0;
|
||||
private string[] _serverNames = new string[]{};
|
||||
private int[] _serverIds = new int[]{};
|
||||
private int _selectedServerId = -1;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
protected override Vector2? CustomSize => (300, 300);
|
||||
public ResearchClientBoundUserInterface Owner { get; set; }
|
||||
|
||||
public ResearchClientServerSelectionMenu()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Title = _localizationManager.GetString("Research Server Selection");
|
||||
|
||||
_servers = new ItemList() {SelectMode = ItemList.ItemListSelectMode.Single};
|
||||
|
||||
_servers.OnItemSelected += OnItemSelected;
|
||||
_servers.OnItemDeselected += OnItemDeselected;
|
||||
|
||||
var margin = new MarginContainer()
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
/*MarginTop = 5f,
|
||||
MarginLeft = 5f,
|
||||
MarginRight = -5f,
|
||||
MarginBottom = -5f,*/
|
||||
};
|
||||
|
||||
margin.AddChild(_servers);
|
||||
|
||||
Contents.AddChild(margin);
|
||||
}
|
||||
|
||||
public void OnItemSelected(ItemList.ItemListSelectedEventArgs itemListSelectedEventArgs)
|
||||
{
|
||||
Owner.SelectServer(_serverIds[itemListSelectedEventArgs.ItemIndex]);
|
||||
}
|
||||
|
||||
public void OnItemDeselected(ItemList.ItemListDeselectedEventArgs itemListDeselectedEventArgs)
|
||||
{
|
||||
Owner.DeselectServer();
|
||||
}
|
||||
|
||||
public void Populate(int serverCount, string[] serverNames, int[] serverIds, int selectedServerId)
|
||||
{
|
||||
_serverCount = serverCount;
|
||||
_serverNames = serverNames;
|
||||
_serverIds = serverIds;
|
||||
_selectedServerId = selectedServerId;
|
||||
|
||||
// Disable so we can select the new selected server without triggering a new sync request.
|
||||
_servers.OnItemSelected -= OnItemSelected;
|
||||
_servers.OnItemDeselected -= OnItemDeselected;
|
||||
|
||||
_servers.Clear();
|
||||
for (var i = 0; i < _serverCount; i++)
|
||||
{
|
||||
var id = _serverIds[i];
|
||||
_servers.AddItem($"ID: {id} || {_serverNames[i]}");
|
||||
if (id == _selectedServerId)
|
||||
_servers[id].Selected = true;
|
||||
}
|
||||
|
||||
_servers.OnItemSelected += OnItemSelected;
|
||||
_servers.OnItemDeselected += OnItemDeselected;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using Content.Client.Research;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.Research;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Research
|
||||
{
|
||||
public class ResearchConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
public int Points { get; private set; } = 0;
|
||||
public int PointsPerSecond { get; private set; } = 0;
|
||||
private ResearchConsoleMenu _consoleMenu;
|
||||
private TechnologyDatabaseComponent TechnologyDatabase;
|
||||
|
||||
|
||||
public ResearchConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
SendMessage(new SharedResearchConsoleComponent.ConsoleServerSyncMessage());
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
if (!Owner.Owner.TryGetComponent(out TechnologyDatabase)) return;
|
||||
|
||||
_consoleMenu = new ResearchConsoleMenu(this);
|
||||
|
||||
_consoleMenu.OnClose += Close;
|
||||
|
||||
_consoleMenu.ServerSyncButton.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedResearchConsoleComponent.ConsoleServerSyncMessage());
|
||||
};
|
||||
|
||||
_consoleMenu.ServerSelectionButton.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedResearchConsoleComponent.ConsoleServerSelectionMessage());
|
||||
};
|
||||
|
||||
_consoleMenu.UnlockButton.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedResearchConsoleComponent.ConsoleUnlockTechnologyMessage(_consoleMenu.TechnologySelected.ID));
|
||||
};
|
||||
|
||||
_consoleMenu.OpenCentered();
|
||||
|
||||
TechnologyDatabase.OnDatabaseUpdated += _consoleMenu.Populate;
|
||||
}
|
||||
|
||||
public bool IsTechnologyUnlocked(TechnologyPrototype technology)
|
||||
{
|
||||
return TechnologyDatabase.IsTechnologyUnlocked(technology);
|
||||
}
|
||||
|
||||
public bool CanUnlockTechnology(TechnologyPrototype technology)
|
||||
{
|
||||
return TechnologyDatabase.CanUnlockTechnology(technology);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
var castState = (SharedResearchConsoleComponent.ResearchConsoleBoundInterfaceState)state;
|
||||
Points = castState.Points;
|
||||
PointsPerSecond = castState.PointsPerSecond;
|
||||
// We update the user interface here.
|
||||
_consoleMenu?.PopulatePoints();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
_consoleMenu?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.Research;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Research
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class TechnologyDatabaseComponent : SharedTechnologyDatabaseComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Event called when the database is updated.
|
||||
/// </summary>
|
||||
public event Action OnDatabaseUpdated;
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is TechnologyDatabaseState state)) return;
|
||||
_technologies.Clear();
|
||||
var protoManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
foreach (var techID in state.Technologies)
|
||||
{
|
||||
if (!protoManager.TryIndex(techID, out TechnologyPrototype technology)) continue;
|
||||
_technologies.Add(technology);
|
||||
}
|
||||
|
||||
OnDatabaseUpdated?.Invoke();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.Components.Sound;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timers;
|
||||
@@ -16,7 +16,9 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
{
|
||||
private readonly List<ScheduledSound> _schedules = new List<ScheduledSound>();
|
||||
private AudioSystem _audioSystem;
|
||||
private Random Random;
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IRobustRandom _random;
|
||||
#pragma warning restore 649
|
||||
|
||||
public override void StopAllSounds()
|
||||
{
|
||||
@@ -46,9 +48,8 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
public void Play(ScheduledSound schedule)
|
||||
{
|
||||
if (!schedule.Play) return;
|
||||
if (Random == null) Random = new Random(Owner.Uid.GetHashCode() ^ DateTime.Now.GetHashCode());
|
||||
|
||||
Timer.Spawn((int) schedule.Delay + (Random.Next((int) schedule.RandomDelay)),() =>
|
||||
Timer.Spawn((int) schedule.Delay + (_random.Next((int) schedule.RandomDelay)),() =>
|
||||
{
|
||||
if (!schedule.Play) return; // We make sure this hasn't changed.
|
||||
if (_audioSystem == null) _audioSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
@@ -80,7 +81,7 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
StopScheduledSound(msg.Filename);
|
||||
break;
|
||||
|
||||
case StopAllSoundsMessage msg:
|
||||
case StopAllSoundsMessage _:
|
||||
StopAllSounds();
|
||||
break;
|
||||
}
|
||||
|
||||
61
Content.Client/GameObjects/Components/StackComponent.cs
Normal file
61
Content.Client/GameObjects/Components/StackComponent.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class StackComponent : SharedStackComponent, IItemStatus
|
||||
{
|
||||
[ViewVariables] public int Count { get; private set; }
|
||||
[ViewVariables] public int MaxCount { get; private set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded;
|
||||
|
||||
public Control MakeControl() => new StatusControl(this);
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
var cast = (StackComponentState) curState;
|
||||
|
||||
Count = cast.Count;
|
||||
MaxCount = cast.MaxCount;
|
||||
_uiUpdateNeeded = true;
|
||||
}
|
||||
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private readonly StackComponent _parent;
|
||||
private readonly RichTextLabel _label;
|
||||
|
||||
public StatusControl(StackComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
_label = new RichTextLabel {StyleClasses = {NanoStyle.StyleClassItemStatus}};
|
||||
AddChild(_label);
|
||||
|
||||
parent._uiUpdateNeeded = true;
|
||||
}
|
||||
|
||||
protected override void Update(FrameEventArgs args)
|
||||
{
|
||||
base.Update(args);
|
||||
|
||||
if (!_parent._uiUpdateNeeded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parent._uiUpdateNeeded = false;
|
||||
|
||||
_label.SetMarkup(Loc.GetString("Count: [color=white]{0}[/color]", _parent.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Storage
|
||||
{
|
||||
@@ -30,7 +29,7 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
base.OnAdd();
|
||||
|
||||
Window = new StorageWindow()
|
||||
{ StorageEntity = this};
|
||||
{StorageEntity = this};
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
@@ -39,12 +38,8 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||
IComponent component = null)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
@@ -53,10 +48,10 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
HandleStorageMessage(msg);
|
||||
break;
|
||||
//Opens the UI
|
||||
case OpenStorageUIMessage msg:
|
||||
case OpenStorageUIMessage _:
|
||||
OpenUI();
|
||||
break;
|
||||
case CloseStorageUIMessage msg:
|
||||
case CloseStorageUIMessage _:
|
||||
CloseUI();
|
||||
break;
|
||||
}
|
||||
@@ -106,34 +101,29 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
private Label Information;
|
||||
public ClientStorageComponent StorageEntity;
|
||||
|
||||
protected override Vector2? CustomSize => (180, 320);
|
||||
|
||||
public StorageWindow()
|
||||
{
|
||||
Size = new Vector2(180.0f, 320.0f);
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Title = "Storage Item";
|
||||
RectClipContent = true;
|
||||
|
||||
VSplitContainer = new VBoxContainer("VSplitContainer");
|
||||
Information = new Label("Information")
|
||||
VSplitContainer = new VBoxContainer();
|
||||
Information = new Label
|
||||
{
|
||||
Text = "Items: 0 Volume: 0/0 Stuff",
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||
};
|
||||
VSplitContainer.AddChild(Information);
|
||||
|
||||
var listScrollContainer = new ScrollContainer("ListScrollContainer")
|
||||
var listScrollContainer = new ScrollContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
HScrollEnabled = true,
|
||||
VScrollEnabled = true
|
||||
};
|
||||
EntityList = new VBoxContainer("EntityList")
|
||||
EntityList = new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
};
|
||||
@@ -182,7 +172,8 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
//Sets information about entire storage container current capacity
|
||||
if (StorageEntity.StorageCapacityMax != 0)
|
||||
{
|
||||
Information.Text = String.Format("Items: {0}, Stored: {1}/{2}", storagelist.Count, StorageEntity.StorageSizeUsed, StorageEntity.StorageCapacityMax);
|
||||
Information.Text = String.Format("Items: {0}, Stored: {1}/{2}", storagelist.Count,
|
||||
StorageEntity.StorageSizeUsed, StorageEntity.StorageCapacityMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -196,7 +187,7 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
/// <param name="args"></param>
|
||||
private void OnItemButtonToggled(BaseButton.ButtonToggledEventArgs args)
|
||||
{
|
||||
var control = (EntityButton)args.Button.Parent;
|
||||
var control = (EntityButton) args.Button.Parent;
|
||||
args.Button.Pressed = false;
|
||||
StorageEntity.Interact(control.EntityuID);
|
||||
}
|
||||
@@ -208,17 +199,15 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
private class EntityButton : PanelContainer
|
||||
{
|
||||
public EntityUid EntityuID { get; set; }
|
||||
public Button ActualButton { get; private set; }
|
||||
public SpriteView EntitySpriteView { get; private set; }
|
||||
public Control EntityControl { get; private set; }
|
||||
public Label EntityName { get; private set; }
|
||||
public Label EntitySize { get; private set; }
|
||||
public Button ActualButton { get; }
|
||||
public SpriteView EntitySpriteView { get; }
|
||||
public Control EntityControl { get; }
|
||||
public Label EntityName { get; }
|
||||
public Label EntitySize { get; }
|
||||
|
||||
protected override void Initialize()
|
||||
public EntityButton()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
ActualButton = new Button("Button")
|
||||
ActualButton = new Button
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
@@ -227,12 +216,12 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
};
|
||||
AddChild(ActualButton);
|
||||
|
||||
var hBoxContainer = new HBoxContainer("HBoxContainer") {MouseFilter = MouseFilterMode.Ignore};
|
||||
EntitySpriteView = new SpriteView("SpriteView")
|
||||
var hBoxContainer = new HBoxContainer {MouseFilter = MouseFilterMode.Ignore};
|
||||
EntitySpriteView = new SpriteView
|
||||
{
|
||||
CustomMinimumSize = new Vector2(32.0f, 32.0f), MouseFilter = MouseFilterMode.Ignore
|
||||
};
|
||||
EntityName = new Label("Name")
|
||||
EntityName = new Label
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
Text = "Backpack",
|
||||
@@ -241,23 +230,23 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
hBoxContainer.AddChild(EntitySpriteView);
|
||||
hBoxContainer.AddChild(EntityName);
|
||||
|
||||
EntityControl = new Control("Control")
|
||||
EntityControl = new Control
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand, MouseFilter = MouseFilterMode.Ignore
|
||||
};
|
||||
EntitySize = new Label("Size")
|
||||
EntitySize = new Label
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
Text = "Size 6",
|
||||
Align = Label.AlignMode.Right,
|
||||
AnchorLeft = 1.0f,
|
||||
/*AnchorLeft = 1.0f,
|
||||
AnchorRight = 1.0f,
|
||||
AnchorBottom = 0.5f,
|
||||
AnchorTop = 0.5f,
|
||||
MarginLeft = -38.0f,
|
||||
MarginTop = -7.0f,
|
||||
MarginRight = -5.0f,
|
||||
MarginBottom = 7.0f
|
||||
MarginBottom = 7.0f*/
|
||||
};
|
||||
|
||||
EntityControl.AddChild(EntitySize);
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple component that automatically hides the sibling <see cref="ISpriteComponent"/> when the tile it's on
|
||||
/// is not a sub floor (plating).
|
||||
/// Simple component that automatically hides the sibling
|
||||
/// <see cref="ISpriteComponent" /> when the tile it's on is not a sub floor
|
||||
/// (plating).
|
||||
/// </summary>
|
||||
/// <seealso cref="ContentTileDefinition.IsSubFloor"/>
|
||||
/// <seealso cref="P:Content.Shared.Maps.ContentTileDefinition.IsSubFloor" />
|
||||
[RegisterComponent]
|
||||
public sealed class SubFloorHideComponent : Component
|
||||
{
|
||||
private SnapGridComponent _snapGridComponent;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "SubFloorHide";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -24,28 +26,32 @@ namespace Content.Client.GameObjects.Components
|
||||
_snapGridComponent = Owner.GetComponent<SnapGridComponent>();
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
/// <inheritdoc />
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
_snapGridComponent.OnPositionChanged += SnapGridOnPositionChanged;
|
||||
Owner.EntityManager.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
/// <inheritdoc />
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
if(Owner.Transform.Running == false)
|
||||
return;
|
||||
|
||||
_snapGridComponent.OnPositionChanged -= SnapGridOnPositionChanged;
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
|
||||
}
|
||||
|
||||
private void SnapGridOnPositionChanged()
|
||||
{
|
||||
Owner.EntityManager.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SubFloorHideDirtyEvent : EntitySystemMessage
|
||||
{
|
||||
}
|
||||
internal sealed class SubFloorHideDirtyEvent : EntitySystemMessage { }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using Content.Client.VendingMachines;
|
||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.VendingMachines
|
||||
{
|
||||
class VendingMachineBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private VendingMachineMenu _menu;
|
||||
|
||||
public SharedVendingMachineComponent VendingMachine { get; private set; }
|
||||
|
||||
public VendingMachineBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
SendMessage(new SharedVendingMachineComponent.InventorySyncRequestMessage());
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
if(!Owner.Owner.TryGetComponent(out SharedVendingMachineComponent vendingMachine))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VendingMachine = vendingMachine;
|
||||
|
||||
_menu = new VendingMachineMenu() { Owner = this, Title = Owner.Owner.Name };
|
||||
_menu.Populate(VendingMachine.Inventory);
|
||||
|
||||
_menu.OnClose += Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
public void Eject(string ID)
|
||||
{
|
||||
SendMessage(new SharedVendingMachineComponent.VendingMachineEjectMessage(ID));
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
switch(message)
|
||||
{
|
||||
case SharedVendingMachineComponent.VendingMachineInventoryMessage msg:
|
||||
_menu.Populate(msg.Inventory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if(!disposing) { return; }
|
||||
_menu?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using static Content.Shared.GameObjects.Components.VendingMachines.SharedVendingMachineComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.VendingMachines
|
||||
{
|
||||
public class VendingMachineVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
// TODO: The length of these animations is supposed to be dictated
|
||||
// by the vending machine's pack prototype's `AnimationDuration`
|
||||
// but we have no good way of passing that data from the server
|
||||
// to the client at the moment. Rework Visualizers?
|
||||
private const string DeniedAnimationKey = "deny";
|
||||
private const string EjectAnimationKey = "eject";
|
||||
|
||||
private Animation _deniedAnimation;
|
||||
private Animation _ejectAnimation;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
_deniedAnimation = new Animation {Length = TimeSpan.FromSeconds(1.2f)};
|
||||
{
|
||||
var flick = new AnimationTrackSpriteFlick();
|
||||
_deniedAnimation.AnimationTracks.Add(flick);
|
||||
flick.LayerKey = VendingMachineVisualLayers.Base;
|
||||
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("deny", 0f));
|
||||
}
|
||||
|
||||
_ejectAnimation = new Animation {Length = TimeSpan.FromSeconds(1.2f)};
|
||||
{
|
||||
var flick = new AnimationTrackSpriteFlick();
|
||||
_ejectAnimation.AnimationTracks.Add(flick);
|
||||
flick.LayerKey = VendingMachineVisualLayers.Base;
|
||||
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("eject", 0f));
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
if (!entity.HasComponent<AnimationPlayerComponent>())
|
||||
{
|
||||
entity.AddComponent<AnimationPlayerComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
var animPlayer = component.Owner.GetComponent<AnimationPlayerComponent>();
|
||||
if (!component.TryGetData(VendingMachineVisuals.VisualState, out VendingMachineVisualState state))
|
||||
{
|
||||
state = VendingMachineVisualState.Normal;
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case VendingMachineVisualState.Normal:
|
||||
sprite.LayerSetState(VendingMachineVisualLayers.Base, "normal");
|
||||
break;
|
||||
case VendingMachineVisualState.Off:
|
||||
sprite.LayerSetState(VendingMachineVisualLayers.Base, "off");
|
||||
break;
|
||||
case VendingMachineVisualState.Broken:
|
||||
sprite.LayerSetState(VendingMachineVisualLayers.Base, "broken");
|
||||
break;
|
||||
case VendingMachineVisualState.Deny:
|
||||
if (!animPlayer.HasRunningAnimation(DeniedAnimationKey))
|
||||
{
|
||||
animPlayer.Play(_deniedAnimation, DeniedAnimationKey);
|
||||
}
|
||||
|
||||
break;
|
||||
case VendingMachineVisualState.Eject:
|
||||
if (!animPlayer.HasRunningAnimation(EjectAnimationKey))
|
||||
{
|
||||
animPlayer.Play(_ejectAnimation, EjectAnimationKey);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public enum VendingMachineVisualLayers
|
||||
{
|
||||
Base,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using Content.Shared.GameObjects.Components.Weapons.Melee;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Melee
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class MeleeWeaponArcAnimationComponent : Component
|
||||
{
|
||||
public override string Name => "MeleeWeaponArcAnimation";
|
||||
|
||||
private MeleeWeaponAnimationPrototype _meleeWeaponAnimation;
|
||||
|
||||
private float _timer;
|
||||
private SpriteComponent _sprite;
|
||||
private Angle _baseAngle;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_sprite = Owner.GetComponent<SpriteComponent>();
|
||||
}
|
||||
|
||||
public void SetData(MeleeWeaponAnimationPrototype prototype, Angle baseAngle)
|
||||
{
|
||||
_meleeWeaponAnimation = prototype;
|
||||
_sprite.AddLayer(new RSI.StateId(prototype.State));
|
||||
_baseAngle = baseAngle;
|
||||
}
|
||||
|
||||
internal void Update(float frameTime)
|
||||
{
|
||||
if (_meleeWeaponAnimation == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_timer += frameTime;
|
||||
|
||||
var (r, g, b, a) =
|
||||
Vector4.Clamp(_meleeWeaponAnimation.Color + _meleeWeaponAnimation.ColorDelta * _timer, Vector4.Zero, Vector4.One);
|
||||
_sprite.Color = new Color(r, g, b, a);
|
||||
|
||||
switch (_meleeWeaponAnimation.ArcType)
|
||||
{
|
||||
case WeaponArcType.Slash:
|
||||
var angle = Angle.FromDegrees(_meleeWeaponAnimation.Width)/2;
|
||||
Owner.Transform.LocalRotation =
|
||||
_baseAngle + Angle.Lerp(-angle, angle, (float) (_timer / _meleeWeaponAnimation.Length.TotalSeconds));
|
||||
break;
|
||||
|
||||
case WeaponArcType.Poke:
|
||||
_sprite.Offset += (_meleeWeaponAnimation.Speed * frameTime, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (_meleeWeaponAnimation.Length.TotalSeconds <= _timer)
|
||||
{
|
||||
Owner.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
using System;
|
||||
using Content.Client.Animations;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Client.StaticIoC;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class BallisticMagazineWeaponComponent : Component, IItemStatus
|
||||
{
|
||||
private static readonly Animation AlarmAnimationSmg = new Animation
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(1.4),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackControlProperty
|
||||
{
|
||||
// These timings match the SMG audio file.
|
||||
Property = nameof(Label.FontColorOverride),
|
||||
InterpolationMode = AnimationInterpolationMode.Previous,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Color.Red, 0.1f),
|
||||
new AnimationTrackProperty.KeyFrame(null, 0.3f),
|
||||
new AnimationTrackProperty.KeyFrame(Color.Red, 0.2f),
|
||||
new AnimationTrackProperty.KeyFrame(null, 0.3f),
|
||||
new AnimationTrackProperty.KeyFrame(Color.Red, 0.2f),
|
||||
new AnimationTrackProperty.KeyFrame(null, 0.3f),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly Animation AlarmAnimationLmg = new Animation
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(0.75),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackControlProperty
|
||||
{
|
||||
// These timings match the SMG audio file.
|
||||
Property = nameof(Label.FontColorOverride),
|
||||
InterpolationMode = AnimationInterpolationMode.Previous,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Color.Red, 0.0f),
|
||||
new AnimationTrackProperty.KeyFrame(null, 0.15f),
|
||||
new AnimationTrackProperty.KeyFrame(Color.Red, 0.15f),
|
||||
new AnimationTrackProperty.KeyFrame(null, 0.15f),
|
||||
new AnimationTrackProperty.KeyFrame(Color.Red, 0.15f),
|
||||
new AnimationTrackProperty.KeyFrame(null, 0.15f),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public override string Name => "BallisticMagazineWeapon";
|
||||
public override uint? NetID => ContentNetIDs.BALLISTIC_MAGAZINE_WEAPON;
|
||||
|
||||
private StatusControl _statusControl;
|
||||
|
||||
/// <summary>
|
||||
/// True if a bullet is chambered.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Chambered { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Count of bullets in the magazine.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if no magazine is inserted.
|
||||
/// </remarks>
|
||||
[ViewVariables]
|
||||
public (int count, int max)? MagazineCount { get; private set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] private bool _isLmgAlarmAnimation;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _isLmgAlarmAnimation, "lmg_alarm_animation", false);
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
var cast = (BallisticMagazineWeaponComponentState) curState;
|
||||
|
||||
Chambered = cast.Chambered;
|
||||
MagazineCount = cast.MagazineCount;
|
||||
_statusControl?.Update();
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||
IComponent component = null)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case BmwComponentAutoEjectedMessage _:
|
||||
_statusControl?.PlayAlarmAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
}
|
||||
|
||||
public Control MakeControl()
|
||||
{
|
||||
_statusControl = new StatusControl(this);
|
||||
_statusControl.Update();
|
||||
return _statusControl;
|
||||
}
|
||||
|
||||
public void DestroyControl(Control control)
|
||||
{
|
||||
if (_statusControl == control)
|
||||
{
|
||||
_statusControl = null;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private readonly BallisticMagazineWeaponComponent _parent;
|
||||
private readonly HBoxContainer _bulletsListTop;
|
||||
private readonly HBoxContainer _bulletsListBottom;
|
||||
private readonly TextureRect _chamberedBullet;
|
||||
private readonly Label _noMagazineLabel;
|
||||
|
||||
public StatusControl(BallisticMagazineWeaponComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand;
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter;
|
||||
AddChild(new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListTop = new HBoxContainer {SeparationOverride = 0}),
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Control
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListBottom = new HBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0
|
||||
}),
|
||||
(_noMagazineLabel = new Label
|
||||
{
|
||||
Text = "No Magazine!",
|
||||
StyleClasses = {NanoStyle.StyleClassItemStatus}
|
||||
})
|
||||
}
|
||||
},
|
||||
(_chamberedBullet = new TextureRect
|
||||
{
|
||||
Texture = ResC.GetTexture("/Textures/UserInterface/status/bullets/chambered.png"),
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Fill,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_chamberedBullet.ModulateSelfOverride =
|
||||
_parent.Chambered ? Color.FromHex("#d7df60") : Color.Black;
|
||||
|
||||
_bulletsListTop.RemoveAllChildren();
|
||||
_bulletsListBottom.RemoveAllChildren();
|
||||
|
||||
if (_parent.MagazineCount == null)
|
||||
{
|
||||
_noMagazineLabel.Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var (count, capacity) = _parent.MagazineCount.Value;
|
||||
|
||||
_noMagazineLabel.Visible = false;
|
||||
|
||||
string texturePath;
|
||||
if (capacity <= 20)
|
||||
{
|
||||
texturePath = "/Textures/UserInterface/status/bullets/normal.png";
|
||||
}
|
||||
else if (capacity <= 30)
|
||||
{
|
||||
texturePath = "/Textures/UserInterface/status/bullets/small.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
texturePath = "/Textures/UserInterface/status/bullets/tiny.png";
|
||||
}
|
||||
|
||||
var texture = ResC.GetTexture(texturePath);
|
||||
|
||||
const int tinyMaxRow = 60;
|
||||
|
||||
if (capacity > tinyMaxRow)
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, Math.Min(tinyMaxRow, count), tinyMaxRow, texture);
|
||||
FillBulletRow(_bulletsListTop, Math.Max(0, count - tinyMaxRow), capacity - tinyMaxRow, texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, count, capacity, texture);
|
||||
}
|
||||
}
|
||||
|
||||
private static void FillBulletRow(Control container, int count, int capacity, Texture texture)
|
||||
{
|
||||
var colorA = Color.FromHex("#b68f0e");
|
||||
var colorB = Color.FromHex("#d7df60");
|
||||
var colorGoneA = Color.FromHex("#000000");
|
||||
var colorGoneB = Color.FromHex("#222222");
|
||||
|
||||
var altColor = false;
|
||||
|
||||
for (var i = count; i < capacity; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorGoneA : colorGoneB
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorA : colorB
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return Vector2.ComponentMax((0, 15), base.CalculateMinimumSize());
|
||||
}
|
||||
|
||||
public void PlayAlarmAnimation()
|
||||
{
|
||||
var animation = _parent._isLmgAlarmAnimation ? AlarmAnimationLmg : AlarmAnimationSmg;
|
||||
_noMagazineLabel.PlayAnimation(animation, "alarm");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,8 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
return;
|
||||
}
|
||||
|
||||
var step = ContentHelpers.RoundToLevels(current, capacity, _steps);
|
||||
|
||||
// capacity is - 1 as normally a bullet is chambered so max state is virtually never hit.
|
||||
var step = ContentHelpers.RoundToLevels(current, capacity - 1, _steps);
|
||||
sprite.LayerSetState(0, $"{_baseState}-{step}");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
@@ -10,20 +7,9 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
[RegisterComponent]
|
||||
public sealed class ClientRangedWeaponComponent : SharedRangedWeaponComponent
|
||||
{
|
||||
private TimeSpan _lastFireTime;
|
||||
private int _tick;
|
||||
|
||||
public void TryFire(GridCoordinates worldPos)
|
||||
public void SyncFirePos(GridCoordinates worldPos)
|
||||
{
|
||||
var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
|
||||
var span = curTime - _lastFireTime;
|
||||
if (span.TotalSeconds < 1 / FireRate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastFireTime = curTime;
|
||||
SendNetworkMessage(new FireMessage(worldPos, _tick++));
|
||||
SendNetworkMessage(new SyncFirePosMessage(worldPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Content.Shared.Utility;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
|
||||
73
Content.Client/GameObjects/Components/WelderComponent.cs
Normal file
73
Content.Client/GameObjects/Components/WelderComponent.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class WelderComponent : Component, IItemStatus
|
||||
{
|
||||
public override string Name => "Welder";
|
||||
public override uint? NetID => ContentNetIDs.WELDER;
|
||||
|
||||
[ViewVariables] public float FuelCapacity { get; private set; }
|
||||
[ViewVariables] public float Fuel { get; private set; }
|
||||
[ViewVariables] public bool Activated { get; private set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded;
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
var cast = (WelderComponentState) curState;
|
||||
|
||||
FuelCapacity = cast.FuelCapacity;
|
||||
Fuel = cast.Fuel;
|
||||
Activated = cast.Activated;
|
||||
|
||||
_uiUpdateNeeded = true;
|
||||
}
|
||||
|
||||
public Control MakeControl() => new StatusControl(this);
|
||||
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private readonly WelderComponent _parent;
|
||||
private readonly RichTextLabel _label;
|
||||
|
||||
public StatusControl(WelderComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
_label = new RichTextLabel {StyleClasses = {NanoStyle.StyleClassItemStatus}};
|
||||
AddChild(_label);
|
||||
|
||||
parent._uiUpdateNeeded = true;
|
||||
}
|
||||
|
||||
protected override void Update(FrameEventArgs args)
|
||||
{
|
||||
base.Update(args);
|
||||
|
||||
if (!_parent._uiUpdateNeeded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parent._uiUpdateNeeded = false;
|
||||
|
||||
var fuelCap = _parent.FuelCapacity;
|
||||
var fuel = _parent.Fuel;
|
||||
|
||||
_label.SetMarkup(Loc.GetString("Fuel: [color={0}]{1}/{2}[/color]",
|
||||
fuel < fuelCap / 4f ? "darkorange" : "orange", Math.Round(fuel), fuelCap));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -25,12 +25,13 @@ namespace Content.Client.GameObjects.Components
|
||||
_snapGrid = Owner.GetComponent<SnapGridComponent>();
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
/// <inheritdoc />
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
_snapGrid.OnPositionChanged += SnapGridOnPositionChanged;
|
||||
Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
|
||||
|
||||
var state0 = $"{_stateBase}0";
|
||||
_sprite.LayerMapSet(CornerLayers.SE, _sprite.AddLayerState(state0));
|
||||
@@ -43,7 +44,8 @@ namespace Content.Client.GameObjects.Components
|
||||
_sprite.LayerSetDirOffset(CornerLayers.SW, SpriteComponent.DirectionOffset.Clockwise);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
/// <inheritdoc />
|
||||
protected override void Shutdown()
|
||||
{
|
||||
_snapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
|
||||
|
||||
@@ -52,7 +54,7 @@ namespace Content.Client.GameObjects.Components
|
||||
|
||||
private void SnapGridOnPositionChanged()
|
||||
{
|
||||
Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
|
||||
Owner.EntityManager.EventBus.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
|
||||
}
|
||||
|
||||
public void UpdateSprite()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Wires
|
||||
{
|
||||
public class WiresBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
public WiresBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
private WiresMenu _menu;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_menu = new WiresMenu(_localizationManager) {Owner = this};
|
||||
|
||||
_menu.OnClose += Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
_menu.Populate((WiresBoundUserInterfaceState) state);
|
||||
}
|
||||
|
||||
public void PerformAction(Guid guid, WiresAction action)
|
||||
{
|
||||
SendMessage(new WiresActionMessage(guid, action));
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Content.Client/GameObjects/Components/Wires/WiresMenu.cs
Normal file
66
Content.Client/GameObjects/Components/Wires/WiresMenu.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Wires
|
||||
{
|
||||
public class WiresMenu : SS14Window
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
protected override Vector2? CustomSize => (300, 150);
|
||||
public WiresBoundUserInterface Owner { get; set; }
|
||||
|
||||
private readonly VBoxContainer _wiresContainer;
|
||||
|
||||
public WiresMenu(ILocalizationManager localizationManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
Title = _localizationManager.GetString("Wires");
|
||||
_wiresContainer = new VBoxContainer();
|
||||
Contents.AddChild(_wiresContainer);
|
||||
}
|
||||
|
||||
public void Populate(WiresBoundUserInterfaceState state)
|
||||
{
|
||||
_wiresContainer.RemoveAllChildren();
|
||||
foreach (var wire in state.WiresList)
|
||||
{
|
||||
var container = new HBoxContainer();
|
||||
var newLabel = new Label()
|
||||
{
|
||||
Text = $"{_localizationManager.GetString(wire.Color.Name())}: ",
|
||||
FontColorOverride = wire.Color,
|
||||
};
|
||||
container.AddChild(newLabel);
|
||||
|
||||
var newButton = new Button()
|
||||
{
|
||||
Text = _localizationManager.GetString("Pulse"),
|
||||
};
|
||||
newButton.OnPressed += _ => Owner.PerformAction(wire.Guid, WiresAction.Pulse);
|
||||
container.AddChild(newButton);
|
||||
|
||||
newButton = new Button()
|
||||
{
|
||||
Text = wire.IsCut ? _localizationManager.GetString("Mend") : _localizationManager.GetString("Cut"),
|
||||
};
|
||||
newButton.OnPressed += _ => Owner.PerformAction(wire.Guid, wire.IsCut ? WiresAction.Mend : WiresAction.Cut);
|
||||
container.AddChild(newButton);
|
||||
_wiresContainer.AddChild(container);
|
||||
}
|
||||
|
||||
foreach (var status in state.Statuses)
|
||||
{
|
||||
var container = new HBoxContainer();
|
||||
container.AddChild(new Label
|
||||
{
|
||||
Text = status
|
||||
});
|
||||
_wiresContainer.AddChild(container);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Wires
|
||||
{
|
||||
public class WiresVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
if (component.TryGetData<bool>(WiresVisuals.MaintenancePanelState, out var state))
|
||||
{
|
||||
sprite.LayerSetVisible(WiresVisualLayers.MaintenancePanel, state);
|
||||
}
|
||||
}
|
||||
|
||||
public enum WiresVisualLayers
|
||||
{
|
||||
MaintenancePanel,
|
||||
}
|
||||
}
|
||||
}
|
||||
177
Content.Client/GameObjects/EntitySystems/CombatModeSystem.cs
Normal file
177
Content.Client/GameObjects/EntitySystems/CombatModeSystem.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using Content.Client.GameObjects.Components.Mobs;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystemMessages;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using static Content.Client.StaticIoC;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
public sealed class CombatModeSystem : EntitySystem
|
||||
{
|
||||
private const float AttackTimeThreshold = 0.15f;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IGameHud _gameHud;
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IInputManager _inputManager;
|
||||
[Dependency] private readonly IOverlayManager _overlayManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private InputSystem _inputSystem;
|
||||
|
||||
public bool UseOrAttackIsDown { get; private set; }
|
||||
private float _timeHeld;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_gameHud.OnCombatModeChanged = OnCombatModeChanged;
|
||||
_gameHud.OnTargetingZoneChanged = OnTargetingZoneChanged;
|
||||
|
||||
_inputSystem = EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||
_inputSystem.BindMap.BindFunction(ContentKeyFunctions.UseOrAttack, new InputHandler(this));
|
||||
|
||||
_overlayManager.AddOverlay(new CombatModeOverlay(this));
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_overlayManager.RemoveOverlay(nameof(CombatModeOverlay));
|
||||
}
|
||||
|
||||
private bool IsInCombatMode()
|
||||
{
|
||||
var entity = _playerManager.LocalPlayer.ControlledEntity;
|
||||
if (entity == null || !entity.TryGetComponent(out CombatModeComponent combatMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return combatMode.IsInCombatMode;
|
||||
}
|
||||
|
||||
private void OnTargetingZoneChanged(TargetingZone obj)
|
||||
{
|
||||
RaiseNetworkEvent(new CombatModeSystemMessages.SetTargetZoneMessage(obj));
|
||||
}
|
||||
|
||||
private void OnCombatModeChanged(bool obj)
|
||||
{
|
||||
RaiseNetworkEvent(new CombatModeSystemMessages.SetCombatModeActiveMessage(obj));
|
||||
|
||||
// Just in case.
|
||||
UseOrAttackIsDown = false;
|
||||
}
|
||||
|
||||
private bool HandleInputMessage(ICommonSession session, InputCmdMessage message)
|
||||
{
|
||||
if (!(message is FullInputCmdMessage msg))
|
||||
return false;
|
||||
|
||||
void SendMsg(BoundKeyFunction function, BoundKeyState state)
|
||||
{
|
||||
var functionId = _inputManager.NetworkBindMap.KeyFunctionID(function);
|
||||
|
||||
var sendMsg = new FullInputCmdMessage(msg.Tick, functionId, state,
|
||||
msg.Coordinates, msg.ScreenCoordinates, msg.Uid);
|
||||
_inputSystem.HandleInputCommand(session, function, sendMsg);
|
||||
}
|
||||
|
||||
// If we are not in combat mode, relay it as a regular Use instead.
|
||||
if (!IsInCombatMode())
|
||||
{
|
||||
SendMsg(EngineKeyFunctions.Use, msg.State);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.State == BoundKeyState.Down)
|
||||
{
|
||||
UseOrAttackIsDown = true;
|
||||
_timeHeld = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Up.
|
||||
if (UseOrAttackIsDown && _timeHeld >= AttackTimeThreshold)
|
||||
{
|
||||
// Attack.
|
||||
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Down);
|
||||
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Up);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use.
|
||||
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Down);
|
||||
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Up);
|
||||
}
|
||||
|
||||
UseOrAttackIsDown = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
if (UseOrAttackIsDown)
|
||||
{
|
||||
_timeHeld += frameTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom input handler type so we get the ENTIRE InputCmdMessage.
|
||||
private sealed class InputHandler : InputCmdHandler
|
||||
{
|
||||
private readonly CombatModeSystem _combatModeSystem;
|
||||
|
||||
public InputHandler(CombatModeSystem combatModeSystem)
|
||||
{
|
||||
_combatModeSystem = combatModeSystem;
|
||||
}
|
||||
|
||||
public override bool HandleCmdMessage(ICommonSession session, InputCmdMessage message)
|
||||
{
|
||||
return _combatModeSystem.HandleInputMessage(session, message);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CombatModeOverlay : Overlay
|
||||
{
|
||||
private readonly CombatModeSystem _system;
|
||||
|
||||
public CombatModeOverlay(CombatModeSystem system) : base(nameof(CombatModeOverlay))
|
||||
{
|
||||
_system = system;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleBase handle)
|
||||
{
|
||||
var screenHandle = (DrawingHandleScreen) handle;
|
||||
|
||||
var mousePos = IoCManager.Resolve<IInputManager>().MouseScreenPosition;
|
||||
|
||||
if (_system.UseOrAttackIsDown && _system._timeHeld > AttackTimeThreshold)
|
||||
{
|
||||
var tex = ResC.GetTexture($"/Textures/Objects/Tools/toolbox_r.png");
|
||||
|
||||
screenHandle.DrawTextureRect(tex, UIBox2.FromDimensions(mousePos, tex.Size * 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user