396 Commits

Author SHA1 Message Date
Morbo
d36345cf53 Update locale 2023-04-02 08:47:44 +03:00
Morbo
959e695315 Merge remote-tracking branch 'upstream/april-fools-release' into april-fools 2023-04-02 08:40:12 +03:00
GoodWheatley
4434b3752c Chat Filter (April Fools) (#14999) 2023-04-01 14:47:21 -07:00
DrSmugleaf
8ca2182a7c Hotfix the scalpel from the underground 2023-04-01 14:43:23 -07:00
DrSmugleaf
bd954ca01a Add changelog for surgery 2023-04-01 13:18:15 -07:00
DrSmugleaf
10ecfd4df1 Surgery (#3939) 2023-04-01 13:11:53 -07:00
metalgearsloth
bba7e96927 Update submodule to 0.96.0.4 (#15039) 2023-04-01 20:53:42 +11:00
Morbo
fdc79e4d2a Trait adaptation 2023-04-01 10:02:21 +03:00
Morbo
cce22a32f3 Poor translation 2023-04-01 10:02:13 +03:00
Morbo
0dc500bbff Update locale 2023-04-01 09:23:50 +03:00
Morbo
5e6581ce6a Merge remote-tracking branch 'upstream/april-fools-release' into april-fools
# Conflicts:
#	Resources/Server Info/Guidebook/Science/Xenoarchaeology.xml
#	Resources/Textures/Clothing/Back/Duffels/chemistry.rsi/icon.png
#	Resources/Textures/Objects/Storage/boxes.rsi/box_security.png
#	Resources/Textures/Objects/Storage/boxes.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_1.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_1.rsi/singularity_1.png
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_2.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_2.rsi/singularity_2.png
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_3.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_3.rsi/singularity_3.png
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_4.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_4.rsi/singularity_4.png
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_5.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_5.rsi/singularity_5.png
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_6.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_6.rsi/singularity_6.png
2023-04-01 09:22:31 +03:00
Moony
2c2f2e0045 Moony z level hack (#15033)
* save work

* Adds Z levels

* a

* ladders + parallax scroll

* zoom out not in

* oops, sandbox

* oops i broke the law

* run ci

* fuck

---------

Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
2023-03-31 21:51:06 -05:00
Moony
a9f7ea5185 Adds Z Levels to the game (#15009)
* save work

* Adds Z levels

* a

* ladders + parallax scroll

* zoom out not in

* oops, sandbox

* oops i broke the law

* run ci

---------

Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
2023-03-31 14:41:38 -05:00
csqrb
c7df69d853 The Pizza Lord! [April Fools] (#15012)
* pizza stuff

* goodies

* singularity does not exist
2023-03-31 14:18:29 -05:00
Moony
b1c6fce89c Merge branch 'master' into april-fools-release 2023-03-31 14:07:42 -05:00
IanComradeBot
b02459b4c3 Automatic changelog update 2023-03-31 15:38:28 +00:00
Puro
69a3be39d7 [TTS] Personal AI (#935) 2023-03-31 08:37:23 -07:00
IanComradeBot
f16a460ffd Automatic changelog update 2023-03-31 14:51:52 +00:00
Puro
637fe64785 [TTS] Revenant (#938) 2023-03-31 07:50:47 -07:00
IanComradeBot
ab2ab80eb7 Automatic changelog update 2023-03-31 14:33:25 +00:00
OhMy
b73cf08e17 Handle uppercase for chat replacement (#932) 2023-03-31 07:32:20 -07:00
IanComradeBot
9b86c75fcb Automatic changelog update 2023-03-31 13:11:09 +00:00
lapatison
5d4e0f272f Translation edits (#939) 2023-03-31 06:10:04 -07:00
PJBot
60839d7917 Automatic changelog update 2023-03-31 02:29:12 -04:00
metalgearsloth
acde17d87b Update submodule to 0.96.0.3 (#15008) 2023-03-31 17:28:08 +11:00
metalgearsloth
b6a735774b Add more dungeon layouts (#14924) 2023-03-30 22:54:17 -07:00
PJBot
732cb8b0d6 Automatic changelog update 2023-03-31 01:54:11 -04:00
MilenVolf
404bbbf309 Wall Weapon Capacitor Recharger Fix (#14982) 2023-03-30 22:53:07 -07:00
TemporalOroboros
76212b877e Resolves GravityGeneratorVisualizer is Obsolete (#13885) 2023-03-31 16:04:53 +11:00
PJBot
ad02129045 Automatic changelog update 2023-03-31 00:50:29 -04:00
faint
8b6996cbae DNA basics (#14724)
* DNA component

* Commit numba 2

* Added DNA into Station Records Computer

* commit numba 3

* commit numba 4

* Vomit also contain DNA component now

* fixed DNA field not clearing after scanning another item

* commit numba 10
Drinking leaves DNA on an object. Breaking glasses, bottles and beakers leave DNA and leave fingerprints/fibers with 40% chance on glass shards. + lotta fixes

* 11

* 12

* 14

* Added DNA guide entry

* FIX
2023-03-30 22:49:25 -06:00
PJBot
dfcb7b3c97 Automatic changelog update 2023-03-31 00:47:10 -04:00
potato1234_x
6bfd1d8f11 Missing box icons (#14891)
* boxes

* holo box
2023-03-30 22:46:06 -06:00
metalgearsloth
40deda74ab Fix docking config in some instances (#15005) 2023-03-31 15:45:14 +11:00
metalgearsloth
ce34252cd3 Revert "fuckyou (#14960)" (#15006)
* Revert "fuckyou (#14960)"

This reverts commit e29c54d64e.

* Use volume for it
2023-03-30 22:44:39 -06:00
PJBot
a9aa5011c1 Automatic changelog update 2023-03-31 00:34:25 -04:00
PJBot
25e7acaa9b Automatic changelog update 2023-03-31 00:33:23 -04:00
potato1234_x
9ab3523871 butcherable bandanas and caps (#14893) 2023-03-30 22:33:20 -06:00
brainfood1183
ad31749b55 Desk Bell fix, Poster Rise fix, Happyhonk Mime inhand fix. (#14973)
* deskbell, poster rise fix, happyhonk mime inhand fix.

* cancollide: false
2023-03-30 22:32:57 -06:00
Alekshhh
e29c54d64e fuckyou (#14960) 2023-03-30 22:32:19 -06:00
potato1234_x
dbf9f71ee8 vend tweaks and clothes (#14961) 2023-03-30 22:31:51 -06:00
PJBot
be2d3c4277 Automatic changelog update 2023-03-31 00:31:10 -04:00
Puro
a487ed9df7 [Spawn] Plush Dion now spawns (#14986)
* [Spawn] Diona Plush now spawns

shkibididopdop

* compiled code fun.yml

removed "amount: 1", since it initially appears in the amount of 1 piece.
2023-03-30 22:30:06 -06:00
PJBot
a5b06cb96f Automatic changelog update 2023-03-31 00:26:50 -04:00
T-Stalker
3b9fd4867e Re-adds skub noise [Not april fools] (#14978) 2023-03-31 15:25:46 +11:00
PJBot
00035721e4 Automatic changelog update 2023-03-31 00:22:58 -04:00
Lei Yunxing
cf61150ebd Adds advanced mop and research (#14917)
* add advanced mop

* make advmop clean faster

* works now

* tweak stats

* tweak speed again

* typo!!!

* copyright change for nerds
2023-03-30 22:21:54 -06:00
PJBot
3b46e649ee Automatic changelog update 2023-03-31 00:21:46 -04:00
metalgearsloth
cefc37903e Random emergency shuttle time (#10047)
* Random emergency shuttle time

60 to 180 seconds. Rounds up to nearest 10.
All other FTL will go to the default of 30s.

* fix
2023-03-30 22:20:43 -06:00
Moony
f8a8e7bafc Set lizard's popcap for the day. 2023-03-30 23:00:00 -05:00
Leon Friedrich
59eb53d4f7 Fix resource &prototype upload recording (#15003) 2023-03-30 22:55:06 -05:00
PJBot
18581a01ca Automatic changelog update 2023-03-30 23:41:42 -04:00
metalgearsloth
763089570d Make trays clientside (#14826) 2023-03-31 14:40:38 +11:00
Interrobang01
50fe4337da Added Rights [April Fools] (#15002)
* everyone gets a mk58

* added mk58 ammo to sec dispenser
2023-03-30 22:34:03 -05:00
Nemanja
3c6e67adee addcurrency command (#15000) 2023-03-30 23:02:39 -04:00
Scribbles0
ce1d616f87 pop change (#14998) 2023-03-30 20:51:47 -05:00
Flareguy
b2299a2e5b They have absolutely fucking had it (#14980) 2023-03-30 19:16:16 -05:00
Skye
c9be773c85 Oops, All Captains! (#14995) 2023-03-30 19:02:30 -05:00
Tyzemol
a6aaa6464b Cowtools worldwide (#14981)
* the funny

* cow toolbox has normal tools

---------

Co-authored-by: BuildTools <unconfigured@null.spigotmc.org>
2023-03-30 18:56:22 -05:00
Ablankmann
d6b8e5e243 Nefarious WizOps [April Fools] (#14991)
* fix a typo in xenoarch guide (#14984)

* Wardrobe restock box hotfix (Removes CentCom gear) (#14985)

* initial code

* GOODBYE CENTCOM GEARgit add -A!

* Automatic changelog update

* Magic Ends

* final tweaks

---------

Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com>
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
2023-03-30 18:55:59 -05:00
PJBot
7e53ef32e2 Automatic changelog update 2023-03-30 19:55:43 -04:00
Moony
5cc78c2c75 Revert "Oops, All Captains! (#14943)" (#14994)
This reverts commit 8128759ea8.
2023-03-30 18:55:09 -05:00
Skye
8128759ea8 Oops, All Captains! (#14943) 2023-03-30 18:54:38 -05:00
deltanedas
3f3c163591 honk! (#14958)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-30 18:54:31 -05:00
Nemanja
6878b89a1c Truly Good and Honest Pure of Heart Christian Boy trait (#14972) 2023-03-30 18:54:22 -05:00
Scribbles0
84f24d57ef inflatable walls for EVERYONE (#14974) 2023-03-30 18:54:14 -05:00
Skye
ef9934c61d April Fool's Day: Microwave Haywire Mode (#14975)
* Microwave Haywire Mode

* Fixed microwave board not being ejected
2023-03-30 18:53:56 -05:00
Flipp Syder
7ea9588172 Foxes (#14976)
* foxes

* oops

* oop

* oop

* license/copyright on fox markings
2023-03-30 18:53:50 -05:00
Nemanja
f2b6dcf329 Reenable skeletons [April Fools] (#14977) 2023-03-30 18:53:36 -05:00
Leon Friedrich
ceba6f1585 Improve random tip UI (#14979) 2023-03-30 18:53:13 -05:00
Emisse
b71c8b7ec3 mild bagel updatey (#14993) 2023-03-30 16:49:03 -06:00
PJBot
eeb8d0f630 Automatic changelog update 2023-03-30 12:16:14 -04:00
Whisper
979bdfcfa6 Wardrobe restock box hotfix (Removes CentCom gear) (#14985)
* initial code

* GOODBYE CENTCOM GEARgit add -A!
2023-03-30 11:15:10 -05:00
lapatison
53bc25519c Translate Upstream #936 (#937) 2023-03-30 09:11:30 -07:00
deltanedas
311a027797 fix a typo in xenoarch guide (#14984) 2023-03-30 22:59:32 +11:00
Morbo
7d53df5cfa Add support multi changelogs file for github action 2023-03-30 11:14:52 +03:00
Morb
c13f16fa2a Merge pull request #936 from space-syndicate/upstream-sync
Upstream sync
2023-03-30 00:58:15 -07:00
Morbo
c06bc32509 Update locale 2023-03-30 09:57:43 +03:00
Morbo
bfe04b191e Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts:
#	.github/CODEOWNERS
2023-03-30 09:49:30 +03:00
DrSmugleaf
ead0352fd1 Remove Vera from CODEOWNERS (#14970) 2023-03-29 17:19:25 -07:00
PJBot
a1f61997e1 Automatic changelog update 2023-03-29 19:47:01 -04:00
Leon Friedrich
7f524f6751 Fix high pressure protection (#14968) 2023-03-29 16:45:56 -07:00
PJBot
27f0b1f0ed Automatic changelog update 2023-03-29 18:37:58 -04:00
dontbetank
81a2b29317 plushie (#14962) 2023-03-29 17:36:54 -05:00
Leon Friedrich
87b7f67bcf Add Missing ExamineEntry attribute (#14965) 2023-03-29 17:36:20 -05:00
metalgearsloth
0c87f89fdd Update submodule to 0.96.0.2 (#14959) 2023-03-30 00:08:29 +11:00
PJBot
20e0209f78 Automatic changelog update 2023-03-29 07:05:26 -04:00
metalgearsloth
72d9bd0a58 Don't delete virtual hand items on client (#14954) 2023-03-29 22:04:21 +11:00
ssdaniel24
03f7514ccc Fixed IAA briefcase suffix (#933) 2023-03-29 03:26:36 -07:00
PJBot
91cb2e4e99 Automatic changelog update 2023-03-29 05:20:01 -04:00
metalgearsloth
030ecc6964 Fix vote stacking (#14951) 2023-03-29 20:18:56 +11:00
PJBot
a3405769a0 Automatic changelog update 2023-03-29 04:51:59 -04:00
metalgearsloth
168299dbc4 Don't spawn muzzle flashes for unresolvable coordinates (#14949) 2023-03-29 19:50:54 +11:00
PJBot
d1a9162312 Automatic changelog update 2023-03-29 04:37:35 -04:00
metalgearsloth
4cbd5ef1ca Fix vote popup (#14940) 2023-03-29 19:36:30 +11:00
Emisse
5314c85de8 turred (#14948) 2023-03-29 02:16:01 -06:00
metalgearsloth
3012e5a6e9 Update submodule to 0.96.0.1 (#14947) 2023-03-29 18:54:30 +11:00
metalgearsloth
f6b5fbca6a Add protectedgrid to emergency shuttles (#14946) 2023-03-29 18:48:32 +11:00
PJBot
b32a32dc5c Automatic changelog update 2023-03-29 03:25:58 -04:00
metalgearsloth
54667700c7 Remove skub sound (#14945) 2023-03-29 18:24:54 +11:00
metalgearsloth
723d84b77d Fix turret layer abuse (#14941) 2023-03-29 17:07:15 +11:00
PJBot
91fda459c7 Automatic changelog update 2023-03-28 22:29:45 -04:00
Nemanja
23c4792a13 fix mug names (#14930) 2023-03-28 19:28:41 -07:00
Nemanja
66ff565e16 Add support for true randomized characters (#14918) 2023-03-28 18:30:00 -07:00
PJBot
3c9a74e8a0 Automatic changelog update 2023-03-28 20:47:31 -04:00
crazybrain23
00c442ba98 Gorlax Mandela effect (#14935) 2023-03-28 18:46:26 -06:00
Dawid Bla
b6c2a7ca47 Fixed godmode persisting (#14934) 2023-03-29 10:59:59 +11:00
PJBot
f08037c571 Automatic changelog update 2023-03-28 17:28:28 -04:00
DrSmugleaf
ed45440256 Always show ahelp relay message when the relay is enabled (#14931) 2023-03-28 14:27:21 -07:00
brainfood1183
f9a347be21 remove syndicate encryption key (#14925) 2023-03-28 13:04:46 -06:00
PJBot
ac1d6afc84 Automatic changelog update 2023-03-28 07:59:18 -04:00
jjtParadox
5c129c49da Fix Bureaucratic Error event affecting fewer jobs than intended (#14921) 2023-03-28 06:58:13 -05:00
IanComradeBot
94f68c5fe1 Automatic changelog update 2023-03-28 11:01:46 +00:00
no_mad
d2a126b82e [Maps] Delta Chan HotFix (#931) 2023-03-28 04:00:38 -07:00
Emisse
2e7f9661a6 centvend (#14923) 2023-03-28 02:59:58 -06:00
Morbo
bfd8189607 Fix sponsor TTS button disable 2023-03-28 10:07:08 +03:00
Emisse
f5a34af17e m m marma (#14920) 2023-03-28 00:54:52 -06:00
PJBot
8f1cca267f Automatic changelog update 2023-03-28 01:44:40 -04:00
Nemanja
62e5ef8041 Fix foldable mispredict (#14919) 2023-03-28 16:43:36 +11:00
PJBot
4bc04f1bc5 Automatic changelog update 2023-03-28 01:07:02 -04:00
Nemanja
0ed70b4f37 fix sprite exceptions for cuffs (#14912) 2023-03-27 22:06:25 -07:00
0x6273
25c89539ba Fix door remote not updating airlock lights (#14903) 2023-03-27 22:05:57 -07:00
PJBot
97b2829115 Automatic changelog update 2023-03-27 23:47:11 -04:00
Moony
cfeba15e98 Feat 27 03 23 syndie balance (#14913)
Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
2023-03-27 20:46:06 -07:00
PJBot
9f5c2d6e9c Automatic changelog update 2023-03-27 22:52:45 -04:00
metalgearsloth
a09c4e7bd1 Stretch top bar for separated hud (#14873) 2023-03-27 19:51:40 -07:00
metalgearsloth
f078be9c48 Mark escapepod as protected (#14914) 2023-03-27 19:04:43 -05:00
PJBot
15339faf14 Automatic changelog update 2023-03-27 19:36:04 -04:00
Alekshhh
a8d23e2f6b home depot noises (#14905) 2023-03-27 17:34:59 -06:00
PJBot
e128c0da6a Automatic changelog update 2023-03-27 19:05:29 -04:00
MisterMecky
a7571ac45b Add cardboard material (#14701)
* add cardboard material

* missing stack visualizers

* add crafting recipes

* cardboard crate

* license thing

* rename various things
2023-03-27 19:04:24 -04:00
PJBot
867da5b867 Automatic changelog update 2023-03-27 14:49:39 -04:00
PJBot
d2efee766f Semi-automatic changelog update 2023-03-27 14:48:30 -04:00
metalgearsloth
9afb753374 Use RemCompDeferred for portals (#14896) 2023-03-27 11:41:38 -07:00
IanComradeBot
d5b789f90b Automatic changelog update 2023-03-27 18:39:03 +00:00
Morb
65eab8c589 Trim shuttle end sound effect (#927) 2023-03-27 11:37:58 -07:00
lapatison
24d0890db1 Translate Upstream #926 (#929) 2023-03-27 11:37:19 -07:00
IanComradeBot
2b2f471f96 Automatic changelog update 2023-03-27 15:54:46 +00:00
Puro
de9a568797 Fix IAA EncryptionKey sprite (#930) 2023-03-27 08:53:41 -07:00
DocNight
57094966ce desk bell from SS13 (tgstation) (#14870) 2023-03-27 10:29:09 -04:00
metalgearsloth
a0e7ce2005 Add PreventPilot to arrivals source (#14899) 2023-03-28 00:25:27 +11:00
metalgearsloth
91c5ee2bb3 Update submodule to 0.96.0.0 (#14897) 2023-03-27 22:42:39 +11:00
Leon Friedrich
36f7a5b0e6 Rename WorldMap to MapId (#14857) 2023-03-27 22:40:57 +11:00
Morbo
bb8d298f9b Update locale 2023-03-27 12:27:29 +03:00
IanComradeBot
2349e4bf75 Automatic changelog update 2023-03-27 08:29:14 +00:00
no_mad
99038eef8c [Maps] Update Ishimura V0.22 (#919) 2023-03-27 11:28:01 +03:00
no_mad
6f3f37fc9e [Maps] Update Delta V0.14 (#917) 2023-03-27 11:27:46 +03:00
lapatison
6107f2ce49 Fix naming of Gorlex Marauders (#925) 2023-03-26 22:31:14 -07:00
Morb
0969f264c8 Merge pull request #926 from space-syndicate/upstream-sync
Upstream sync
2023-03-26 22:29:50 -07:00
MisterMecky
512b79efe2 Add butcherable component to rat servants (#14889) 2023-03-26 22:27:09 -07:00
Morbo
95939e4985 Update locale 2023-03-27 08:04:40 +03:00
Morbo
908aa1a039 Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts:
#	Content.Client/Kitchen/UI/GrinderMenu.xaml
2023-03-27 07:49:16 +03:00
Nemanja
d2943382e3 Make wall lockers have a base price of 50 (#14885) 2023-03-26 20:22:53 -06:00
Flipp Syder
626dfa05cd Adds arrivals blacklist (#14882) 2023-03-27 12:53:27 +11:00
Interrobang01
018ba85885 Cryptobiolin is now true to its description (#14844) 2023-03-26 18:03:06 -07:00
Leon Friedrich
87185d019c Fix auto-emote bug (#14883) 2023-03-26 17:47:46 -07:00
Nemanja
ef29436347 Revert "Allow RD, CMO, and QM to be traitors" (#14877) 2023-03-26 17:38:32 -07:00
Tyzemol
6476474205 Belt and back slot quick draw (#14828)
* backgunquickequip

* backgunquickequip

* fix build fail

* fix build fail 2

* cleanup

---------

Co-authored-by: BuildTools <unconfigured@null.spigotmc.org>
2023-03-26 16:01:09 -07:00
Leon Friedrich
4d71b1b81e Revert "Mind ecs" (#14881) 2023-03-27 08:24:00 +11:00
lapatison
b31a3450c2 Minor translations (#924) 2023-03-26 23:05:23 +03:00
TemporalOroboros
c6c8fa2075 Resolves MedicalScannerVisualizer is Obsolete (#13893) 2023-03-26 15:26:00 -04:00
IanComradeBot
2d039500f2 Automatic changelog update 2023-03-26 19:17:38 +00:00
no_mad
83bfbffa69 Revert C4 1984 (#914)
Co-authored-by: Morb <14136326+Morb0@users.noreply.github.com>
2023-03-26 12:16:34 -07:00
IanComradeBot
e3989944c6 Automatic changelog update 2023-03-26 19:13:51 +00:00
OhMy
5523948efe Add more words to chat filter (#923) 2023-03-26 12:12:45 -07:00
brainfood1183
edeb6c0e5a escapepods (#14879) 2023-03-26 13:12:43 -06:00
Puro
3e7ff70d31 [Clothing] Moth cloak and mask (#14851)
* Moth cloak

* Update meta.json

* Update meta.json

* fixed moth mask

yes.

* Moth mask now hides hair

yes.

* now the moth's cloak will spawn on the map

yes
2023-03-26 13:11:43 -06:00
ShadowCommander
bfc4da9377 Mind ecs (#14412) 2023-03-26 14:31:13 -04:00
Alekshhh
0e5dc41fe8 Space Bear Round 3 (#14685) 2023-03-26 13:50:17 -04:00
metalgearsloth
d2cf1b8d5d Shrink clearance for dungeon doors (#14656)
* Shrink clearance for dungeon doors

I tried adjusting it on engine but it was leading to test assertions on content which scared me.

* a

* comment
2023-03-26 12:07:49 -05:00
metalgearsloth
a8130f177f Fix static pricing for stacks (#14865)
Removed BaseItem price as it was always a placeholder and easier to just change without it.
Ensure staticprice is never used if stackprice is present.
Added StackComponent to the test so the behavior matches expectation.
2023-03-26 12:01:42 -05:00
Nemanja
930d097616 NukeOps start with either station codes or their codes (#14025)
* NukeOps start with all nuke codes

* make it pick a random code

* clarify this
2023-03-26 11:58:57 -05:00
IanComradeBot
778b5b28c7 Automatic changelog update 2023-03-26 15:55:47 +00:00
JerryTheMouse
c310e0c527 Translate suffixies external doors (#921)
Co-authored-by: lapatison <100279397+lapatison@users.noreply.github.com>
2023-03-26 08:54:41 -07:00
metalgearsloth
5b9705bc4d Add margins to chat (#14875)
* Add margins to chat

* a
2023-03-26 09:57:29 -05:00
metalgearsloth
492a361dd9 Prevent really latejoins from being T (#14866)
AKA if they're still on arrivals and either padded time or got lucky with timing.
2023-03-26 08:17:38 -05:00
metalgearsloth
93fd38cf68 Fix default chat alert being off-screen (#14868) 2023-03-26 08:16:27 -05:00
metalgearsloth
2dfdf73aa6 Fix cuff layer spam (#14869) 2023-03-26 08:15:32 -05:00
metalgearsloth
f32a922c11 Fix firevisuals layer spam (#14871) 2023-03-26 08:15:23 -05:00
Emisse
81f97cf125 fland (#14867) 2023-03-26 03:27:39 -06:00
Emisse
ea61e6b6f8 Box Fixe + Pod (#14847)
* Boxee

* rando vends

* fuck my life

* vends
2023-03-26 00:38:21 -06:00
Emisse
163b6c4e8f Meta Fixe+Pod (#14846)
* Meta Fixe+Pod

* whut

* fuck my life

* buddy pal
2023-03-26 00:36:40 -06:00
Emisse
51e2fa5015 bgal (#14862) 2023-03-26 00:33:45 -06:00
keronshb
a92b67b10d Cardboard Boxes will play effect & sound again (#14859) 2023-03-26 13:26:39 +11:00
Kara
2ba333cb55 Buff bullet impulses a wee bit (#14858) 2023-03-25 20:55:24 -05:00
Leon Friedrich
1bccbf4013 Add new map saving test (#14854) 2023-03-26 12:17:27 +11:00
Leon Friedrich
dacc9a9d22 Update engine and increases test time limit (#14853) 2023-03-26 10:28:02 +11:00
deltanedas
3cd30c408b add signal valve (#14830)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-25 16:16:27 -07:00
deltanedas
27e5fe5767 pneumatic cannon fixes (#14705)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-25 16:15:46 -07:00
ssdaniel24
e898246af1 Removed duplicated line from chat sanitizer replacements (#14841)
Co-authored-by: ssdaniel24 <ssdaniel24@github.com>
2023-03-25 16:12:02 -07:00
brainfood1183
ba3de94c73 Monkey can wear breath mask and smoke a blunt (#14612) 2023-03-25 15:59:48 -07:00
DEATHB4DEFEAT
7c21494a6a uichange Fix Grinder (#14234) 2023-03-25 10:51:35 -04:00
DEATHB4DEFEAT
32cce0d938 uichange Crew Monitor (#14235) 2023-03-25 10:51:28 -04:00
DEATHB4DEFEAT
9480291c4f uichange Communications Console (#14236) 2023-03-25 10:51:16 -04:00
Nemanja
cc43bc63ae rename "dame dane" clothing to "yakuza" clothing (#14840) 2023-03-25 07:28:11 -05:00
lapatison
ccbf8b5748 Watermelon and grapes (#14587) 2023-03-25 08:15:21 -04:00
brainfood1183
8b22ea15ae Origin Station Update 19.03.2023 (arrivals) (#14741)
* fixes substation medical access
adds station records computers

* arrivals

* added decals

* add escape pods x3

* remove planet grass

* add drain to freezer

* fix atempt, maybe escapepods causing issues.

* fix (maybe)

* remove escape pods

* reverted to arrivals, removed planet grass, added drain freezer, changed glass to plasma singulo.

* revert arrivals no changes
2023-03-24 23:48:15 -06:00
778b
7738d82811 Fixed collision of Solar Panels (#14801) 2023-03-25 15:32:45 +11:00
Kara
4ba9e8090d Minor entitystorage air fixes (#14842) 2023-03-25 15:30:19 +11:00
Mr0maks
bda78dab60 Fix force climbing DoAfter (#14736) 2023-03-25 15:12:47 +11:00
Menshin
735701d915 Alert display lights now properly react to power changes. (#14839) 2023-03-24 20:10:48 -07:00
lapatison
0acf552118 Translate Upstream #912 (#915) 2023-03-24 15:20:54 -07:00
Whisper
76b5439dc3 Emergency welder 5 space in bags (#14829) 2023-03-24 17:30:40 -04:00
dontbetank
5de921b923 Books localization (#14813) 2023-03-24 17:27:30 -04:00
AJCM-git
d9bacb63e7 Fixes the changelog getting squished in the lobby (#14836) 2023-03-24 17:08:49 -04:00
Alekshhh
230e058593 Cerberus Resprite (#14653) 2023-03-24 16:28:29 -04:00
AJCM-git
0377f328e8 Fixes codewords in the roundend summary (#14835) 2023-03-24 15:54:44 -04:00
deltanedas
a5f99dc949 dylo has 30u overdose (#14831)
* dylo has 30u overdose

* 😔

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-24 13:13:22 -05:00
IanComradeBot
2da11e4efd Automatic changelog update 2023-03-24 15:55:28 +00:00
fedKotikeD
d371535db1 Add psychologist stamp (#906) 2023-03-24 18:54:22 +03:00
Slava0135
81159b0ff5 better fluid spreading (#14529) 2023-03-25 01:09:52 +11:00
Leon Friedrich
473a02120d Map-Init guidebook entities. (#14823) 2023-03-24 20:00:29 +11:00
potato1234_x
51778afe6f TG Vending Machines + Tweaks (#14703)
* d

d

* engivend misalignment

* sustenance vendor

* Revert "sustenance vendor"

This reverts commit 2f4fb47df4529e93b7fc69da1b7a10e8a7c9f2c2.

* shamblers juice

* pwrgame

* most food/drink machines

* robotech deluxe, centdrobe and some restock boxes

* copyright + salv vend

* tweaks

* restock box + more tweaks

* yaml linter fail

* divide vendor contents

* divide contents 2
2023-03-24 02:54:47 -06:00
Leon Friedrich
ffe6b166d6 Remove TimedDespawn component from dev map (#14824) 2023-03-24 18:27:44 +11:00
metalgearsloth
8c6d05b4ce Update submodule to 0.94.0.0 (#14821) 2023-03-24 17:29:52 +11:00
metalgearsloth
dcbc094f94 Remove bounds check for FTL (#14787) 2023-03-24 17:17:08 +11:00
PJBot
64107023cf Automatic changelog update 2023-03-24 01:11:02 -04:00
Rane
5ea213c906 Fix cardboard box remote control exploits (#14494) 2023-03-24 16:09:58 +11:00
deltanedas
0663211bd0 refactor rehydration (#14707) 2023-03-24 16:00:38 +11:00
metalgearsloth
377f473ced Change pricingsystem a bit (#14470) 2023-03-24 15:27:55 +11:00
IanComradeBot
c1211bae8a Automatic changelog update 2023-03-24 04:00:55 +00:00
Morb
c94d3d8c27 Locale fallback (#913) 2023-03-23 21:00:36 -07:00
lapatison
ae65972548 Translate Sec Improvements #894 (#909) 2023-03-23 20:59:44 -07:00
Leon Friedrich
303506fc38 fix ban command help string (#14820) 2023-03-24 14:49:13 +11:00
Morb
b4caef5567 Merge pull request #912 from space-syndicate/upstream-sync
Upstream sync
2023-03-23 20:37:59 -07:00
Morbo
2c42bd5137 Update locale 2023-03-24 06:36:29 +03:00
Morbo
9aaaf5b509 Merge remote-tracking branch 'upstream/master' into upstream-sync 2023-03-24 06:35:28 +03:00
Leon Friedrich
31e4989271 Add dev map (#14614)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2023-03-24 14:17:36 +11:00
Morbo
60e88af3cf Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts:
#	Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs
2023-03-24 06:13:25 +03:00
Emisse
dd2c2b2b05 C4 1984 (#14683) 2023-03-24 14:12:17 +11:00
PJBot
ca498697d0 Automatic changelog update 2023-03-23 23:08:24 -04:00
Mr0maks
bca82315c1 Fix freedom implant charges (#14737) 2023-03-24 14:07:20 +11:00
Scribbles0
f34af1017d arrivals (#14817) 2023-03-23 21:01:48 -06:00
Morbo
5caad7e434 Update locale 2023-03-24 05:53:11 +03:00
metalgearsloth
427e5c95ca Add autocomplete to nukearm (#14819) 2023-03-24 13:50:49 +11:00
Nemanja
65acae15c0 Make artifacts support saving (#14784) 2023-03-24 13:50:24 +11:00
Morbo
c58729755f Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts:
#	Content.Server/Chat/Managers/ChatManager.cs
#	Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs
#	Resources/Textures/Clothing/Back/Satchels/hydroponics.rsi/equipped-BACKPACK.png
#	Resources/Textures/Clothing/Back/Satchels/hydroponics.rsi/icon.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/icon-on.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/icon.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/inhand-left.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/inhand-right.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/meta.json
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/on-equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/on-inhand-left.png
#	Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/on-inhand-right.png
#	Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/icon.png
#	Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/inhand-left.png
#	Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/inhand-right.png
#	Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/meta.json
2023-03-24 05:48:43 +03:00
metalgearsloth
a0332c2f2e Don't spawn midi timer for inactive instruments (#14300) 2023-03-24 13:47:38 +11:00
PJBot
6f87b0f81b Automatic changelog update 2023-03-23 22:27:23 -04:00
MisterMecky
fba633a6b1 Modify and add stack sprites for wood (#14684) 2023-03-23 22:26:19 -04:00
metalgearsloth
1db612f478 Update submodule to 0.93.3.0 (#14818) 2023-03-24 13:24:27 +11:00
metalgearsloth
d0f5eb0987 Fix tests (#14816) 2023-03-24 13:19:40 +11:00
metalgearsloth
56d7fe4f62 Add space dungeon support (#14619) 2023-03-24 13:19:29 +11:00
metalgearsloth
10f2443286 Add tree felling and chopping sounds (#14644) 2023-03-24 13:17:22 +11:00
PJBot
e2d027d15b Automatic changelog update 2023-03-23 22:14:20 -04:00
metalgearsloth
d3ef4b7572 Fix static melee effect offsets (#14815) 2023-03-24 13:13:15 +11:00
metalgearsloth
448165ffda Escape pods (#14809)
* Namespace adjustments for days

* pod

* thanks rider

* Fix the oop launch

* Fixes

* Fix stuff

* eeeeeeeee

* Fix

* access

* map

* forgor

* thing

* Genericise escape pod fill
2023-03-23 19:54:41 -06:00
PJBot
9aadc77b92 Automatic changelog update 2023-03-23 21:51:32 -04:00
MWKane
517b2b4fcf Remove BoxerComponent (#13935) 2023-03-23 21:50:28 -04:00
deltanedas
e236a1facc storage open sound has cooldown now (#14811) 2023-03-23 21:43:49 -04:00
Leon Friedrich
07667ae34b Fix mech double interactions (#14672) 2023-03-24 12:42:43 +11:00
PJBot
b960bc7636 Automatic changelog update 2023-03-23 21:41:30 -04:00
lapatison
c8084e2f5b Added orderable crates for biosuits (#14374) 2023-03-24 12:40:26 +11:00
PJBot
73b8b1e76c Automatic changelog update 2023-03-23 21:06:59 -04:00
Alekshhh
25e61bebcf Ammo Now Appear on Tables (#14639) 2023-03-23 21:05:55 -04:00
PJBot
89fdb5791e Automatic changelog update 2023-03-23 20:10:49 -04:00
Slava0135
d03ca61da1 Telecom server panel check (#14523) 2023-03-23 20:09:45 -04:00
PJBot
8c7e917038 Automatic changelog update 2023-03-23 20:03:46 -04:00
Slava0135
53681a8b31 Add telecomms system (#14486) 2023-03-23 20:02:41 -04:00
Emisse
0f2e912302 Box Arrivals Update (#14793) 2023-03-24 09:56:19 +11:00
Kara
48cefca4e4 Godmode refactor (#14651) 2023-03-23 14:57:15 -04:00
PJBot
31320a9e9a Automatic changelog update 2023-03-23 14:15:58 -04:00
deltanedas
674085defb holster + sus box tweaks (#14802) 2023-03-23 14:14:55 -04:00
PJBot
cd6b5712a5 Automatic changelog update 2023-03-23 13:45:39 -04:00
deltanedas
778c302f85 dehydrated carp can fit in locker again (#14694) 2023-03-23 13:44:35 -04:00
PJBot
76283ce647 Automatic changelog update 2023-03-23 13:18:11 -04:00
Flareguy
74bffa9818 i can this. i can that. i am doctor mario i can all (#14662) 2023-03-23 12:17:06 -05:00
PJBot
9c65bb883a Automatic changelog update 2023-03-23 13:09:50 -04:00
08A
4290577d5d Fix welder interaction (#14704) 2023-03-23 13:08:46 -04:00
PJBot
f919361ed5 Automatic changelog update 2023-03-23 12:54:31 -04:00
Nemanja
52ef1dd7f0 Revert "Paperwork Resprite (#14568)" (#14698)
This reverts commit 6c2edad3bd.
2023-03-23 12:53:27 -04:00
PJBot
f4ba28d56b Automatic changelog update 2023-03-23 12:52:54 -04:00
Alekshhh
453ae9d958 Dame Dane Change (#14686) 2023-03-23 12:51:49 -04:00
PJBot
f0de157e8f Automatic changelog update 2023-03-23 12:30:43 -04:00
deltanedas
47d5ec20ce list codewords on traitor round end (#14810) 2023-03-23 12:29:39 -04:00
PJBot
e43f154d23 Automatic changelog update 2023-03-23 12:18:37 -04:00
Whisper
8ebf650fe9 Zombies drop their headsets. (#14525) 2023-03-23 12:17:32 -04:00
PJBot
deefe7daed Automatic changelog update 2023-03-23 12:13:38 -04:00
Riley constable
5fcac6cac5 Added light post sprites (#14533) 2023-03-23 12:12:33 -04:00
Peptide90
04f6fef7a8 fix shotgun start node not being named start (#14611) 2023-03-23 12:12:14 -04:00
PJBot
9a71e4a5db Automatic changelog update 2023-03-23 12:07:13 -04:00
Alekshhh
fd006f990a Spear and Baseball bat tweak (#14375) 2023-03-23 12:06:09 -04:00
PJBot
734082c103 Automatic changelog update 2023-03-23 11:55:23 -04:00
Slava0135
620c40e087 Add explosive banana peel 2 (#14491) 2023-03-23 11:54:14 -04:00
PJBot
9c3b963e8e Automatic changelog update 2023-03-23 11:11:22 -04:00
Chief-Engineer
88fb6ccebc Add admin alerts (#13589) 2023-03-23 11:10:49 -04:00
potato1234_x
a7bafa58f1 Hydroponics Sprite Changes (#14649) 2023-03-23 11:10:18 -04:00
PJBot
6a4743a2de Automatic changelog update 2023-03-23 10:56:54 -04:00
deltanedas
52af530d61 emag disposal units to disable pressure requirement (#14630) 2023-03-23 10:55:49 -04:00
0x6273
21e5aea8ca Add EmoteOnDamage comp/system for zombies (#14371) 2023-03-23 10:52:46 -04:00
PJBot
35c237b9e1 Automatic changelog update 2023-03-23 08:54:25 -04:00
metalgearsloth
b5a33ea7ab Avoid NPCs getting stuck around tables (#14807) 2023-03-23 23:53:17 +11:00
metalgearsloth
16cebe6601 Update submodule to 0.93.2.0 (#14808) 2023-03-23 23:53:00 +11:00
metalgearsloth
86edcb960d Add autocompletion and confirmation to docking command (#14806) 2023-03-23 23:50:50 +11:00
metalgearsloth
635aa7e999 Fix decal serialization determinism (#14805) 2023-03-23 23:05:27 +11:00
Emisse
bb78c75acf Aspid Arrivals Update (#14791) 2023-03-23 21:34:23 +11:00
Emisse
e0c5813a2b Fland Arrivals Update (#14794) 2023-03-23 20:39:06 +11:00
Emisse
c4bf9b5806 Marathon Arrivals Update (#14796) 2023-03-23 20:38:55 +11:00
Emisse
0e001229b7 Omega Arrivals Update (#14799) 2023-03-23 20:38:48 +11:00
Emisse
912d0c7268 Meta Arrivals Update (#14797) 2023-03-23 20:38:34 +11:00
metalgearsloth
92dff4a630 Fix cargo (again) (#14800) 2023-03-23 19:21:12 +11:00
Emisse
c2a17452e7 Bagel Arrivals Update (#14792) 2023-03-23 19:21:00 +11:00
Emisse
d3d7e59175 Moose Arrivals Update (#14798) 2023-03-23 19:20:46 +11:00
Emisse
c8cea841ca Kettle Arrivals Update (#14795) 2023-03-23 19:19:59 +11:00
metalgearsloth
5ad059bf36 Change FTLCompletedEvent raise target (#14790) 2023-03-23 18:11:19 +11:00
PJBot
1a43dd1f50 Automatic changelog update 2023-03-23 02:56:55 -04:00
Slava0135
da7d024c37 allow to place tiles under directional windows (#13836) 2023-03-23 17:55:51 +11:00
PJBot
9413a829a4 Automatic changelog update 2023-03-23 02:51:55 -04:00
metalgearsloth
86ce1258d7 Fix docking (#14789) 2023-03-23 17:50:51 +11:00
PJBot
6ef66a7ada Automatic changelog update 2023-03-23 02:42:45 -04:00
metalgearsloth
d5cf2f28c0 Fix double FTL started event (#14788) 2023-03-23 17:41:42 +11:00
Nemanja
d5d9046fb6 Anomaly cleanup (#14781) 2023-03-23 16:53:32 +11:00
PJBot
3a545a171e Automatic changelog update 2023-03-23 01:53:24 -04:00
metalgearsloth
ca94c1748e Radar changes (#14783) 2023-03-23 16:52:20 +11:00
metalgearsloth
a0a96da4c9 Add arrivals to airlock suffix (#14786) 2023-03-23 16:40:37 +11:00
metalgearsloth
a8214c05d4 Add tagged airlock for arrivals (#14785) 2023-03-23 16:38:46 +11:00
PJBot
943b129f61 Automatic changelog update 2023-03-23 01:11:53 -04:00
metalgearsloth
569f30b721 Cargo shuttle changes (#14363) 2023-03-23 16:10:49 +11:00
PJBot
7f4bb7fe8a Automatic changelog update 2023-03-23 01:04:23 -04:00
Nemanja
e4fc696e62 Sort markings alphabetically by name (#14778) 2023-03-23 16:03:20 +11:00
Alekshhh
80efcdc231 Reduced Morbling Blood (#14638) 2023-03-23 00:29:58 -04:00
PJBot
5d76fd4c64 Automatic changelog update 2023-03-23 00:23:04 -04:00
Alekshhh
73f85fb280 PKA Consistent Firerate (#14597) 2023-03-23 00:22:01 -04:00
PJBot
4adeeee9b2 Automatic changelog update 2023-03-22 23:50:45 -04:00
adamsong
980c3ef799 Improved solution container visuals (#13791) 2023-03-23 14:49:42 +11:00
PJBot
ec71302b4f Automatic changelog update 2023-03-22 23:42:47 -04:00
AJCM-git
7a6fddce4f Moves guidebook UI logic to a UI Controller, some tweaks (#14601) 2023-03-22 23:41:43 -04:00
PJBot
6b2558456b Automatic changelog update 2023-03-22 23:40:16 -04:00
ssdaniel24
8cff034f52 Added janitoral uniform with miniskirt (#14050) 2023-03-22 23:39:12 -04:00
Maxtone
33cf53d6cf Fix Caustic damage group, Health Analyzer damage groups, change caustic to a damage type, add resistances (#14218) 2023-03-22 23:38:35 -04:00
Flipp Syder
55fb37e696 Fixes wire exception spam (#14780) 2023-03-22 19:53:29 -07:00
PJBot
b8fe133472 Automatic changelog update 2023-03-22 21:45:41 -04:00
Nemanja
f8bed49836 fix spawn artifact system (#14779) 2023-03-22 18:44:37 -07:00
PJBot
974144ddff Automatic changelog update 2023-03-22 21:38:47 -04:00
metalgearsloth
9932fe5c07 Arrivals tweaks (#14773)
Co-authored-by: Flipp Syder <76629141+vulppine@users.noreply.github.com>
2023-03-23 12:37:43 +11:00
PJBot
837e92683e Automatic changelog update 2023-03-22 16:53:44 -04:00
metalgearsloth
32a73acf12 Adjust radar grid drawing (#14769)
* Adjust radar grid drawing

Looks nicer

* werk

* a
2023-03-22 15:52:39 -05:00
IanComradeBot
34a1260b8c Automatic changelog update 2023-03-22 12:12:09 +00:00
no_mad
0fd0aea0ef Change armor to sec coat (#907) 2023-03-22 05:11:04 -07:00
Moony
59d60d4434 Update engine. (#14768)
Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
2023-03-22 04:43:15 -05:00
metalgearsloth
f3a06a0696 Add arrivals (#14755)
* Arrivals

* More arrivals and shitty uhh preload

* cvar

* a

* clockin + maps

* shitter prevention

* Placement

* a

* cvar for tests and dev

* weh
2023-03-22 04:29:55 -05:00
PJBot
a26b284349 Automatic changelog update 2023-03-22 00:59:28 -04:00
metalgearsloth
5823e47442 Fix jetpack assert (#14752) 2023-03-22 15:58:53 +11:00
metalgearsloth
4151b31b31 Clear cached NPC factions on refresh (#14762) 2023-03-22 15:58:23 +11:00
PJBot
0936f43d9e Automatic changelog update 2023-03-22 00:21:24 -04:00
T-Stalker
5bf968b1cd Gets rid of Torch's looping sound (#14625) 2023-03-22 15:20:21 +11:00
PJBot
8dc3af1a2b Automatic changelog update 2023-03-22 00:19:39 -04:00
T-Stalker
002d65cc8c Re-sprite the riot suit (#14621) 2023-03-22 15:18:34 +11:00
PJBot
16773558c2 Automatic changelog update 2023-03-21 22:35:27 -04:00
metalgearsloth
59cdbe5913 Fix melee arc context menu (#14765) 2023-03-22 13:34:22 +11:00
metalgearsloth
776d2df6bd Don't reload parallax prototypes unless necessary (#14763) 2023-03-22 12:38:29 +11:00
Kara
b4502757a5 Partial revert #14648 (#14759) 2023-03-21 16:47:26 -07:00
IanComradeBot
ba27027407 Automatic changelog update 2023-03-21 01:04:50 +00:00
lapatison
04271431be Translate Upstream #904 (#905) 2023-03-20 18:03:45 -07:00
IanComradeBot
c1d3518c60 Automatic changelog update 2023-03-21 00:22:27 +00:00
Morb
e81df5a24e Shotgun more sounds (#902) 2023-03-20 17:21:20 -07:00
Morb
80508175b6 Add custom footsteps for jackboots (#903) 2023-03-20 17:21:05 -07:00
Morb
439bc11348 Merge pull request #904 from space-syndicate/upstream-sync
Upstream sync
2023-03-20 17:20:45 -07:00
Morbo
279e031277 Update locale 2023-03-21 02:55:56 +03:00
Morbo
ca189b0db4 Merge remote-tracking branch 'upstream/master' into upstream-sync
# Conflicts:
#	Content.Server/Connection/ConnectionManager.cs
#	Content.Server/Station/Systems/StationSpawningSystem.cs
#	Content.Shared/CCVar/CCVars.cs
2023-03-21 02:50:29 +03:00
PJBot
88d68568aa Automatic changelog update 2023-03-20 15:33:34 -04:00
deltanedas
93425f0dd5 add exploding pen from goldeneye (#14421) 2023-03-20 15:32:28 -04:00
Nemanja
1ca6ced0cc new encryption key sprites (#14742)
* new encryption key sprites

* delete everything

* put it back
2023-03-19 20:56:11 -05:00
IanComradeBot
1a4bd2754c Automatic changelog update 2023-03-20 00:50:34 +00:00
SonicHDC
ed4734ea06 Fix ammo machine sprite (#901) 2023-03-19 17:49:28 -07:00
PJBot
447e66748a Automatic changelog update 2023-03-19 20:49:10 -04:00
Scribbles0
9f8f85ccf6 Nukeops Preferred Species (#14327)
* nukeops PC species

* cleanup

* invalid species fallback

* cleanup
2023-03-19 17:48:05 -07:00
deltanedas
df98091580 restructure cognizine effect so creatures that have minds can talk (#14695)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-19 17:47:06 -07:00
Robert V
8871078b33 Remove early return from SetFolded (#14697) 2023-03-19 17:46:37 -07:00
Flareguy
854f88d69c Waist bags (#14474)
* Everything (hopefully)

* makes them actually obtainable (oops)

* renames the fannypack to "waist bag"

* Removes and replaces remaining mentions of fannypacks

* oops
2023-03-19 17:45:38 -07:00
PJBot
7a247ce274 Automatic changelog update 2023-03-19 19:42:29 -04:00
deltanedas
abfac96631 fix voice mask working in pockets (#14743)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-19 16:41:25 -07:00
faint
3bf0bd3b3b "Blocked by" string is fluent now (#14713) 2023-03-19 13:36:04 -07:00
IanComradeBot
e5c0729144 Automatic changelog update 2023-03-19 06:07:25 +00:00
no_mad
3d5b5fb320 [Maps] Shuttle names fix (#899) 2023-03-19 09:06:20 +03:00
PJBot
44838f2f26 Automatic changelog update 2023-03-18 20:57:43 -04:00
Kara
7995817c80 Entity storage air capacity changes (#14734) 2023-03-18 19:56:38 -05:00
778b
fff00dd25f Added IFF console boards (#14732)
* Added computers boards

* Added boards to consoles
2023-03-18 19:55:53 -05:00
Pieter-Jan Briers
3af2e60817 Ban message improvements (#14731)
Server config now provide appeals forum link, game admins won't need to type it out manually anymore.
Add warning about trying to ban evade.
Cleaned up code a bit.
2023-03-18 19:55:12 -05:00
IanComradeBot
084be340a8 Automatic changelog update 2023-03-18 23:15:49 +00:00
Morb
3801a3b8e6 Fix shuttle call window (#898) 2023-03-18 16:14:44 -07:00
IanComradeBot
f01858c233 Automatic changelog update 2023-03-18 22:03:54 +00:00
Morb
397f497a7a [Resprite] Intercom (#897) 2023-03-18 15:02:49 -07:00
Vordenburg
eed3c2a509 Add Rotation attribute to GuideEntityEmbed. (#14729) 2023-03-18 14:26:45 -07:00
Pieter-Jan Briers
360a507688 Shared interfaces for server and role ban entities (#14730) 2023-03-18 20:44:14 +01:00
PJBot
a37ed23de9 Automatic changelog update 2023-03-18 06:58:42 -04:00
Slava0135
6ea3a13c76 make solar flare only open autoclose airlocks (#14635)
* only autoclose airlocks can be opened

* use entity query enum
2023-03-18 11:57:38 +01:00
Moony
0290e20256 Revert "Mutation Toxins (#14314)" (#14726)
This reverts commit a7f9b2881b.
2023-03-17 19:50:16 -05:00
Mr0maks
eb6d2c5b97 Fix handcuffs in fight mode (#14716) 2023-03-17 13:13:04 +11:00
Leon Friedrich
cce75f4d72 Add missing MagnetState attribute (#14715) 2023-03-17 12:50:10 +11:00
Leon Friedrich
d89f4670f1 Fix BloodstreamComponent enumerator (#14714) 2023-03-17 12:40:20 +11:00
PJBot
265a9aaf1e Automatic changelog update 2023-03-16 18:28:34 -04:00
Kara
c9dfe6ee0c Blood tweaks & fixes (#14648) 2023-03-16 15:27:28 -07:00
deltanedas
e0cfc42360 only add emag component if the event was handled (#14627)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2023-03-15 19:19:08 -07:00
PJBot
3b5354c2f2 Automatic changelog update 2023-03-15 19:51:12 -04:00
not-gavnaed
e0427bbd2b add station records computer(https://github.com/space-wizards/space-station-14/pull/14524) on aspid and bagel (#14691)
Co-authored-by: WIN-AOO91TUKDC7\geniy <bogdanilchev@yandex.ru>
2023-03-15 18:50:07 -05:00
1269 changed files with 1236747 additions and 1163903 deletions

View File

@@ -1,7 +1,9 @@
<BoxContainer
xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Orientation="Vertical"
HorizontalExpand="true">
HorizontalExpand="True">
<OutputPanel Name="TextOutput" VerticalExpand="true" />
<HistoryLineEdit Name="SenderLineEdit" />
<RichTextLabel Name="RelayedToDiscordLabel" Access="Public" Visible="False" />
</BoxContainer>

View File

@@ -3,7 +3,6 @@ using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
using Content.Client.Administration.UI.CustomControls;
namespace Content.Client.Administration.UI.Bwoink
{
@@ -18,6 +17,13 @@ namespace Content.Client.Administration.UI.Bwoink
public BwoinkPanel(Action<string> messageSender)
{
RobustXamlLoader.Load(this);
var msg = new FormattedMessage();
msg.PushColor(Color.LightGray);
msg.AddText(Loc.GetString("bwoink-system-messages-being-relayed-to-discord"));
msg.Pop();
RelayedToDiscordLabel.SetMessage(msg);
_messageSender = messageSender;
OnVisibilityChanged += c =>

View File

@@ -7,8 +7,9 @@
<LineEdit Name="_callShuttleTime" Text="4:00" PlaceHolder="m:ss" HorizontalExpand="True" SizeFlagsStretchRatio="2"/>
<Control HorizontalExpand="True" SizeFlagsStretchRatio="1"/>
<cc:CommandButton Command="callshuttle 4:00" Name="_callShuttleButton" Text="{Loc 'comms-console-menu-call-shuttle'}" HorizontalExpand="True" SizeFlagsStretchRatio="2" />
<!-- Corvax: Move button -->
<cc:CommandButton Command="recallshuttle" Name="_recallShuttleButton" Text="{Loc 'comms-console-menu-recall-shuttle'}" HorizontalAlignment="Center" SizeFlagsStretchRatio="3" />
</BoxContainer>
<cc:CommandButton Command="recallshuttle" Name="_recallShuttleButton" Text="{Loc 'comms-console-menu-recall-shuttle'}" HorizontalAlignment="Center"/>
</BoxContainer>
</DefaultWindow>

View File

@@ -15,32 +15,32 @@ public sealed class AlertLevelDisplaySystem : EntitySystem
SubscribeLocalEvent<AlertLevelDisplayComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(EntityUid uid, AlertLevelDisplayComponent component, ref AppearanceChangeEvent args)
private void OnAppearanceChange(EntityUid uid, AlertLevelDisplayComponent alertLevelDisplay, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
{
return;
}
var layer = args.Sprite.LayerMapReserveBlank(AlertLevelDisplay.Layer);
if (!args.Sprite.LayerMapTryGet(AlertLevelDisplay.Layer, out _))
if (args.AppearanceData.TryGetValue(AlertLevelDisplay.Powered, out var poweredObject))
{
var layer = args.Sprite.AddLayer(new RSI.StateId(component.AlertVisuals.Values.First()));
args.Sprite.LayerMapSet(AlertLevelDisplay.Layer, layer);
args.Sprite.LayerSetVisible(layer, poweredObject is true);
}
if (!args.AppearanceData.TryGetValue(AlertLevelDisplay.CurrentLevel, out var level))
{
args.Sprite.LayerSetState(AlertLevelDisplay.Layer, new RSI.StateId(component.AlertVisuals.Values.First()));
args.Sprite.LayerSetState(layer, alertLevelDisplay.AlertVisuals.Values.First());
return;
}
if (component.AlertVisuals.TryGetValue((string) level, out var visual))
if (alertLevelDisplay.AlertVisuals.TryGetValue((string) level, out var visual))
{
args.Sprite.LayerSetState(AlertLevelDisplay.Layer, new RSI.StateId(visual));
args.Sprite.LayerSetState(layer, visual);
}
else
{
args.Sprite.LayerSetState(AlertLevelDisplay.Layer, new RSI.StateId(component.AlertVisuals.Values.First()));
args.Sprite.LayerSetState(layer, alertLevelDisplay.AlertVisuals.Values.First());
}
}
}

View File

@@ -27,8 +27,13 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
component.LightEntity = null;
}
if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.RemoveLayer(FireVisualLayers.Fire);
// Need LayerMapTryGet because Init fails if there's no existing sprite / appearancecomp
// which means in some setups (most frequently no AppearanceComp) the layer never exists.
if (TryComp<SpriteComponent>(uid, out var sprite) &&
sprite.LayerMapTryGet(FireVisualLayers.Fire, out var layer))
{
sprite.RemoveLayer(layer);
}
}
private void OnComponentInit(EntityUid uid, FireVisualsComponent component, ComponentInit args)

View File

@@ -203,7 +203,7 @@ public sealed class BackgroundAudioSystem : EntitySystem
_ambientParams.WithVolume(_ambientParams.Volume + _configManager.GetCVar(CCVars.AmbienceVolume)));
}
private void EndAmbience()
public void EndAmbience()
{
_playingCollection = null;
_ambientStream?.Stop();

View File

@@ -1,12 +1,12 @@
using Content.Client.Cargo.UI;
using Content.Shared.Cargo.BUI;
using Content.Shared.Cargo.Events;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Cargo.BUI;
[UsedImplicitly]
public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
{
private CargoShuttleMenu? _menu;
@@ -21,9 +21,7 @@ public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
if (collection == null)
return;
_menu = new CargoShuttleMenu(collection.Resolve<IGameTiming>(), collection.Resolve<IPrototypeManager>(), collection.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>());
_menu.ShuttleCallRequested += OnShuttleCall;
_menu.ShuttleRecallRequested += OnShuttleRecall;
_menu = new CargoShuttleMenu(collection.Resolve<IPrototypeManager>(), collection.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>());
_menu.OnClose += Close;
_menu.OpenCentered();
@@ -38,24 +36,12 @@ public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
}
}
private void OnShuttleRecall()
{
SendMessage(new CargoRecallShuttleMessage());
}
private void OnShuttleCall()
{
SendMessage(new CargoCallShuttleMessage());
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not CargoShuttleConsoleBoundUserInterfaceState cargoState) return;
_menu?.SetAccountName(cargoState.AccountName);
_menu?.SetShuttleName(cargoState.ShuttleName);
_menu?.SetShuttleETA(cargoState.ShuttleETA);
_menu?.SetOrders(cargoState.Orders);
_menu?.SetCanRecall(cargoState.CanRecall);
}
}

View File

@@ -22,12 +22,6 @@
<Label Name="ShuttleStatusLabel"
Text="{Loc 'cargo-console-menu-shuttle-status-away-text'}" />
</BoxContainer>
<Button Name="ShuttleCallButton"
Text="Call Shuttle"/>
<Button Name="ShuttleRecallButton"
Text="Recall Shuttle"
ToolTip="Needs to be out of range to recall."
Visible="False"/>
<Label Text="{Loc 'cargo-console-menu-orders-label'}" />
<PanelContainer VerticalExpand="True"
SizeFlagsStretchRatio="6">

View File

@@ -3,8 +3,6 @@ using Content.Shared.Cargo;
using Content.Shared.Cargo.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
@@ -14,23 +12,14 @@ namespace Content.Client.Cargo.UI
[GenerateTypedNameReferences]
public sealed partial class CargoShuttleMenu : FancyWindow
{
private readonly IGameTiming _timing;
private readonly IPrototypeManager _protoManager;
private readonly SpriteSystem _spriteSystem;
public Action? ShuttleCallRequested;
public Action? ShuttleRecallRequested;
private TimeSpan? _shuttleEta;
public CargoShuttleMenu(IGameTiming timing, IPrototypeManager protoManager, SpriteSystem spriteSystem)
public CargoShuttleMenu(IPrototypeManager protoManager, SpriteSystem spriteSystem)
{
RobustXamlLoader.Load(this);
_timing = timing;
_protoManager = protoManager;
_spriteSystem = spriteSystem;
ShuttleCallButton.OnPressed += OnCallPressed;
ShuttleRecallButton.OnPressed += OnRecallPressed;
Title = Loc.GetString("cargo-shuttle-console-menu-title");
}
@@ -44,33 +33,6 @@ namespace Content.Client.Cargo.UI
ShuttleNameLabel.Text = name;
}
public void SetShuttleETA(TimeSpan? eta)
{
_shuttleEta = eta;
if (eta == null)
{
ShuttleCallButton.Visible = false;
ShuttleRecallButton.Visible = true;
}
else
{
ShuttleRecallButton.Visible = false;
ShuttleCallButton.Visible = true;
ShuttleCallButton.Disabled = true;
}
}
private void OnRecallPressed(BaseButton.ButtonEventArgs obj)
{
ShuttleRecallRequested?.Invoke();
}
private void OnCallPressed(BaseButton.ButtonEventArgs obj)
{
ShuttleCallRequested?.Invoke();
}
public void SetOrders(List<CargoOrderData> orders)
{
Orders.DisposeAllChildren();
@@ -102,27 +64,5 @@ namespace Content.Client.Cargo.UI
Orders.AddChild(row);
}
}
public void SetCanRecall(bool canRecall)
{
ShuttleRecallButton.Disabled = !canRecall;
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
var remaining = _shuttleEta - _timing.CurTime;
if (remaining == null || remaining <= TimeSpan.Zero)
{
ShuttleStatusLabel.Text = $"Available";
ShuttleCallButton.Disabled = false;
}
else
{
ShuttleStatusLabel.Text = $"Available in: {remaining.Value.TotalSeconds:0.0}";
}
}
}
}

View File

@@ -71,6 +71,7 @@ namespace Content.Client.Changelog
NewChangelogEntriesChanged?.Invoke();
}
// Corvax-MultiChangelog-Start
public async Task<List<ChangelogEntry>> LoadChangelog()
{
var paths = _resource.ContentFindFiles("/Changelog/")
@@ -85,6 +86,7 @@ namespace Content.Client.Changelog
}
return result.OrderBy(x => x.Time).ToList();
}
// Corvax-MultiChangelog-End
private Task<List<ChangelogEntry>> LoadChangelogFile(ResourcePath path)
{

View File

@@ -1,5 +1,6 @@
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Rounding;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;
@@ -41,7 +42,6 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
Logger.Error("Attempted to set solution container visuals volume ratio on " + ToPrettyString(uid) + " to a value greater than 1. Volume should never be greater than max volume!");
fraction = 1f;
}
if (component.Metamorphic)
{
if (args.Sprite.LayerMapTryGet(component.BaseLayer, out var baseLayer))
@@ -79,7 +79,7 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
}
}
var closestFillSprite = (int) Math.Round(fraction * component.MaxFillLevels);
int closestFillSprite = ContentHelpers.RoundToLevels(fraction, 1, component.MaxFillLevels + 1);
if (closestFillSprite > 0)
{

View File

@@ -28,6 +28,7 @@ namespace Content.Client.Communications.UI
public CommunicationsConsoleBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()

View File

@@ -0,0 +1,16 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'comms-console-menu-title'}"
MinSize="350 225">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="5">
<LineEdit Name="MessageInput" PlaceHolder="{Loc 'comms-console-menu-announcement-placeholder'}" HorizontalExpand="True" Margin="0 0 0 5" />
<Button Name="AnnounceButton" Text="{Loc 'comms-console-menu-announcement-button'}" StyleClasses="OpenLeft" Access="Public" />
<OptionButton Name="AlertLevelButton" StyleClasses="OpenRight" Access="Public" />
<Control MinSize="10 10" />
<RichTextLabel Name="CountdownLabel" VerticalExpand="True" />
<Button Name="EmergencyShuttleButton" Text="Placeholder Text" Access="Public" />
</BoxContainer>
</controls:FancyWindow>

View File

@@ -1,7 +1,10 @@
using System.Threading;
using Content.Client.UserInterface.Controls;
using System.Threading;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
@@ -10,36 +13,22 @@ using Timer = Robust.Shared.Timing.Timer;
namespace Content.Client.Communications.UI
{
public sealed class CommunicationsConsoleMenu : DefaultWindow
[GenerateTypedNameReferences]
public sealed partial class CommunicationsConsoleMenu : FancyWindow
{
private CommunicationsConsoleBoundUserInterface Owner { get; set; }
private readonly CancellationTokenSource _timerCancelTokenSource = new();
private LineEdit _messageInput { get; set; }
public readonly Button AnnounceButton;
public readonly Button EmergencyShuttleButton;
private readonly RichTextLabel _countdownLabel;
public readonly OptionButton AlertLevelButton;
public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner)
{
SetSize = MinSize = (600, 400);
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
Title = Loc.GetString("comms-console-menu-title");
Owner = owner;
_messageInput = new LineEdit
{
PlaceHolder = Loc.GetString("comms-console-menu-announcement-placeholder"),
HorizontalExpand = true,
SizeFlagsStretchRatio = 1
};
AnnounceButton = new Button();
AnnounceButton.Text = Loc.GetString("comms-console-menu-announcement-button");
AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(_messageInput.Text.Trim());
AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(MessageInput.Text.Trim());
AnnounceButton.Disabled = !owner.CanAnnounce;
AlertLevelButton = new OptionButton();
AlertLevelButton.OnItemSelected += args =>
{
var metadata = AlertLevelButton.GetItemMetadata(args.Id);
@@ -50,37 +39,9 @@ namespace Content.Client.Communications.UI
};
AlertLevelButton.Disabled = !owner.AlertLevelSelectable;
_countdownLabel = new RichTextLabel(){MinSize = new Vector2(0, 200)};
EmergencyShuttleButton = new Button();
EmergencyShuttleButton.OnPressed += (_) => Owner.EmergencyShuttleButtonPressed();
EmergencyShuttleButton.Disabled = !owner.CanCall;
var vbox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
HorizontalExpand = true,
VerticalExpand = true
};
vbox.AddChild(_messageInput);
vbox.AddChild(new Control(){MinSize = new Vector2(0,10), HorizontalExpand = true});
vbox.AddChild(AnnounceButton);
vbox.AddChild(AlertLevelButton);
vbox.AddChild(new Control(){MinSize = new Vector2(0,10), HorizontalExpand = true});
vbox.AddChild(_countdownLabel);
vbox.AddChild(EmergencyShuttleButton);
var hbox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
HorizontalExpand = true,
VerticalExpand = true
};
hbox.AddChild(new Control(){MinSize = new Vector2(100,0), HorizontalExpand = true});
hbox.AddChild(vbox);
hbox.AddChild(new Control(){MinSize = new Vector2(100,0), HorizontalExpand = true});
Contents.AddChild(hbox);
UpdateCountdown();
Timer.SpawnRepeating(1000, UpdateCountdown, _timerCancelTokenSource.Token);
}
@@ -126,13 +87,13 @@ namespace Content.Client.Communications.UI
{
if (!Owner.CountdownStarted)
{
_countdownLabel.SetMessage("");
CountdownLabel.SetMessage("");
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-call-shuttle");
return;
}
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle");
_countdownLabel.SetMessage($"Time remaining\n{Owner.Countdown.ToString()}s");
CountdownLabel.SetMessage($"Time remaining\n{Owner.Countdown.ToString()}s");
}
public override void Close()

View File

@@ -63,7 +63,7 @@ public sealed partial class HumanoidProfileEditor
IoCManager.Resolve<SponsorsManager>().TryGetInfo(out var sponsor) &&
!sponsor.AllowedMarkings.Contains(voice.ID))
{
_voiceButton.SetItemDisabled(i, true);
_voiceButton.SetItemDisabled(_voiceButton.GetIdx(i), true);
}
}

View File

@@ -15,31 +15,24 @@ public sealed class CuffableSystem : SharedCuffableSystem
{
base.Initialize();
SubscribeLocalEvent<CuffableComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<CuffableComponent, ComponentShutdown>(OnCuffableShutdown);
SubscribeLocalEvent<CuffableComponent, ComponentHandleState>(OnCuffableHandleState);
SubscribeLocalEvent<HandcuffComponent, ComponentHandleState>(OnHandcuffHandleState);
}
private void OnShutdown(EntityUid uid, CuffableComponent component, ComponentShutdown args)
{
if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, false);
}
private void OnHandcuffHandleState(EntityUid uid, HandcuffComponent component, ref ComponentHandleState args)
{
if (args.Current is not HandcuffComponentState state)
return;
component.Cuffing = state.Cuffing;
component.OverlayIconState = state.IconState;
}
if (state.IconState == string.Empty)
return;
private void OnCuffableShutdown(EntityUid uid, CuffableComponent component, ComponentShutdown args)
{
if (TryComp<SpriteComponent>(uid, out var sprite))
{
sprite.LayerSetState(HumanoidVisualLayers.Handcuffs, state.IconState);
}
sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, false);
}
private void OnCuffableHandleState(EntityUid uid, CuffableComponent component, ref ComponentHandleState args)

View File

@@ -52,6 +52,12 @@ namespace Content.Client.Forensics
{
text.AppendLine(fiber);
}
text.AppendLine();
text.AppendLine(Loc.GetString("forensic-scanner-interface-dnas"));
foreach (var dna in msg.DNAs)
{
text.AppendLine(dna);
}
Diagnostics.Text = text.ToString();
}
}

View File

@@ -34,6 +34,7 @@ namespace Content.Client.GameTicking.Managers
[ViewVariables] public bool DisallowedLateJoin { get; private set; }
[ViewVariables] public string? ServerInfoBlob { get; private set; }
[ViewVariables] public TimeSpan StartTime { get; private set; }
[ViewVariables] public TimeSpan PreloadTime { get; private set; }
[ViewVariables] public TimeSpan RoundStartTimeSpan { get; private set; }
[ViewVariables] public new bool Paused { get; private set; }
@@ -89,6 +90,7 @@ namespace Content.Client.GameTicking.Managers
private void LobbyStatus(TickerLobbyStatusEvent message)
{
StartTime = message.StartTime;
PreloadTime = message.PreloadTime;
RoundStartTimeSpan = message.RoundStartTimeSpan;
IsGameStarted = message.IsRoundStarted;
AreWeReady = message.YouAreReady;

View File

@@ -1,93 +0,0 @@
using System.Linq;
using Content.Shared.Gravity;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Gravity
{
[UsedImplicitly]
public sealed class GravityGeneratorVisualizer : AppearanceVisualizer
{
[DataField("spritemap")]
private Dictionary<string, string> _rawSpriteMap
{
get => _spriteMap.ToDictionary(x => x.Key.ToString().ToLower(), x => x.Value);
set
{
_spriteMap.Clear();
// Get Sprites for each status
foreach (var status in (GravityGeneratorStatus[]) Enum.GetValues(typeof(GravityGeneratorStatus)))
{
if (value.TryGetValue(status.ToString().ToLower(), out var sprite))
{
_spriteMap[status] = sprite;
}
}
}
}
private Dictionary<GravityGeneratorStatus, string> _spriteMap = new();
[Obsolete("Subscribe to your component being initialised instead.")]
public override void InitializeEntity(EntityUid entity)
{
base.InitializeEntity(entity);
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out SpriteComponent? sprite))
return;
sprite.LayerMapReserveBlank(GravityGeneratorVisualLayers.Base);
sprite.LayerMapReserveBlank(GravityGeneratorVisualLayers.Core);
}
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<SpriteComponent>(component.Owner);
if (component.TryGetData(GravityGeneratorVisuals.State, out GravityGeneratorStatus state))
{
if (_spriteMap.TryGetValue(state, out var spriteState))
{
var layer = sprite.LayerMapGet(GravityGeneratorVisualLayers.Base);
sprite.LayerSetState(layer, spriteState);
}
}
if (component.TryGetData(GravityGeneratorVisuals.Charge, out float charge))
{
var layer = sprite.LayerMapGet(GravityGeneratorVisualLayers.Core);
switch (charge)
{
case < 0.2f:
sprite.LayerSetVisible(layer, false);
break;
case >= 0.2f and < 0.4f:
sprite.LayerSetVisible(layer, true);
sprite.LayerSetState(layer, "startup");
break;
case >= 0.4f and < 0.6f:
sprite.LayerSetVisible(layer, true);
sprite.LayerSetState(layer, "idle");
break;
case >= 0.6f and < 0.8f:
sprite.LayerSetVisible(layer, true);
sprite.LayerSetState(layer, "activating");
break;
default:
sprite.LayerSetVisible(layer, true);
sprite.LayerSetState(layer, "activated");
break;
}
}
}
public enum GravityGeneratorVisualLayers : byte
{
Base,
Core
}
}
}

View File

@@ -1,12 +1,66 @@
using Content.Shared.Gravity;
using Robust.Client.GameObjects;
namespace Content.Client.Gravity;
public sealed partial class GravitySystem : SharedGravitySystem
{
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedGravityGeneratorComponent, AppearanceChangeEvent>(OnAppearanceChange);
InitializeShake();
}
/// <summary>
/// Ensures that the visible state of gravity generators are synced with their sprites.
/// </summary>
private void OnAppearanceChange(EntityUid uid, SharedGravityGeneratorComponent comp, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (_appearanceSystem.TryGetData<GravityGeneratorStatus>(uid, GravityGeneratorVisuals.State, out var state, args.Component))
{
if (comp.SpriteMap.TryGetValue(state, out var spriteState))
{
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Base);
args.Sprite.LayerSetState(layer, spriteState);
}
}
if (_appearanceSystem.TryGetData<float>(uid, GravityGeneratorVisuals.Charge, out var charge, args.Component))
{
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Core);
switch (charge)
{
case < 0.2f:
args.Sprite.LayerSetVisible(layer, false);
break;
case >= 0.2f and < 0.4f:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreStartupState);
break;
case >= 0.4f and < 0.6f:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreIdleState);
break;
case >= 0.6f and < 0.8f:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreActivatingState);
break;
default:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreActivatedState);
break;
}
}
}
}
public enum GravityGeneratorVisualLayers : byte
{
Base,
Core
}

View File

@@ -1,23 +1,34 @@
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Client.Guidebook;
namespace Content.Client.Guidebook.Components;
/// <summary>
/// This component stores a reference to a guidebook that contains information relevant to this entity.
/// </summary>
[RegisterComponent]
[Access(typeof(GuidebookSystem))]
public sealed class GuideHelpComponent : Component
{
/// <summary>
/// What guides to include show when opening the guidebook. The first entry will be used to select the currently
/// selected guidebook.
/// What guides to include show when opening the guidebook. The first entry will be used to select the currently
/// selected guidebook.
/// </summary>
[DataField("guides", customTypeSerializer: typeof(PrototypeIdListSerializer<GuideEntryPrototype>), required: true)]
[ViewVariables]
public List<string> Guides = new();
/// <summary>
/// Whether or not to automatically include the children of the given guides.
/// Whether or not to automatically include the children of the given guides.
/// </summary>
[DataField("includeChildren")]
[ViewVariables(VVAccess.ReadWrite)]
public bool IncludeChildren = true;
/// <summary>
/// Whether or not to open the UI when interacting with the entity while on hand.
/// Mostly intended for books
/// </summary>
[DataField("openOnActivation")]
[ViewVariables(VVAccess.ReadWrite)]
public bool OpenOnActivation;
}

View File

@@ -1,4 +1,4 @@
namespace Content.Client.Guidebook;
namespace Content.Client.Guidebook.Components;
/// <summary>
/// This is used for the guidebook monkey.

View File

@@ -164,8 +164,17 @@ public sealed partial class GuideEntityEmbed : BoxContainer, IDocumentTag
if (args.TryGetValue("Interactive", out var interactive))
Interactive = bool.Parse(interactive);
if (args.TryGetValue("Rotation", out var rotation))
{
Sprite.Rotation = Angle.FromDegrees(double.Parse(rotation));
}
Margin = new Thickness(4, 8);
// By default, we will map-initialize guidebook entities.
if (!args.TryGetValue("Init", out var mapInit) || !bool.Parse(mapInit))
_entityManager.RunMapInit(ent, _entityManager.GetComponent<MetaDataComponent>(ent));
control = this;
return true;
}

View File

@@ -1,8 +1,7 @@
using System.Linq;
using Content.Client.Guidebook.Controls;
using Content.Client.Guidebook.Components;
using Content.Client.Light;
using Content.Client.Verbs;
using Content.Shared.Input;
using Content.Shared.Interaction;
using Content.Shared.Light.Component;
using Content.Shared.Speech;
@@ -10,10 +9,7 @@ using Content.Shared.Tag;
using Content.Shared.Verbs;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.Guidebook;
@@ -24,25 +20,21 @@ namespace Content.Client.Guidebook;
public sealed class GuidebookSystem : EntitySystem
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly VerbSystem _verbSystem = default!;
[Dependency] private readonly RgbLightControllerSystem _rgbLightControllerSystem = default!;
[Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!;
[Dependency] private readonly TagSystem _tags = default!;
private GuidebookWindow _guideWindow = default!;
public event Action<List<string>, List<string>?, string?, bool, string?>? OnGuidebookOpen;
public const string GuideEmbedTag = "GuideEmbeded";
/// <inheritdoc/>
public override void Initialize()
{
CommandBinds.Builder
.Bind(ContentKeyFunctions.OpenGuidebook,
new PointerInputCmdHandler(HandleOpenGuidebook))
.Register<GuidebookSystem>();
_guideWindow = new GuidebookWindow();
SubscribeLocalEvent<GuideHelpComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerbs);
SubscribeLocalEvent<GuideHelpComponent, ActivateInWorldEvent>(OnInteract);
SubscribeLocalEvent<GuidebookControlsTestComponent, InteractHandEvent>(OnGuidebookControlsTestInteractHand);
SubscribeLocalEvent<GuidebookControlsTestComponent, ActivateInWorldEvent>(OnGuidebookControlsTestActivateInWorld);
SubscribeLocalEvent<GuidebookControlsTestComponent, GetVerbsEvent<AlternativeVerb>>(
@@ -58,12 +50,21 @@ public sealed class GuidebookSystem : EntitySystem
{
Text = Loc.GetString("guide-help-verb"),
Icon = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/VerbIcons/information.svg.192dpi.png")),
Act = () => OpenGuidebook(component.Guides, includeChildren: component.IncludeChildren, selected: component.Guides[0]),
Act = () => OnGuidebookOpen?.Invoke(component.Guides, null, null, component.IncludeChildren, component.Guides[0]),
ClientExclusive = true,
CloseMenu = true
});
}
private void OnInteract(EntityUid uid, GuideHelpComponent component, ActivateInWorldEvent args)
{
if (!component.OpenOnActivation || component.Guides.Count == 0 || _tags.HasTag(uid, GuideEmbedTag))
return;
OnGuidebookOpen?.Invoke(component.Guides, null, null, component.IncludeChildren, component.Guides[0]);
args.Handled = true;
}
private void OnGuidebookControlsTestGetAlternateVerbs(EntityUid uid, GuidebookControlsTestComponent component, GetVerbsEvent<AlternativeVerb> args)
{
args.Verbs.Add(new AlternativeVerb()
@@ -81,8 +82,8 @@ public sealed class GuidebookSystem : EntitySystem
{
Act = () =>
{
var light = EnsureComp<PointLightComponent>(uid); // RGB demands this.
light.Enabled = false;
EnsureComp<PointLightComponent>(uid); // RGB demands this.
_pointLightSystem.SetEnabled(uid, false);
var rgb = EnsureComp<RgbLightControllerComponent>(uid);
var sprite = EnsureComp<SpriteComponent>(uid);
@@ -143,103 +144,4 @@ public sealed class GuidebookSystem : EntitySystem
var activateMsg = new InteractHandEvent(user, activated);
RaiseLocalEvent(activated, activateMsg, true);
}
private bool HandleOpenGuidebook(in PointerInputCmdHandler.PointerInputCmdArgs args)
{
if (args.State != BoundKeyState.Down)
return false;
OpenGuidebook();
return true;
}
/// <summary>
/// Opens the guidebook.
/// </summary>
/// <param name="guides">What guides should be shown. If not specified, this will instead raise a <see
/// cref="GetGuidesEvent"/> and automatically include all guide prototypes.</param>
/// <param name="rootEntries">A list of guides that should form the base of the table of contents. If not specified,
/// this will automatically simply be a list of all guides that have no parent.</param>
/// <param name="forceRoot">This forces a singular guide to contain all other guides. This guide will
/// contain its own children, in addition to what would normally be the root guides if this were not
/// specified.</param>
/// <param name="includeChildren">Whether or not to automatically include child entries. If false, this will ONLY
/// show the specified entries</param>
/// <param name="selected">The guide whose contents should be displayed when the guidebook is opened</param>
public bool OpenGuidebook(
Dictionary<string, GuideEntry>? guides = null,
List<string>? rootEntries = null,
string? forceRoot = null,
bool includeChildren = true,
string? selected = null)
{
_guideWindow.OpenCenteredRight();
if (guides == null)
{
var ev = new GetGuidesEvent()
{
Guides = _prototypeManager.EnumeratePrototypes<GuideEntryPrototype>().ToDictionary(x => x.ID, x => (GuideEntry) x)
};
RaiseLocalEvent(ev);
guides = ev.Guides;
}
else if (includeChildren)
{
var oldGuides = guides;
guides = new(oldGuides);
foreach (var guide in oldGuides.Values)
{
RecursivelyAddChildren(guide, guides);
}
}
_guideWindow.UpdateGuides(guides, rootEntries, forceRoot, selected);
return true;
}
public bool OpenGuidebook(
List<string> guideList,
List<string>? rootEntries = null,
string? forceRoot = null,
bool includeChildren = true,
string? selected = null)
{
Dictionary<string, GuideEntry> guides = new();
foreach (var guideId in guideList)
{
if (!_prototypeManager.TryIndex<GuideEntryPrototype>(guideId, out var guide))
{
Logger.Error($"Encountered unknown guide prototype: {guideId}");
continue;
}
guides.Add(guideId, guide);
}
return OpenGuidebook(guides, rootEntries, forceRoot, includeChildren, selected);
}
private void RecursivelyAddChildren(GuideEntry guide, Dictionary<string, GuideEntry> guides)
{
foreach (var childId in guide.Children)
{
if (guides.ContainsKey(childId))
continue;
if (!_prototypeManager.TryIndex<GuideEntryPrototype>(childId, out var child))
{
Logger.Error($"Encountered unknown guide prototype: {childId} as a child of {guide.Id}. If the child is not a prototype, it must be directly provided.");
continue;
}
guides.Add(childId, child);
RecursivelyAddChildren(child, guides);
}
}
}
public sealed class GetGuidesEvent : EntityEventArgs
{
public Dictionary<string, GuideEntry> Guides { get; init; } = new();
}

View File

@@ -1,3 +1,3 @@
<Control xmlns="https://spacestation14.io">
<Label StyleClasses="ItemStatus" Text="Blocked by" />
<Label StyleClasses="ItemStatus" Text="{Loc 'hands-system-blocked-by'}" />
</Control>

View File

@@ -185,7 +185,8 @@ public sealed partial class MarkingPicker : Control
? _markingManager.MarkingsByCategory(_selectedMarkingCategory)
: _markingManager.MarkingsByCategoryAndSpecies(_selectedMarkingCategory, _currentSpecies);
foreach (var marking in markings.Values)
var sortedMarkings = markings.OrderBy(p => Loc.GetString(GetMarkingName(p.Value)));
foreach (var (_, marking) in sortedMarkings)
{
if (_currentMarkings.TryGetMarking(_selectedMarkingCategory, marking.ID, out _))
{
@@ -219,7 +220,7 @@ public sealed partial class MarkingPicker : Control
if (!IgnoreSpecies)
{
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager);
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager);
}
// walk backwards through the list for visual purposes
@@ -438,7 +439,7 @@ public sealed partial class MarkingPicker : Control
{
markingSet.AddBack(MarkingCategories.Hair, HairMarking);
}
if (FacialHairMarking != null)
if (FacialHairMarking != null)
{
markingSet.AddBack(MarkingCategories.FacialHair, FacialHairMarking);
}

View File

@@ -178,7 +178,8 @@ public sealed partial class SingleMarkingPicker : BoxContainer
MarkingList.Clear();
foreach (var (id, marking) in _markingPrototypeCache)
var sortedMarkings = _markingPrototypeCache.OrderBy(p => Loc.GetString($"marking-{p.Key}"));
foreach (var (id, marking) in sortedMarkings)
{
var item = MarkingList.AddItem(Loc.GetString($"marking-{id}"), marking.Sprites[0].Frame0());
item.Metadata = marking.ID;

View File

@@ -1,5 +1,6 @@
using Content.Client.Changelog;
using Content.Client.UserInterface.Systems.EscapeMenu;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared.CCVar;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -34,6 +35,14 @@ namespace Content.Client.Info
AddInfoButton("server-info-wiki-button", CCVars.InfoLinksWiki);
AddInfoButton("server-info-forum-button", CCVars.InfoLinksForum);
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
var guidebookButton = new Button() { Text = Loc.GetString("server-info-guidebook-button") };
guidebookButton.OnPressed += _ =>
{
guidebookController.ToggleGuidebook();
};
buttons.AddChild(guidebookButton);
var changelogButton = new ChangelogButton();
changelogButton.OnPressed += args => UserInterfaceManager.GetUIController<ChangelogUIController>().ToggleWindow();
buttons.AddChild(changelogButton);

View File

@@ -87,7 +87,7 @@ public sealed class InstrumentSystem : SharedInstrumentSystem
if (!Resolve(uid, ref instrument) || instrument.Renderer == null)
return;
instrument.Renderer.TrackingEntity = instrument.Owner;
instrument.Renderer.TrackingEntity = uid;
instrument.Renderer.DisablePercussionChannel = !instrument.AllowPercussion;
instrument.Renderer.DisableProgramChangeEvent = !instrument.AllowProgramChange;
@@ -127,7 +127,9 @@ public sealed class InstrumentSystem : SharedInstrumentSystem
// We dispose of the synth two seconds from now to allow the last notes to stop from playing.
// Don't use timers bound to the entity in case it is getting deleted.
Timer.Spawn(2000, () => { renderer?.Dispose(); });
if (renderer != null)
Timer.Spawn(2000, () => { renderer.Dispose(); });
instrument.Renderer = null;
instrument.MidiEventBuffer.Clear();

View File

@@ -1,15 +1,16 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.Kitchen.UI"
Title="{Loc grinder-menu-title}" MinSize="512 256" SetSize="750 256">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical" VerticalAlignment="Center">
<Button Name="GrindButton" Text="{Loc grinder-menu-grind-button}" TextAlign="Center" MinSize="64 64"/>
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc grinder-menu-title}" MinSize="768 256">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical" VerticalAlignment="Top" Margin="8">
<Button Name="GrindButton" Text="{Loc grinder-menu-grind-button}" TextAlign="Center" MinSize="64 48"/>
<Control MinSize="0 16"/>
<Button Name="JuiceButton" Text="{Loc grinder-menu-juice-button}" TextAlign="Center" MinSize="64 64"/>
<Button Name="JuiceButton" Text="{Loc grinder-menu-juice-button}" TextAlign="Center" MinSize="64 48"/>
</BoxContainer>
<Control MinSize="16 0"/>
<ui:LabelledContentBox Name="ChamberContentBox" LabelText="{Loc grinder-menu-chamber-content-box-label}" ButtonText="{Loc grinder-menu-chamber-content-box-button}" VerticalExpand="True" HorizontalExpand="True" SizeFlagsStretchRatio="2"/>
<Control MinSize="8 0"/>
<ui:LabelledContentBox Name="BeakerContentBox" LabelText="{Loc grinder-menu-beaker-content-box-label}" ButtonText="{Loc grinder-menu-beaker-content-box-button}" VerticalExpand="True" HorizontalExpand="True" SizeFlagsStretchRatio="2"/>
<ui:LabelledContentBox Name="ChamberContentBox" LabelText="{Loc grinder-menu-chamber-content-box-label}" ButtonText="{Loc grinder-menu-chamber-content-box-button}" VerticalExpand="True" HorizontalExpand="True" Margin="8" SizeFlagsStretchRatio="2"/>
<ui:LabelledContentBox Name="BeakerContentBox" LabelText="{Loc grinder-menu-beaker-content-box-label}" ButtonText="{Loc grinder-menu-beaker-content-box-button}" VerticalExpand="True" HorizontalExpand="True" Margin="8" SizeFlagsStretchRatio="2"/>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View File

@@ -1,3 +1,4 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Kitchen;
@@ -11,7 +12,7 @@ using Robust.Shared.Prototypes;
namespace Content.Client.Kitchen.UI
{
[GenerateTypedNameReferences]
public sealed partial class GrinderMenu : DefaultWindow
public sealed partial class GrinderMenu : FancyWindow
{
private readonly IEntityManager _entityManager;
private readonly IPrototypeManager _prototypeManager ;

View File

@@ -1,5 +1,5 @@
<BoxContainer Orientation="Vertical" xmlns="https://spacestation14.io">
<SplitContainer Orientation="Horizontal">
<SplitContainer Orientation="Horizontal" Margin="5">
<Label Name="Label" Align="Center"/>
<Button Name="EjectButton" Access="Public" TextAlign="Center"/>
</SplitContainer>

View File

@@ -138,6 +138,10 @@ namespace Content.Client.Lobby
{
text = Loc.GetString("lobby-state-paused");
}
else if ((_gameTicker.StartTime - _gameTicker.PreloadTime) < _gameTiming.CurTime)
{
text = Loc.GetString("lobby-state-preloading");
}
else
{
var difference = _gameTicker.StartTime - _gameTiming.CurTime;

View File

@@ -17,7 +17,7 @@
<Control Name="DefaultState" VerticalExpand="True">
<!-- Left Top Panel -->
<PanelContainer StyleClasses="AngleRect" HorizontalAlignment="Left" Name = "LeftSideTop" VerticalAlignment="Top" >
<BoxContainer Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="620">
<BoxContainer Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="800">
<info:LinkBanner Name="LinkBanner" VerticalExpand="false" HorizontalAlignment="Center" Margin="3 3 3 3"/>
<controls:StripeBack>
<BoxContainer Orientation="Horizontal" SeparationOverride="6" Margin="3 3 3 3">

View File

@@ -1,23 +1,16 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'crew-monitoring-user-interface-title'}"
SetSize="775 400">
<ScrollContainer HorizontalExpand="True"
VerticalExpand="True">
<GridContainer Name="SensorsTable"
HorizontalExpand="True"
VerticalExpand="True"
HSeparationOverride="5"
VSeparationOverride="20"
Columns="3">
<!-- Table header -->
<Label Text="{Loc 'crew-monitoring-user-interface-name'}"
StyleClasses="LabelHeading"/>
<Label Text="{Loc 'crew-monitoring-user-interface-status'}"
StyleClasses="LabelHeading"/>
<Label Text="{Loc 'crew-monitoring-user-interface-location'}"
StyleClasses="LabelHeading"/>
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'crew-monitoring-user-interface-title'}"
SetSize="775 400">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" Margin="5">
<GridContainer Name="SensorsTable" HorizontalExpand="True" VerticalExpand="True" HSeparationOverride="5" VSeparationOverride="20" Columns="4">
<!-- Category Headers -->
<Label Text="{Loc 'crew-monitoring-user-interface-name'}" StyleClasses="LabelHeading"/>
<Label Text="{Loc 'crew-monitoring-user-interface-job'}" StyleClasses="LabelHeading"/>
<Label Text="{Loc 'crew-monitoring-user-interface-status'}" StyleClasses="LabelHeading"/>
<Label Text="{Loc 'crew-monitoring-user-interface-location'}" StyleClasses="LabelHeading"/>
<!-- Table rows are filled by code -->
<!-- Additional table rows are filled by code -->
</GridContainer>
</ScrollContainer>
</DefaultWindow>
</controls:FancyWindow>

View File

@@ -14,7 +14,7 @@ using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Medical.CrewMonitoring
{
[GenerateTypedNameReferences]
public sealed partial class CrewMonitoringWindow : DefaultWindow
public sealed partial class CrewMonitoringWindow : FancyWindow
{
private List<Control> _rowsContent = new();
private List<(DirectionIcon Icon, Vector2 Position)> _directionIcons = new();
@@ -41,16 +41,26 @@ namespace Content.Client.Medical.CrewMonitoring
// add a row for each sensor
foreach (var sensor in stSensors.OrderBy(a => a.Name))
{
// add users name and job
// format: UserName (Job)
// add users name
// format: UserName
var nameLabel = new Label()
{
Text = $"{sensor.Name} ({sensor.Job})"
Text = sensor.Name,
HorizontalExpand = true
};
nameLabel.HorizontalExpand = true;
SensorsTable.AddChild(nameLabel);
_rowsContent.Add(nameLabel);
// add users job
// format: JobName
var jobLabel = new Label()
{
Text = sensor.Job,
HorizontalExpand = true
};
SensorsTable.AddChild(jobLabel);
_rowsContent.Add(jobLabel);
// add users status and damage
// format: IsAlive (TotalDamage)
var statusText = Loc.GetString(sensor.IsAlive ?
@@ -122,7 +132,7 @@ namespace Content.Client.Medical.CrewMonitoring
{
foreach (var child in _rowsContent)
{
SensorsTable.RemoveChild(child);
SensorsTable.RemoveChild(child);
}
_rowsContent.Clear();
}

View File

@@ -0,0 +1,7 @@
using Content.Shared.Medical.Surgery;
namespace Content.Client.Medical.Surgery;
public sealed class SurgeryRealmSystem : SharedSurgeryRealmSystem
{
}

View File

@@ -1,9 +1,8 @@
using Content.Shared.MedicalScanner;
namespace Content.Client.MedicalScanner
namespace Content.Client.MedicalScanner;
[RegisterComponent]
public sealed class MedicalScannerComponent : SharedMedicalScannerComponent
{
[RegisterComponent]
public sealed class MedicalScannerComponent : SharedMedicalScannerComponent
{
}
}

View File

@@ -1,61 +0,0 @@
using System;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using static Content.Shared.MedicalScanner.SharedMedicalScannerComponent;
using static Content.Shared.MedicalScanner.SharedMedicalScannerComponent.MedicalScannerStatus;
namespace Content.Client.MedicalScanner
{
[UsedImplicitly]
public sealed class MedicalScannerVisualizer : AppearanceVisualizer
{
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<SpriteComponent>(component.Owner);
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 "closed";
case Open: return "open";
case Red: return "occupied";
case Death: return "occupied";
case Green: return "occupied";
case Yellow: return "occupied";
default:
throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus");
}
}
private string StatusToTerminalStateId(MedicalScannerStatus status)
{
switch (status)
{
case Off: return "off_unlit";
case Open: return "idle_unlit";
case Red: return "red_unlit";
case Death: return "off_unlit";
case Green: return "idle_unlit";
case Yellow: return "maint_unlit";
default:
throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus");
}
}
public enum MedicalScannerVisualLayers : byte
{
Machine,
Terminal,
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Client.Parallax.Managers;
using Content.Shared._Afterlight.ThirdDimension;
using Content.Shared.CCVar;
using Content.Shared.Parallax.Biomes;
using Robust.Client.Graphics;
@@ -19,6 +20,7 @@ public sealed class ParallaxOverlay : Overlay
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IParallaxManager _manager = default!;
private readonly ParallaxSystem _parallax;
private readonly SharedZLevelSystem _zlevel = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowWorld;
@@ -27,11 +29,12 @@ public sealed class ParallaxOverlay : Overlay
ZIndex = ParallaxSystem.ParallaxZIndex;
IoCManager.InjectDependencies(this);
_parallax = _entManager.System<ParallaxSystem>();
_zlevel = _entManager.System<SharedZLevelSystem>();
}
protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (args.MapId == MapId.Nullspace || _entManager.HasComponent<BiomeComponent>(_mapManager.GetMapEntityId(args.MapId)))
if (args.MapId == MapId.Nullspace || _entManager.HasComponent<BiomeComponent>(_mapManager.GetMapEntityId(args.MapId)) || _zlevel.MapBelow[(int)args.MapId] != null)
return false;
return true;

View File

@@ -1,3 +1,4 @@
using Content.Client.Parallax.Data;
using Content.Client.Parallax.Managers;
using Content.Shared.Parallax;
using Robust.Client.Graphics;
@@ -27,6 +28,9 @@ public sealed class ParallaxSystem : SharedParallaxSystem
private void OnReload(PrototypesReloadedEventArgs obj)
{
if (!obj.ByType.ContainsKey(typeof(ParallaxPrototype)))
return;
_parallax.UnloadParallax(Fallback);
_parallax.LoadDefaultParallax();

View File

@@ -75,8 +75,9 @@ namespace Content.Client.Physics.Controllers
return;
}
var physicsUid = player;
PhysicsComponent? body;
TransformComponent? xformMover = xform;
var xformMover = xform;
if (mover.ToParent && HasComp<RelayInputMoverComponent>(xform.ParentUid))
{
@@ -85,6 +86,8 @@ namespace Content.Client.Physics.Controllers
{
return;
}
physicsUid = xform.ParentUid;
}
else if (!TryComp(player, out body))
{
@@ -128,7 +131,7 @@ namespace Content.Client.Physics.Controllers
}
// Server-side should just be handled on its own so we'll just do this shizznit
HandleMobMovement(player, mover, body, xformMover, frameTime, xformQuery, moverQuery, relayTargetQuery);
HandleMobMovement(player, mover, physicsUid, body, xformMover, frameTime, xformQuery, moverQuery, relayTargetQuery);
}
protected override bool CanSound()

View File

@@ -1,10 +1,15 @@
using Content.Client.Stylesheets;
using Content.Shared.Shuttles.BUIStates;
using Content.Shared.Shuttles.Components;
using JetBrains.Annotations;
using Content.Shared.Shuttles.Systems;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Collections;
using Robust.Shared.Input;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
@@ -32,14 +37,14 @@ public sealed class RadarControl : Control
private Angle? _rotation;
private float _radarMinRange = 64f;
private float _radarMaxRange = 256f;
public float RadarRange { get; private set; } = 256f;
private float _radarMinRange = SharedRadarConsoleSystem.DefaultMinRange;
private float _radarMaxRange = SharedRadarConsoleSystem.DefaultMaxRange;
public float RadarRange { get; private set; } = SharedRadarConsoleSystem.DefaultMinRange;
/// <summary>
/// We'll lerp between the radarrange and actual range
/// </summary>
private float _actualRadarRange = 256f;
private float _actualRadarRange = SharedRadarConsoleSystem.DefaultMinRange;
/// <summary>
/// Controls the maximum distance that IFF labels will display.
@@ -69,6 +74,11 @@ public sealed class RadarControl : Control
public Action<float>? OnRadarRangeChanged;
/// <summary>
/// Raised if the user left-clicks on the radar control with the relevant entitycoordinates.
/// </summary>
public Action<EntityCoordinates>? OnRadarClick;
public RadarControl()
{
IoCManager.InjectDependencies(this);
@@ -86,14 +96,11 @@ public sealed class RadarControl : Control
{
_radarMaxRange = ls.MaxRange;
if (_radarMaxRange < RadarRange)
{
_actualRadarRange = _radarMaxRange;
}
if (_radarMaxRange < _radarMinRange)
_radarMinRange = _radarMaxRange;
_actualRadarRange = Math.Clamp(_actualRadarRange, _radarMinRange, _radarMaxRange);
_docks.Clear();
foreach (var state in ls.Docks)
@@ -104,6 +111,43 @@ public sealed class RadarControl : Control
}
}
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{
base.KeyBindUp(args);
if (_coordinates == null || _rotation == null || args.Function != EngineKeyFunctions.UIClick ||
OnRadarClick == null)
{
return;
}
var a = InverseScalePosition(args.RelativePosition);
var relativeWorldPos = new Vector2(a.X, -a.Y);
relativeWorldPos = _rotation.Value.RotateVec(relativeWorldPos);
var coords = _coordinates.Value.Offset(relativeWorldPos);
OnRadarClick?.Invoke(coords);
}
/// <summary>
/// Gets the entitycoordinates of where the mouseposition is, relative to the control.
/// </summary>
[PublicAPI]
public EntityCoordinates GetMouseCoordinates(ScreenCoordinates screen)
{
if (_coordinates == null || _rotation == null)
{
return EntityCoordinates.Invalid;
}
var pos = screen.Position / UIScale - GlobalPosition;
var a = InverseScalePosition(pos);
var relativeWorldPos = new Vector2(a.X, -a.Y);
relativeWorldPos = _rotation.Value.RotateVec(relativeWorldPos);
var coords = _coordinates.Value.Offset(relativeWorldPos);
return coords;
}
protected override void MouseWheel(GUIMouseWheelEventArgs args)
{
base.MouseWheel(args);
@@ -170,20 +214,18 @@ public sealed class RadarControl : Control
var offset = _coordinates.Value.Position;
var offsetMatrix = Matrix3.CreateInverseTransform(
mapPosition.Position,
xform.WorldRotation - _rotation.Value);
xform.WorldRotation + _rotation.Value);
// Draw our grid in detail
var ourGridId = _coordinates.Value.GetGridUid(_entManager);
if (ourGridId != null)
if (_entManager.TryGetComponent<MapGridComponent>(ourGridId, out var ourGrid) &&
fixturesQuery.TryGetComponent(ourGridId, out var ourFixturesComp))
{
var ourGridMatrix = xformQuery.GetComponent(ourGridId.Value).WorldMatrix;
var ourGridFixtures = fixturesQuery.GetComponent(ourGridId.Value);
Matrix3.Multiply(in ourGridMatrix, in offsetMatrix, out var matrix);
// Draw our grid; use non-filled boxes so it doesn't look awful.
DrawGrid(handle, matrix, ourGridFixtures, Color.Yellow);
DrawGrid(handle, matrix, ourFixturesComp, ourGrid, Color.MediumSpringGreen, true);
DrawDocks(handle, ourGridId.Value, matrix);
}
@@ -200,7 +242,7 @@ public sealed class RadarControl : Control
foreach (var grid in _mapManager.FindGridsIntersecting(mapPosition.MapId,
new Box2(mapPosition.Position - MaxRadarRange, mapPosition.Position + MaxRadarRange)))
{
if (grid.Owner == ourGridId || !fixturesQuery.TryGetComponent(grid.Owner, out var gridFixtures))
if (grid.Owner == ourGridId || !fixturesQuery.TryGetComponent(grid.Owner, out var fixturesComp))
continue;
var gridBody = bodyQuery.GetComponent(grid.Owner);
@@ -228,7 +270,11 @@ public sealed class RadarControl : Control
var gridXform = xformQuery.GetComponent(grid.Owner);
var gridMatrix = gridXform.WorldMatrix;
Matrix3.Multiply(in gridMatrix, in offsetMatrix, out var matty);
var color = iff?.Color ?? IFFComponent.IFFColor;
var color = iff?.Color ?? Color.Gold;
// Others default:
// Color.FromHex("#FFC000FF")
// Hostile default: Color.Firebrick
if (ShowIFF &&
(iff == null && IFFComponent.ShowIFFDefault ||
@@ -278,7 +324,7 @@ public sealed class RadarControl : Control
}
// Detailed view
DrawGrid(handle, matty, gridFixtures, color);
DrawGrid(handle, matty, fixturesComp, grid, color, true);
DrawDocks(handle, grid.Owner, matty);
}
@@ -309,9 +355,10 @@ public sealed class RadarControl : Control
private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3 matrix)
{
if (!ShowDocks) return;
if (!ShowDocks)
return;
const float DockScale = 1.2f;
const float DockScale = 1f;
if (_docks.TryGetValue(uid, out var docks))
{
@@ -342,44 +389,139 @@ public sealed class RadarControl : Control
verts[i] = ScalePosition(vert);
}
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, color);
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, color.WithAlpha(0.8f));
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
}
}
}
private void DrawGrid(DrawingHandleScreen handle, Matrix3 matrix, FixturesComponent component, Color color)
private void DrawGrid(DrawingHandleScreen handle, Matrix3 matrix, FixturesComponent fixturesComp, MapGridComponent grid, Color color, bool drawInterior)
{
foreach (var fixture in component.Fixtures.Values)
var rator = grid.GetAllTilesEnumerator();
var edges = new ValueList<Vector2>();
var tileTris = new ValueList<Vector2>();
if (drawInterior)
{
// If the fixture has any points out of range we won't draw any of it.
var invalid = false;
var poly = (PolygonShape) fixture.Shape;
var verts = new Vector2[poly.VertexCount + 1];
var interiorTris = new ValueList<Vector2>();
// TODO: Engine pr
Span<Vector2> verts = new Vector2[8];
for (var i = 0; i < poly.VertexCount; i++)
foreach (var fixture in fixturesComp.Fixtures.Values)
{
var vert = matrix.Transform(poly.Vertices[i]);
var invalid = false;
var poly = (PolygonShape) fixture.Shape;
if (vert.Length > RadarRange)
for (var i = 0; i < poly.VertexCount; i++)
{
invalid = true;
break;
var vert = poly.Vertices[i];
vert = new Vector2(MathF.Round(vert.X), MathF.Round(vert.Y));
vert = matrix.Transform(vert);
if (vert.Length > RadarRange)
{
invalid = true;
break;
}
verts[i] = vert;
}
vert.Y = -vert.Y;
verts[i] = ScalePosition(vert);
if (invalid)
continue;
Vector2 AdjustedVert(Vector2 vert)
{
if (vert.Length > RadarRange)
{
vert = vert.Normalized * RadarRange;
}
vert.Y = -vert.Y;
return ScalePosition(vert);
}
interiorTris.Add(AdjustedVert(verts[0]));
interiorTris.Add(AdjustedVert(verts[1]));
interiorTris.Add(AdjustedVert(verts[3]));
interiorTris.Add(AdjustedVert(verts[1]));
interiorTris.Add(AdjustedVert(verts[2]));
interiorTris.Add(AdjustedVert(verts[3]));
}
if (invalid) continue;
// Closed list
verts[poly.VertexCount] = verts[0];
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, interiorTris.Span, color.WithAlpha(0.05f));
}
while (rator.MoveNext(out var tileRef))
{
// TODO: Short-circuit interior chunk nodes
// This can be optimised a lot more if required.
Vector2? tileVec = null;
// Iterate edges and see which we can draw
for (var i = 0; i < 4; i++)
{
var dir = (DirectionFlag) Math.Pow(2, i);
var dirVec = dir.AsDir().ToIntVec();
if (!grid.GetTileRef(tileRef.Value.GridIndices + dirVec).Tile.IsEmpty)
continue;
Vector2 start;
Vector2 end;
tileVec ??= (Vector2) tileRef.Value.GridIndices * grid.TileSize;
// Draw line
// Could probably rotate this but this might be faster?
switch (dir)
{
case DirectionFlag.South:
start = tileVec.Value;
end = tileVec.Value + new Vector2(grid.TileSize, 0f);
break;
case DirectionFlag.East:
start = tileVec.Value + new Vector2(grid.TileSize, 0f);
end = tileVec.Value + new Vector2(grid.TileSize, grid.TileSize);
break;
case DirectionFlag.North:
start = tileVec.Value + new Vector2(grid.TileSize, grid.TileSize);
end = tileVec.Value + new Vector2(0f, grid.TileSize);
break;
case DirectionFlag.West:
start = tileVec.Value + new Vector2(0f, grid.TileSize);
end = tileVec.Value;
break;
default:
throw new NotImplementedException();
}
var adjustedStart = matrix.Transform(start);
var adjustedEnd = matrix.Transform(end);
if (adjustedStart.Length > RadarRange || adjustedEnd.Length > RadarRange)
continue;
start = ScalePosition(new Vector2(adjustedStart.X, -adjustedStart.Y));
end = ScalePosition(new Vector2(adjustedEnd.X, -adjustedEnd.Y));
edges.Add(start);
edges.Add(end);
}
}
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, tileTris.Span, color.WithAlpha(0.05f));
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, edges.Span, color);
}
private Vector2 ScalePosition(Vector2 value)
{
return value * MinimapScale + MidPoint;
}
private Vector2 InverseScalePosition(Vector2 value)
{
return (value - MidPoint) / MinimapScale;
}
}

View File

@@ -118,7 +118,11 @@ public sealed partial class GeneralStationRecordConsoleWindow : DefaultWindow
},
new Label()
{
Text = Loc.GetString("general-station-record-console-record-fingerprint", ("fingerprint", record.Fingerprint is null ? Loc.GetString("generic-not-available-shorthand") : record.Fingerprint))
Text = Loc.GetString("general-station-record-console-record-fingerprint", ("fingerprint", record.Fingerprint ?? Loc.GetString("generic-not-available-shorthand")))
},
new Label()
{
Text = Loc.GetString("general-station-record-console-record-dna", ("dna", record.DNA ?? Loc.GetString("generic-not-available-shorthand")))
}
};

View File

@@ -40,16 +40,12 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
scannerRevealed &= !ShowAll; // no transparency for show-subfloor mode.
var revealed = !covered || ShowAll || scannerRevealed;
var transparency = scannerRevealed ? component.ScannerTransparency : 1f;
// set visibility & color of each layer
foreach (var layer in args.Sprite.AllLayers)
{
// pipe connection visuals are updated AFTER this, and may re-hide some layers
layer.Visible = revealed;
if (layer.Visible)
layer.Color = layer.Color.WithAlpha(transparency);
}
// Is there some layer that is always visible?

View File

@@ -0,0 +1,10 @@
namespace Content.Client.SubFloor;
/// <summary>
/// Added clientside if an entity is revealed for TRay.
/// </summary>
[RegisterComponent]
public sealed class TrayRevealedComponent : Component
{
}

View File

@@ -0,0 +1,144 @@
using Content.Client.Hands;
using Content.Shared.SubFloor;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Shared.Map;
using Robust.Shared.Timing;
namespace Content.Client.SubFloor;
public sealed class TrayScannerSystem : SharedTrayScannerSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
private const string TRayAnimationKey = "trays";
private const double AnimationLength = 0.5;
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!_timing.IsFirstTimePredicted)
return;
// TODO: Multiple viewports or w/e
var player = _player.LocalPlayer?.ControlledEntity;
var xformQuery = GetEntityQuery<TransformComponent>();
if (!xformQuery.TryGetComponent(player, out var playerXform))
return;
var playerPos = _transform.GetWorldPosition(playerXform, xformQuery);
var playerMap = playerXform.MapID;
var range = 0f;
if (TryComp<HandsComponent>(player, out var playerHands) &&
TryComp<TrayScannerComponent>(playerHands.ActiveHandEntity, out var scanner) && scanner.Enabled)
{
range = scanner.Range;
foreach (var comp in _lookup.GetComponentsInRange<SubFloorHideComponent>(playerMap, playerPos, range))
{
var uid = comp.Owner;
if (!comp.IsUnderCover || !comp.BlockAmbience | !comp.BlockInteractions)
continue;
EnsureComp<TrayRevealedComponent>(uid);
}
}
var revealedQuery = AllEntityQuery<TrayRevealedComponent, SpriteComponent, TransformComponent>();
var subfloorQuery = GetEntityQuery<SubFloorHideComponent>();
while (revealedQuery.MoveNext(out var uid, out _, out var sprite, out var xform))
{
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
// Revealing
// Add buffer range to avoid flickers.
if (subfloorQuery.HasComponent(uid) &&
xform.MapID != MapId.Nullspace &&
xform.MapID == playerMap &&
xform.Anchored &&
range != 0f &&
(playerPos - worldPos).Length <= range + 0.5f)
{
// Due to the fact client is predicting this server states will reset it constantly
if ((!_appearance.TryGetData(uid, SubFloorVisuals.ScannerRevealed, out bool value) || !value) &&
sprite.Color.A > SubfloorRevealAlpha)
{
sprite.Color = sprite.Color.WithAlpha(0f);
}
SetRevealed(uid, true);
if (sprite.Color.A >= SubfloorRevealAlpha || _animation.HasRunningAnimation(uid, TRayAnimationKey))
continue;
_animation.Play(uid, new Animation()
{
Length = TimeSpan.FromSeconds(AnimationLength),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Color),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), 0f),
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(SubfloorRevealAlpha), (float) AnimationLength)
}
}
}
}, TRayAnimationKey);
}
// Hiding
else
{
// Hidden completely so unreveal and reset the alpha.
if (sprite.Color.A <= 0f)
{
SetRevealed(uid, false);
RemCompDeferred<TrayRevealedComponent>(uid);
sprite.Color = sprite.Color.WithAlpha(1f);
continue;
}
SetRevealed(uid, true);
if (_animation.HasRunningAnimation(uid, TRayAnimationKey))
continue;
_animation.Play(uid, new Animation()
{
Length = TimeSpan.FromSeconds(AnimationLength),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Color),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(sprite.Color, 0f),
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), (float) AnimationLength)
}
}
}
}, TRayAnimationKey);
}
}
}
private void SetRevealed(EntityUid uid, bool value)
{
_appearance.SetData(uid, SubFloorVisuals.ScannerRevealed, value);
}
}

View File

@@ -0,0 +1,11 @@
<tips:ClippyUI xmlns="https://spacestation14.io"
xmlns:tips="clr-namespace:Content.Client.Tips"
MinSize="64 64"
Visible="False">
<PanelContainer Name="LabelPanel" Access="Public" Visible="False" MaxWidth="300" MaxHeight="200">
<ScrollContainer Name="ScrollingContents" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False" ReturnMeasure="True">
<RichTextLabel Name="Label" Access="Public"/>
</ScrollContainer>
</PanelContainer>
<SpriteView Name="Entity" Access="Public" MinSize="128 128"/>
</tips:ClippyUI>

View File

@@ -0,0 +1,53 @@
using Content.Client.Paper;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Tips;
[GenerateTypedNameReferences]
public sealed partial class ClippyUI : UIWidget
{
public ClippyState State = ClippyState.Hidden;
public ClippyUI()
{
RobustXamlLoader.Load(this);
}
public void InitLabel(PaperVisualsComponent? visuals, IResourceCache resCache)
{
if (visuals == null)
return;
Label.ModulateSelfOverride = visuals.FontAccentColor;
if (visuals.BackgroundImagePath == null)
return;
LabelPanel.ModulateSelfOverride = visuals.BackgroundModulate;
var backgroundImage = resCache.GetResource<TextureResource>(visuals.BackgroundImagePath);
var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch;
var backgroundPatchMargin = visuals.BackgroundPatchMargin;
LabelPanel.PanelOverride = new StyleBoxTexture
{
Texture = backgroundImage,
TextureScale = visuals.BackgroundScale,
Mode = backgroundImageMode,
PatchMarginLeft = backgroundPatchMargin.Left,
PatchMarginBottom = backgroundPatchMargin.Bottom,
PatchMarginRight = backgroundPatchMargin.Right,
PatchMarginTop = backgroundPatchMargin.Top
};
}
public enum ClippyState : byte
{
Hidden,
Revealing,
Speaking,
Hiding,
}
}

View File

@@ -0,0 +1,244 @@
using Content.Client.Gameplay;
using Content.Client.Message;
using Content.Client.Paper;
using Content.Shared.CCVar;
using Content.Shared.Movement.Components;
using Content.Shared.Tips;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using static Content.Client.Tips.ClippyUI;
namespace Content.Client.Tips;
public sealed class ClippyUIController : UIController
{
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly IConsoleHost _conHost = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IResourceCache _resCache = default!;
[UISystemDependency] private readonly AudioSystem? _audio = default;
public const float Padding = 50;
public static Angle WaddleRotation = Angle.FromDegrees(10);
private EntityUid _entity;
private float _secondsUntilNextState;
private int _previousStep = 0;
private ClippyEvent? _currentMessage;
private readonly Queue<ClippyEvent> _queuedMessages = new();
public override void Initialize()
{
base.Initialize();
_conHost.RegisterCommand("local_clippy", ClippyCommand);
UIManager.OnScreenChanged += OnScreenChanged;
}
private void ClippyCommand(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length == 0)
{
shell.WriteLine("usage: clippy <message> [entity prototype] [speak time] [animate time] [waddle]");
return;
}
var ev = new ClippyEvent(args[0]);
string proto;
if (args.Length > 1)
{
ev.Proto = args[1];
if (!_protoMan.HasIndex<EntityPrototype>(ev.Proto))
{
shell.WriteError($"Unknown prototype: {ev.Proto}");
return;
}
}
if (args.Length > 2)
ev.SpeakTime = float.Parse(args[2]);
if (args.Length > 3)
ev.SlideTime = float.Parse(args[3]);
if (args.Length > 4)
ev.WaddleInterval = float.Parse(args[4]);
AddMessage(ev);
}
public void AddMessage(ClippyEvent ev)
{
_queuedMessages.Enqueue(ev);
}
public override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
var screen = UIManager.ActiveScreen;
if (screen == null)
{
_queuedMessages.Clear();
return;
}
var clippy = screen.GetOrAddWidget<ClippyUI>();
_secondsUntilNextState -= args.DeltaSeconds;
if (_secondsUntilNextState <= 0)
NextState(clippy);
else
{
var pos = UpdatePosition(clippy, screen.Size, args); ;
LayoutContainer.SetPosition(clippy, pos);
}
}
private Vector2 UpdatePosition(ClippyUI clippy, Vector2 screenSize, FrameEventArgs args)
{
if (_currentMessage == null)
return default;
var slideTime = _currentMessage.SlideTime;
var offset = clippy.State switch
{
ClippyState.Hidden => 0,
ClippyState.Revealing => Math.Clamp(1 - _secondsUntilNextState / slideTime, 0, 1),
ClippyState.Hiding => Math.Clamp(_secondsUntilNextState / slideTime, 0, 1),
_ => 1,
};
var waddle = _currentMessage.WaddleInterval;
if (_currentMessage == null
|| waddle <= 0
|| clippy.State == ClippyState.Hidden
|| clippy.State == ClippyState.Speaking
|| !EntityManager.TryGetComponent(_entity, out SpriteComponent? sprite))
{
return (screenSize.X - offset * (clippy.DesiredSize.X + Padding), (screenSize.Y - clippy.DesiredSize.Y) / 2);
}
var numSteps = (int) Math.Ceiling(slideTime / waddle);
var curStep = (int) Math.Floor(numSteps * offset);
var stepSize = (clippy.DesiredSize.X + Padding) / numSteps;
if (curStep != _previousStep)
{
_previousStep = curStep;
sprite.Rotation = sprite.Rotation > 0
? -WaddleRotation
: WaddleRotation;
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step))
{
var audioParams = step.Sound.Params
.AddVolume(-7f)
.WithVariation(0.1f);
_audio?.PlayGlobal(step.Sound, EntityUid.Invalid, audioParams);
}
}
return (screenSize.X - stepSize * curStep, (screenSize.Y - clippy.DesiredSize.Y) / 2);
}
private void NextState(ClippyUI clippy)
{
SpriteComponent? sprite;
switch (clippy.State)
{
case ClippyState.Hidden:
if (!_queuedMessages.TryDequeue(out var next))
return;
_entity = EntityManager.SpawnEntity(next.Proto ?? _cfg.GetCVar(CCVars.ClippyEntity), MapCoordinates.Nullspace);
if (!EntityManager.TryGetComponent(_entity, out sprite))
return;
clippy.InitLabel(EntityManager.GetComponentOrNull<PaperVisualsComponent>(_entity), _resCache);
var scale = sprite.Scale;
sprite.Scale = Vector2.One;
clippy.Entity.Sprite = sprite;
clippy.Entity.Scale = scale;
_currentMessage = next;
_secondsUntilNextState = next.SlideTime;
clippy.State = ClippyState.Revealing;
_previousStep = 0;
sprite.LayerSetAnimationTime("revealing", 0);
sprite.LayerSetVisible("revealing", true);
sprite.LayerSetVisible("speaking", false);
sprite.LayerSetVisible("hiding", false);
sprite.Rotation = 0;
clippy.Label.SetMarkup(_currentMessage.Msg);
clippy.LabelPanel.Visible = false;
clippy.Visible = true;
sprite.Visible = true;
break;
case ClippyState.Revealing:
clippy.State = ClippyState.Speaking;
if (!EntityManager.TryGetComponent(_entity, out sprite))
return;
sprite.Rotation = 0;
_previousStep = 0;
sprite.LayerSetAnimationTime("speaking", 0);
sprite.LayerSetVisible("revealing", false);
sprite.LayerSetVisible("speaking", true);
sprite.LayerSetVisible("hiding", false);
clippy.LabelPanel.Visible = true;
clippy.InvalidateArrange();
clippy.InvalidateMeasure();
if (_currentMessage != null)
_secondsUntilNextState = _currentMessage.SpeakTime;
break;
case ClippyState.Speaking:
clippy.State = ClippyState.Hiding;
if (!EntityManager.TryGetComponent(_entity, out sprite))
return;
sprite.LayerSetAnimationTime("hiding", 0);
sprite.LayerSetVisible("revealing", false);
sprite.LayerSetVisible("speaking", false);
sprite.LayerSetVisible("hiding", true);
clippy.LabelPanel.Visible = false;
if (_currentMessage != null)
_secondsUntilNextState = _currentMessage.SlideTime;
break;
default: // finished hiding
EntityManager.DeleteEntity(_entity);
_entity = default;
clippy.Visible = false;
_currentMessage = null;
_secondsUntilNextState = 0;
clippy.State = ClippyState.Hidden;
break;
}
}
private void OnScreenChanged((UIScreen? Old, UIScreen? New) ev)
{
ev.Old?.RemoveWidget<ClippyUI>();
_currentMessage = null;
EntityManager.DeleteEntity(_entity);
}
}

View File

@@ -0,0 +1,20 @@
using Content.Shared.Tips;
using Robust.Client.UserInterface;
namespace Content.Client.Tips;
public sealed class TipsSystem : EntitySystem
{
[Dependency] private readonly IUserInterfaceManager _uiMan = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<ClippyEvent>(OnClippyEv);
}
private void OnClippyEv(ClippyEvent ev)
{
_uiMan.GetUIController<ClippyUIController>().AddMessage(ev);
}
}

View File

@@ -15,7 +15,14 @@
<LayoutContainer Name="ViewportContainer" HorizontalExpand="True" VerticalExpand="True">
<controls:MainViewport Name="MainViewport"/>
</LayoutContainer>
<menuBar:GameTopMenuBar Name="TopBar" Access="Protected" />
<BoxContainer Name="TopLeft" Access="Protected" Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<menuBar:GameTopMenuBar Name="TopBar" Access="Protected" />
<!-- Buffer so big votes don't skew it -->
<Control/>
</BoxContainer>
<BoxContainer Name="VoteMenu" Access="Public" Margin="0 10 0 10" Orientation="Vertical"/>
</BoxContainer>
<widgets:GhostGui Name="Ghost" Access="Protected" />
<hotbar:HotbarGui Name="Hotbar" Access="Protected" />
<actions:ActionsBar Name="Actions" Access="Protected" />

View File

@@ -1,7 +1,5 @@
using Content.Client.UserInterface.Systems.Chat.Widgets;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface.Screens;
@@ -17,7 +15,7 @@ public sealed partial class DefaultGameScreen : InGameScreen
SetAnchorPreset(MainViewport, LayoutPreset.Wide);
SetAnchorPreset(ViewportContainer, LayoutPreset.Wide);
SetAnchorAndMarginPreset(TopBar, LayoutPreset.TopLeft, margin: 10);
SetAnchorAndMarginPreset(TopLeft, LayoutPreset.TopLeft, margin: 10);
SetAnchorAndMarginPreset(Actions, LayoutPreset.BottomLeft, margin: 10);
SetAnchorAndMarginPreset(Ghost, LayoutPreset.BottomWide, margin: 80);
SetAnchorAndMarginPreset(Hotbar, LayoutPreset.BottomWide, margin: 5);
@@ -48,6 +46,6 @@ public sealed partial class DefaultGameScreen : InGameScreen
{
SetMarginBottom(Chat, size.X);
SetMarginLeft(Chat, size.Y);
SetMarginTop(Alerts, Size.X);
SetMarginTop(Alerts, size.X);
}
}

View File

@@ -16,6 +16,7 @@
<controls:RecordedSplitContainer Name="ScreenContainer" HorizontalExpand="True" VerticalExpand="True" SplitWidth="0" StretchDirection="TopLeft">
<LayoutContainer Name="ViewportContainer" HorizontalExpand="True" VerticalExpand="True">
<controls:MainViewport Name="MainViewport"/>
<BoxContainer Name="VoteMenu" Access="Public" Orientation="Vertical"/>
<widgets:GhostGui Name="Ghost" Access="Protected" />
<hotbar:HotbarGui Name="Hotbar" Access="Protected" />
<actions:ActionsBar Name="Actions" Access="Protected" />

View File

@@ -1,6 +1,5 @@
using Content.Client.UserInterface.Systems.Chat.Widgets;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@@ -18,6 +17,7 @@ public sealed partial class SeparatedChatGameScreen : InGameScreen
SetAnchorPreset(ScreenContainer, LayoutPreset.Wide);
SetAnchorPreset(ViewportContainer, LayoutPreset.Wide);
SetAnchorPreset(MainViewport, LayoutPreset.Wide);
SetAnchorAndMarginPreset(VoteMenu, LayoutPreset.TopLeft, margin: 10);
SetAnchorAndMarginPreset(Actions, LayoutPreset.BottomLeft, margin: 10);
SetAnchorAndMarginPreset(Ghost, LayoutPreset.BottomWide, margin: 80);
SetAnchorAndMarginPreset(Hotbar, LayoutPreset.BottomWide, margin: 5);

View File

@@ -29,9 +29,18 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
private BwoinkSystem? _bwoinkSystem;
private MenuButton? AhelpButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.AHelpButton;
public IAHelpUIHandler? UIHelper;
private bool _discordRelayActive;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<SharedBwoinkSystem.BwoinkDiscordRelayUpdated>(DiscordRelayUpdated);
}
public void OnStateEntered(GameplayState state)
{
@@ -71,7 +80,6 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
EnsureUIHelper();
}
private void AHelpButtonPressed(BaseButton.ButtonEventArgs obj)
{
EnsureUIHelper();
@@ -129,6 +137,12 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
UIHelper!.Receive(message);
}
private void DiscordRelayUpdated(SharedBwoinkSystem.BwoinkDiscordRelayUpdated args, EntitySessionEventArgs session)
{
_discordRelayActive = args.DiscordRelayEnabled;
UIHelper?.DiscordRelayChanged(_discordRelayActive);
}
public void EnsureUIHelper()
{
var isAdmin = _adminManager.HasFlag(AdminFlags.Adminhelp);
@@ -139,6 +153,7 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
UIHelper?.Dispose();
var ownerUserId = _playerManager.LocalPlayer!.UserId;
UIHelper = isAdmin ? new AdminAHelpUIHandler(ownerUserId) : new UserAHelpUIHandler(ownerUserId);
UIHelper.DiscordRelayChanged(_discordRelayActive);
UIHelper.SendMessageAction = (userId, textMessage) => _bwoinkSystem?.Send(userId, textMessage);
UIHelper.OnClose += () => { SetAHelpPressed(false); };
@@ -161,14 +176,15 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
EnsureUIHelper();
if (UIHelper!.IsOpen)
return;
UIHelper!.Open(localPlayer.UserId);
UIHelper!.Open(localPlayer.UserId, _discordRelayActive);
}
public void Open(NetUserId userId)
{
EnsureUIHelper();
if (!UIHelper!.IsAdmin)
return;
UIHelper?.Open(userId);
UIHelper?.Open(userId, _discordRelayActive);
}
public void ToggleWindow()
@@ -177,7 +193,6 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
UIHelper?.ToggleWindow();
}
public void PopOut()
{
EnsureUIHelper();
@@ -223,8 +238,9 @@ public interface IAHelpUIHandler : IDisposable
public bool IsOpen { get; }
public void Receive(SharedBwoinkSystem.BwoinkTextMessage message);
public void Close();
public void Open(NetUserId netUserId);
public void Open(NetUserId netUserId, bool relayActive);
public void ToggleWindow();
public void DiscordRelayChanged(bool active);
public event Action OnClose;
public event Action OnOpen;
public Action<NetUserId, string>? SendMessageAction { get; set; }
@@ -298,11 +314,15 @@ public sealed class AdminAHelpUIHandler : IAHelpUIHandler
OpenWindow();
}
public void DiscordRelayChanged(bool active)
{
}
public event Action? OnClose;
public event Action? OnOpen;
public Action<NetUserId, string>? SendMessageAction { get; set; }
public void Open(NetUserId channelId)
public void Open(NetUserId channelId, bool relayActive)
{
SelectChannel(channelId);
OpenWindow();
@@ -381,11 +401,12 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
public bool IsOpen => _window is { Disposed: false, IsOpen: true };
private DefaultWindow? _window;
private BwoinkPanel? _chatPanel;
private bool _discordRelayActive;
public void Receive(SharedBwoinkSystem.BwoinkTextMessage message)
{
DebugTools.Assert(message.UserId == _ownerId);
EnsureInit();
EnsureInit(_discordRelayActive);
_chatPanel!.ReceiveLine(message);
_window!.OpenCentered();
}
@@ -397,7 +418,7 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
public void ToggleWindow()
{
EnsureInit();
EnsureInit(_discordRelayActive);
if (_window!.IsOpen)
{
_window.Close();
@@ -413,27 +434,38 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
{
}
public void DiscordRelayChanged(bool active)
{
_discordRelayActive = active;
if (_chatPanel != null)
{
_chatPanel.RelayedToDiscordLabel.Visible = active;
}
}
public event Action? OnClose;
public event Action? OnOpen;
public Action<NetUserId, string>? SendMessageAction { get; set; }
public void Open(NetUserId channelId)
public void Open(NetUserId channelId, bool relayActive)
{
EnsureInit();
EnsureInit(relayActive);
_window!.OpenCentered();
}
private void EnsureInit()
private void EnsureInit(bool relayActive)
{
if (_window is { Disposed: false })
return;
_chatPanel = new BwoinkPanel(text => SendMessageAction?.Invoke(_ownerId, text));
_chatPanel.RelayedToDiscordLabel.Visible = relayActive;
_window = new DefaultWindow()
{
TitleClass="windowTitleAlert",
HeaderClass="windowHeaderAlert",
Title=Loc.GetString("bwoink-user-title"),
SetSize=(400, 200),
MinSize=(500, 200),
};
_window.OnClose += () => { OnClose?.Invoke(); };
_window.OnOpen += () => { OnOpen?.Invoke(); };

View File

@@ -496,6 +496,7 @@ public sealed class ChatUIController : UIController
if (_admin.HasFlag(AdminFlags.Admin))
{
FilterableChannels |= ChatChannel.Admin;
FilterableChannels |= ChatChannel.AdminAlert;
FilterableChannels |= ChatChannel.AdminChat;
CanSendChannels |= ChatSelectChannel.Admin;
}

View File

@@ -20,6 +20,7 @@ public sealed partial class ChannelFilterPopup : Popup
ChatChannel.OOC,
ChatChannel.Dead,
ChatChannel.Admin,
ChatChannel.AdminAlert,
ChatChannel.AdminChat,
ChatChannel.Server
};

View File

@@ -13,7 +13,7 @@
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical" SeparationOverride="4" HorizontalExpand="True" VerticalExpand="True">
<OutputPanel Name="Contents" HorizontalExpand="True" VerticalExpand="True" />
<OutputPanel Name="Contents" HorizontalExpand="True" VerticalExpand="True" Margin="8 8 8 4" />
<controls:ChatInputBox HorizontalExpand="True" Name="ChatInput" Access="Public" Margin="2"/>
</BoxContainer>
</PanelContainer>

View File

@@ -1,12 +1,10 @@
using Content.Client.Gameplay;
using Content.Client.Guidebook;
using Content.Client.Info;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Client.UserInterface.Systems.Info;
using Content.Shared.CCVar;
using JetBrains.Annotations;
using Robust.Client.Console;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Shared.Configuration;
@@ -26,7 +24,7 @@ public sealed class EscapeUIController : UIController, IOnStateEntered<GameplayS
[Dependency] private readonly ChangelogUIController _changelog = default!;
[Dependency] private readonly InfoUIController _info = default!;
[Dependency] private readonly OptionsUIController _options = default!;
[UISystemDependency] private readonly GuidebookSystem? _guidebook = default!;
[Dependency] private readonly GuidebookUIController _guidebook = default!;
private Options.UI.EscapeMenu? _escapeWindow;
@@ -102,7 +100,7 @@ public sealed class EscapeUIController : UIController, IOnStateEntered<GameplayS
_escapeWindow.GuidebookButton.OnPressed += _ =>
{
_guidebook?.OpenGuidebook();
_guidebook.ToggleGuidebook();
};
// Hide wiki button if we don't have a link for it.

View File

@@ -0,0 +1,206 @@
using System.Linq;
using Content.Client.Gameplay;
using Content.Client.Guidebook;
using Content.Client.Guidebook.Controls;
using Content.Client.Lobby;
using Content.Client.UserInterface.Controls;
using Content.Shared.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using static Robust.Client.UserInterface.Controls.BaseButton;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Guidebook;
public sealed class GuidebookUIController : UIController, IOnStateEntered<LobbyState>, IOnStateEntered<GameplayState>, IOnStateExited<LobbyState>, IOnStateExited<GameplayState>, IOnSystemChanged<GuidebookSystem>
{
[UISystemDependency] private readonly GuidebookSystem _guidebookSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private GuidebookWindow? _guideWindow;
private MenuButton? GuidebookButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.GuidebookButton;
public void OnStateEntered(LobbyState state)
{
HandleStateEntered();
}
public void OnStateEntered(GameplayState state)
{
HandleStateEntered();
}
private void HandleStateEntered()
{
DebugTools.Assert(_guideWindow == null);
// setup window
_guideWindow = UIManager.CreateWindow<GuidebookWindow>();
_guideWindow.OnClose += OnWindowClosed;
_guideWindow.OnOpen += OnWindowOpen;
// setup keybinding
CommandBinds.Builder
.Bind(ContentKeyFunctions.OpenGuidebook,
InputCmdHandler.FromDelegate(_ => ToggleGuidebook()))
.Register<GuidebookUIController>();
}
public void OnStateExited(LobbyState state)
{
HandleStateExited();
}
public void OnStateExited(GameplayState state)
{
HandleStateExited();
}
private void HandleStateExited()
{
if (_guideWindow == null)
return;
_guideWindow.OnClose -= OnWindowClosed;
_guideWindow.OnOpen -= OnWindowOpen;
// shutdown
_guideWindow.Dispose();
_guideWindow = null;
CommandBinds.Unregister<GuidebookUIController>();
}
public void OnSystemLoaded(GuidebookSystem system)
{
_guidebookSystem.OnGuidebookOpen += ToggleGuidebook;
}
public void OnSystemUnloaded(GuidebookSystem system)
{
_guidebookSystem.OnGuidebookOpen -= ToggleGuidebook;
}
internal void UnloadButton()
{
if (GuidebookButton == null)
return;
GuidebookButton.OnPressed -= GuidebookButtonOnPressed;
}
internal void LoadButton()
{
if (GuidebookButton == null)
return;
GuidebookButton.OnPressed += GuidebookButtonOnPressed;
}
private void GuidebookButtonOnPressed(ButtonEventArgs obj)
{
ToggleGuidebook();
}
private void OnWindowClosed()
{
if (GuidebookButton != null)
GuidebookButton.Pressed = false;
}
private void OnWindowOpen()
{
if (GuidebookButton != null)
GuidebookButton.Pressed = true;
}
/// <summary>
/// Opens the guidebook.
/// </summary>
/// <param name="guides">What guides should be shown. If not specified, this will instead list all the entries</param>
/// <param name="rootEntries">A list of guides that should form the base of the table of contents. If not specified,
/// this will automatically simply be a list of all guides that have no parent.</param>
/// <param name="forceRoot">This forces a singular guide to contain all other guides. This guide will
/// contain its own children, in addition to what would normally be the root guides if this were not
/// specified.</param>
/// <param name="includeChildren">Whether or not to automatically include child entries. If false, this will ONLY
/// show the specified entries</param>
/// <param name="selected">The guide whose contents should be displayed when the guidebook is opened</param>
public void ToggleGuidebook(
Dictionary<string, GuideEntry>? guides = null,
List<string>? rootEntries = null,
string? forceRoot = null,
bool includeChildren = true,
string? selected = null)
{
if (_guideWindow == null)
return;
if (_guideWindow.IsOpen)
{
_guideWindow.Close();
return;
}
if (GuidebookButton != null)
GuidebookButton.Pressed = !_guideWindow.IsOpen;
if (guides == null)
{
guides = _prototypeManager.EnumeratePrototypes<GuideEntryPrototype>()
.ToDictionary(x => x.ID, x => (GuideEntry) x);
}
else if (includeChildren)
{
var oldGuides = guides;
guides = new(oldGuides);
foreach (var guide in oldGuides.Values)
{
RecursivelyAddChildren(guide, guides);
}
}
_guideWindow.UpdateGuides(guides, rootEntries, forceRoot, selected);
_guideWindow.OpenCenteredRight();
}
public void ToggleGuidebook(
List<string> guideList,
List<string>? rootEntries = null,
string? forceRoot = null,
bool includeChildren = true,
string? selected = null)
{
Dictionary<string, GuideEntry> guides = new();
foreach (var guideId in guideList)
{
if (!_prototypeManager.TryIndex<GuideEntryPrototype>(guideId, out var guide))
{
Logger.Error($"Encountered unknown guide prototype: {guideId}");
continue;
}
guides.Add(guideId, guide);
}
ToggleGuidebook(guides, rootEntries, forceRoot, includeChildren, selected);
}
private void RecursivelyAddChildren(GuideEntry guide, Dictionary<string, GuideEntry> guides)
{
foreach (var childId in guide.Children)
{
if (guides.ContainsKey(childId))
continue;
if (!_prototypeManager.TryIndex<GuideEntryPrototype>(childId, out var child))
{
Logger.Error($"Encountered unknown guide prototype: {childId} as a child of {guide.Id}. If the child is not a prototype, it must be directly provided.");
continue;
}
guides.Add(childId, child);
RecursivelyAddChildren(child, guides);
}
}
}

View File

@@ -1,4 +1,3 @@
using Content.Client.Gameplay;
using Content.Client.UserInterface.Systems.Actions;
using Content.Client.UserInterface.Systems.Admin;
using Content.Client.UserInterface.Systems.Bwoink;
@@ -6,6 +5,7 @@ using Content.Client.UserInterface.Systems.Character;
using Content.Client.UserInterface.Systems.Crafting;
using Content.Client.UserInterface.Systems.EscapeMenu;
using Content.Client.UserInterface.Systems.Gameplay;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Client.UserInterface.Systems.Inventory;
using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Client.UserInterface.Systems.Sandbox;
@@ -23,6 +23,7 @@ public sealed class GameTopMenuBarUIController : UIController
[Dependency] private readonly AHelpUIController _ahelp = default!;
[Dependency] private readonly ActionUIController _action = default!;
[Dependency] private readonly SandboxUIController _sandbox = default!;
[Dependency] private readonly GuidebookUIController _guidebook = default!;
private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>();
@@ -38,6 +39,7 @@ public sealed class GameTopMenuBarUIController : UIController
public void UnloadButtons()
{
_escape.UnloadButton();
_guidebook.UnloadButton();
_inventory.UnloadButton();
_admin.UnloadButton();
_character.UnloadButton();
@@ -50,6 +52,7 @@ public sealed class GameTopMenuBarUIController : UIController
public void LoadButtons()
{
_escape.LoadButton();
_guidebook.LoadButton();
_inventory.LoadButton();
_admin.LoadButton();
_character.LoadButton();

View File

@@ -9,7 +9,7 @@
Name = "MenuButtons"
VerticalExpand="False"
Orientation="Horizontal"
HorizontalAlignment="Left"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
SeparationOverride="5"
>
@@ -23,6 +23,16 @@
HorizontalExpand="True"
AppendStyleClass="{x:Static style:StyleBase.ButtonOpenRight}"
/>
<ui:MenuButton
Name="GuidebookButton"
Access="Internal"
Icon="{xe:Tex '/Textures/Interface/VerbIcons/information.svg.192dpi.png'}"
ToolTip="{Loc 'game-hud-open-guide-menu-button-tooltip'}"
BoundKey = "{x:Static is:ContentKeyFunctions.OpenGuidebook}"
MinSize="42 64"
HorizontalExpand="True"
AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}"
/>
<ui:MenuButton
Name="CharacterButton"
Access="Internal"

View File

@@ -0,0 +1,11 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="You feel like you are going to have a bad time"
MinWidth="500">
<BoxContainer Orientation="Vertical">
<Label Text="Begin surgery on yourself to heal all injuries?" HorizontalExpand="True" />
<BoxContainer Orientation="Horizontal">
<Button Name="AcceptButton" Access="Public" Text="Accept" />
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,14 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface.Systems.Surgery;
[GenerateTypedNameReferences]
public sealed partial class SelfRequestWindow : DefaultWindow
{
public SelfRequestWindow()
{
RobustXamlLoader.Load(this);
}
}

View File

@@ -0,0 +1,54 @@
using Content.Shared.Medical.Surgery;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Enums;
namespace Content.Client.UserInterface.Systems.Surgery;
public sealed class SurgeryRealmOverlay : Overlay
{
private readonly IEntityManager _entityManager;
private readonly IEyeManager _eyeManager;
private readonly Font _font;
public SurgeryRealmOverlay(IEntityManager entityManager, IEyeManager eyeManager, IResourceCache resourceCache)
{
_entityManager = entityManager;
_eyeManager = eyeManager;
ZIndex = 200;
_font = new VectorFont(resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
}
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
protected override void Draw(in OverlayDrawArgs args)
{
if (!EntitySystem.TryGet(out EntityLookupSystem? entityLookup))
return;
var viewport = args.WorldAABB;
foreach (var heart in _entityManager.EntityQuery<SurgeryRealmHeartComponent>())
{
// if not on the same map, continue
if (_entityManager.GetComponent<TransformComponent>(heart.Owner).MapID != _eyeManager.CurrentMap)
{
continue;
}
var aabb = entityLookup.GetWorldAABB(heart.Owner);
// if not on screen, continue
if (!aabb.Intersects(in viewport))
{
continue;
}
var lineoffset = new Vector2(0f, 11f);
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center +
new Angle(-_eyeManager.CurrentEye.Rotation).RotateVec(
aabb.TopRight - aabb.Center)) + new Vector2(1f, 7f);
args.ScreenHandle.DrawString(_font, screenCoordinates + lineoffset * 2, $"Health: {heart.Health}", Color.OrangeRed);
}
}
}

View File

@@ -0,0 +1,67 @@
using System.IO;
using System.Threading.Tasks;
using Content.Client.Audio;
using Content.Client.Instruments;
using Content.Shared.Medical.Surgery;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Shared.ContentPack;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Surgery;
public sealed class SurgeryRealmUIController : UIController
{
[UISystemDependency] private readonly BackgroundAudioSystem? _backgroundAudio = default!;
private SelfRequestWindow _selfRequestWindow = default!;
private SurgeryRealmOverlay _overlay = default!;
public override void Initialize()
{
base.Initialize();
_overlay = new SurgeryRealmOverlay(EntityManager, IoCManager.Resolve<IEyeManager>(),
IoCManager.Resolve<IResourceCache>());
IoCManager.Resolve<IOverlayManager>().AddOverlay(_overlay);
SubscribeNetworkEvent<SurgeryRealmRequestSelfEvent>(OnSurgeryRequestSelf);
// pjb dont look
SubscribeNetworkEvent<SurgeryRealmStartEvent>((msg, args) => _ = OnSurgeryRealmStart(msg, args));
}
private void OnSurgeryRequestSelf(SurgeryRealmRequestSelfEvent msg, EntitySessionEventArgs args)
{
_selfRequestWindow?.Dispose();
_selfRequestWindow = new SelfRequestWindow();
_selfRequestWindow.OpenCentered();
_selfRequestWindow.AcceptButton.OnPressed += buttonArgs =>
{
_selfRequestWindow.Dispose();
IoCManager.Resolve<IEntityNetworkManager>().SendSystemNetworkMessage(new SurgeryRealmAcceptSelfEvent());
};
}
private async Task OnSurgeryRealmStart(SurgeryRealmStartEvent msg, EntitySessionEventArgs args)
{
for (var i = 500; i < 10000; i += 500)
{
// I LOVE ambience code
Timer.Spawn(i, () => _backgroundAudio?.EndAmbience());
}
var file = IoCManager.Resolve<IResourceManager>()
.ContentFileRead(new ResourcePath("/Audio/Surgery/midilovania.mid"));
await using var memStream = new MemoryStream((int) file.Length);
// 100ms delay is due to a race condition or something idk.
// While we're waiting, load it into memory.
await Task.WhenAll(Timer.Delay(100), file.CopyToAsync(memStream));
EntitySystem.Get<InstrumentSystem>()
.OpenMidi(msg.Camera, memStream.GetBuffer().AsSpan(0, (int)memStream.Length));
}
}

View File

@@ -1,5 +1,7 @@
using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Gameplay;
using Content.Shared._Afterlight.ThirdDimension;
using Content.Shared.CCVar;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
@@ -77,16 +79,28 @@ public sealed class ViewportUIController : UIController
base.FrameUpdate(e);
Viewport.Viewport.Eye = _eyeManager.CurrentEye;
// verify that the current eye is not "null". Fuck IEyeManager.
var ent = _playerMan.LocalPlayer?.ControlledEntity;
if (_entMan.TryGetComponent(ent, out ZViewComponent? view))
{
Viewport.Viewport.LowerEyes = view.DownViewEnts.Select(x =>
{
var eye = _entMan.GetComponent<EyeComponent>(x);
eye.Rotation = _eyeManager.CurrentEye.Rotation;
eye.DrawFov = false; // We're z leveling, no FoV.
return eye.Eye!;
}).ToArray();
}
if (_eyeManager.CurrentEye.Position != default || ent == null)
return;
_entMan.TryGetComponent(ent, out EyeComponent? eye);
if (eye?.Eye == _eyeManager.CurrentEye
&& _entMan.GetComponent<TransformComponent>(ent.Value).WorldPosition == default)
return; // nothing to worry about, the player is just in null space... actually that is probably a problem?

View File

@@ -0,0 +1,37 @@
using Content.Client.UserInterface.Screens;
using Content.Client.UserInterface.Systems.Gameplay;
using Content.Client.Voting;
using Robust.Client.UserInterface.Controllers;
namespace Content.Client.UserInterface.Systems.Vote;
public sealed class VoteUIController : UIController
{
[Dependency] private readonly IVoteManager _votes = default!;
public override void Initialize()
{
base.Initialize();
var gameplayStateLoad = UIManager.GetUIController<GameplayStateLoadController>();
gameplayStateLoad.OnScreenLoad += OnScreenLoad;
gameplayStateLoad.OnScreenUnload += OnScreenUnload;
}
private void OnScreenLoad()
{
switch (UIManager.ActiveScreen)
{
case DefaultGameScreen game:
_votes.SetPopupContainer(game.VoteMenu);
break;
case SeparatedChatGameScreen separated:
_votes.SetPopupContainer(separated.VoteMenu);
break;
}
}
private void OnScreenUnload()
{
_votes.ClearPopupContainer();
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.UserInterface;
@@ -24,7 +25,9 @@ namespace Content.Client.Viewport
// Internal viewport creation is deferred.
private IClydeViewport? _viewport;
private List<IClydeViewport> _lowerPorts = new();
private IEye? _eye;
private IEye[] _lowerEyes = new IEye[] {};
private Vector2i _viewportSize;
private int _curRenderScale;
private ScalingViewportStretchMode _stretchMode = ScalingViewportStretchMode.Bilinear;
@@ -50,6 +53,27 @@ namespace Content.Client.Viewport
}
}
public IEye[] LowerEyes
{
get => _lowerEyes;
set
{
var old = value;
_lowerEyes = value;
if (old.Length != value.Length)
{
InvalidateViewport();
Logger.Debug("Eyes updated..");
}
foreach (var (eye, port) in _lowerEyes.Zip(_lowerPorts))
{
port.Eye = eye;
}
}
}
/// <summary>
/// The size, in unscaled pixels, of the internal viewport.
/// </summary>
@@ -137,6 +161,11 @@ namespace Content.Client.Viewport
_viewport!.Render();
foreach (var viewport in _lowerPorts)
{
viewport.Render();
}
if (_queuedScreenshots.Count != 0)
{
var callbacks = _queuedScreenshots.ToArray();
@@ -155,6 +184,10 @@ namespace Content.Client.Viewport
var drawBox = GetDrawBox();
var drawBoxGlobal = drawBox.Translated(GlobalPixelPosition);
_viewport.RenderScreenOverlaysBelow(handle, this, drawBoxGlobal);
foreach (var viewport in _lowerPorts.AsEnumerable().Reverse())
{
handle.DrawTextureRect(viewport.RenderTarget.Texture, drawBox);
}
handle.DrawTextureRect(_viewport.RenderTarget.Texture, drawBox);
_viewport.RenderScreenOverlaysAbove(handle, this, drawBoxGlobal);
}
@@ -224,6 +257,23 @@ namespace Content.Client.Viewport
{
Filter = StretchMode == ScalingViewportStretchMode.Bilinear,
});
_viewport.ClearColor = Color.Blue.WithAlpha(0.02f);
_lowerPorts.Clear();
for (var i = 0; i < _lowerEyes.Length; i++)
{
_lowerPorts.Add(_clyde.CreateViewport(
ViewportSize * renderScale,
new TextureSampleParameters
{
Filter = StretchMode == ScalingViewportStretchMode.Bilinear,
}));
_lowerPorts[i].RenderScale = (renderScale, renderScale);
_lowerPorts[i].ClearColor = Color.Blue.WithAlpha(0.02f);
_lowerPorts[i].Eye = _lowerEyes[i];
_lowerPorts[i].Eye!.Zoom = _lowerPorts[i].Eye!.Zoom * (1.02f + i * 0.02f);
}
_viewport.RenderScale = (renderScale, renderScale);
@@ -241,6 +291,11 @@ namespace Content.Client.Viewport
{
_viewport?.Dispose();
_viewport = null;
foreach (var port in _lowerPorts)
{
port.Dispose();
}
_lowerPorts = new();
}
public MapCoordinates ScreenToMap(Vector2 coords)
@@ -291,7 +346,7 @@ namespace Content.Client.Viewport
private void EnsureViewportCreated()
{
if (_viewport == null)
if (_viewport == null || _lowerPorts.Count != _lowerEyes.Length)
{
RegenerateViewport();
}

View File

@@ -95,6 +95,13 @@ namespace Content.Client.Voting
}
_popupContainer = container;
SetVoteData();
}
private void SetVoteData()
{
if (_popupContainer == null)
return;
foreach (var (vId, vote) in _votes)
{
@@ -121,9 +128,13 @@ namespace Content.Client.Voting
@new = true;
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>()
.PlayGlobal("/Audio/Effects/voteding.ogg", Filter.Local(), false);
// TODO: It would be better if this used a per-state container, i.e. a container
// for the lobby and each HUD layout.
SetPopupContainer(_userInterfaceManager.WindowRoot);
// Refresh
var container = _popupContainer;
ClearPopupContainer();
if (container != null)
SetPopupContainer(container);
// New vote from the server.
var vote = new ActiveVote(voteId)
@@ -142,6 +153,7 @@ namespace Content.Client.Voting
_votes.Remove(voteId);
if (_votePopups.TryGetValue(voteId, out var toRemove))
{
toRemove.Orphan();
_votePopups.Remove(voteId);
}

View File

@@ -153,10 +153,13 @@ public sealed partial class MeleeWeaponSystem
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey);
break;
case WeaponArcAnimation.None:
var (mapPos, mapRot) = _transform.GetWorldPositionRotation(userXform, GetEntityQuery<TransformComponent>());
var xform = Transform(animationUid);
var xformQuery = GetEntityQuery<TransformComponent>();
var (mapPos, mapRot) = _transform.GetWorldPositionRotation(userXform, xformQuery);
var xform = xformQuery.GetComponent(animationUid);
xform.AttachToGridOrMap();
_transform.SetWorldPosition(xform, mapPos + (mapRot - userXform.LocalRotation).RotateVec(localPos));
var worldPos = mapPos + (mapRot - userXform.LocalRotation).RotateVec(localPos);
var newLocalPos = _transform.GetInvWorldMatrix(xform.ParentUid, xformQuery).Transform(worldPos);
_transform.SetLocalPositionNoLerp(xform, newLocalPos);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break;

View File

@@ -169,7 +169,8 @@ public sealed partial class GunSystem : SharedGunSystem
});
}
public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null)
public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null, bool throwItems = false)
{
// Rather than splitting client / server for every ammo provider it's easier
// to just delete the spawned entities. This is for programmer sanity despite the wasted perf.
@@ -178,6 +179,16 @@ public sealed partial class GunSystem : SharedGunSystem
foreach (var (ent, shootable) in ammo)
{
if (throwItems)
{
Recoil(user, direction);
if (ent!.Value.IsClientSide())
Del(ent.Value);
else
RemComp<AmmoComponent>(ent.Value);
continue;
}
switch (shootable)
{
case CartridgeAmmoComponent cartridge:
@@ -247,6 +258,9 @@ public sealed partial class GunSystem : SharedGunSystem
else
return;
if (!coordinates.IsValid(EntityManager))
return;
var ent = Spawn(message.Prototype, coordinates);
var effectXform = Transform(ent);

View File

@@ -0,0 +1,7 @@
using Content.Shared.Wires;
namespace Content.Client.Wires;
public sealed class WiresSystem : SharedWiresSystem
{
}

View File

@@ -0,0 +1,17 @@
using Content.Shared._Afterlight.ThirdDimension;
using Robust.Shared.Map;
namespace Content.Client.zlevels;
public sealed class ZViewSystem : SharedZViewSystem
{
public override EntityUid SpawnViewEnt(EntityUid source, MapCoordinates loc)
{
throw new NotImplementedException();
}
public override bool CanSetup(EntityUid source)
{
return false;
}
}

View File

@@ -53,6 +53,7 @@ public static class PoolManager
(CVars.ThreadParallelCount.Name, "1"),
(CCVars.GameRoleTimers.Name, "false"),
(CCVars.CargoShuttles.Name, "false"),
(CCVars.ArrivalsShuttles.Name, "false"),
(CCVars.EmergencyShuttleEnabled.Name, "false"),
(CCVars.ProcgenPreload.Name, "false"),
// @formatter:on

View File

@@ -10,7 +10,7 @@ namespace Content.IntegrationTests;
public sealed class PoolManagerTestEventHandler
{
// This value is completely arbitrary.
private static TimeSpan MaximumTotalTestingTimeLimit => TimeSpan.FromMinutes(15);
private static TimeSpan MaximumTotalTestingTimeLimit => TimeSpan.FromMinutes(20);
private static TimeSpan HardStopTimeLimit => MaximumTotalTestingTimeLimit.Add(TimeSpan.FromMinutes(1));
[OneTimeSetUp]
public void Setup()

View File

@@ -3,6 +3,7 @@ using System.Linq;
using Content.Server.Cargo.Components;
using Content.Server.Cargo.Systems;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.Stacks;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
@@ -82,13 +83,57 @@ public sealed class CargoTest
if (entManager.TryGetComponent<StaticPriceComponent>(ent, out var staticpricecomp))
{
Assert.That(staticpricecomp.Price, Is.EqualTo(0),
$"The prototype {proto} have a StackPriceComponent and StaticPriceComponent whose values are not compatible with each other.");
$"The prototype {proto} has a StackPriceComponent and StaticPriceComponent whose values are not compatible with each other.");
}
}
if (entManager.HasComponent<StackComponent>(ent))
{
if (entManager.TryGetComponent<StaticPriceComponent>(ent, out var staticpricecomp))
{
Assert.That(staticpricecomp.Price, Is.EqualTo(0),
$"The prototype {proto} has a StackComponent and StaticPriceComponent whose values are not compatible with each other.");
}
}
entManager.DeleteEntity(ent);
}
mapManager.DeleteMap(mapId);
});
await pairTracker.CleanReturnAsync();
}
[Test]
public async Task StackPrice()
{
const string StackProto = @"
- type: entity
id: A
- type: stack
id: StackProto
spawn: A
- type: entity
id: StackEnt
components:
- type: StackPrice
price: 20
- type: Stack
stackType: StackProto
count: 5
";
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = StackProto});
var server = pairTracker.Pair.Server;
var entManager = server.ResolveDependency<IEntityManager>();
var priceSystem = entManager.System<PricingSystem>();
var ent = entManager.SpawnEntity("StackEnt", MapCoordinates.Nullspace);
var price = priceSystem.GetPrice(ent);
Assert.That(price, Is.EqualTo(100.0));
await pairTracker.CleanReturnAsync();
}
}

View File

@@ -225,7 +225,7 @@ namespace Content.IntegrationTests.Tests
Assert.IsNotNull(stationConfig, $"{entManager.ToPrettyString(station)} had null StationConfig.");
var shuttlePath = stationConfig.EmergencyShuttlePath.ToString();
var shuttle = mapLoader.LoadGrid(shuttleMap, shuttlePath);
Assert.That(shuttle != null && shuttleSystem.TryFTLDock(entManager.GetComponent<ShuttleComponent>(shuttle.Value), targetGrid.Value), $"Unable to dock {shuttlePath} to {mapProto}");
Assert.That(shuttle != null && shuttleSystem.TryFTLDock(shuttle.Value, entManager.GetComponent<ShuttleComponent>(shuttle.Value), targetGrid.Value), $"Unable to dock {shuttlePath} to {mapProto}");
mapManager.DeleteMap(shuttleMap);

View File

@@ -32,7 +32,7 @@ namespace Content.IntegrationTests.Tests
await server.WaitAssertion(() =>
{
config.SetCVar(CCVars.GameLobbyEnabled, true);
config.SetCVar(CCVars.EmergencyShuttleTransitTime, 1f);
config.SetCVar(CCVars.EmergencyShuttleMinTransitTime, 1f);
config.SetCVar(CCVars.EmergencyShuttleDockTime, 1f);
roundEndSystem.DefaultCooldownDuration = TimeSpan.FromMilliseconds(100);
@@ -116,7 +116,7 @@ namespace Content.IntegrationTests.Tests
await server.WaitAssertion(() =>
{
config.SetCVar(CCVars.GameLobbyEnabled, false);
config.SetCVar(CCVars.EmergencyShuttleTransitTime, CCVars.EmergencyShuttleTransitTime.DefaultValue);
config.SetCVar(CCVars.EmergencyShuttleMinTransitTime, CCVars.EmergencyShuttleMinTransitTime.DefaultValue);
config.SetCVar(CCVars.EmergencyShuttleDockTime, CCVars.EmergencyShuttleDockTime.DefaultValue);
roundEndSystem.DefaultCooldownDuration = TimeSpan.FromSeconds(30);

View File

@@ -78,6 +78,8 @@ namespace Content.IntegrationTests.Tests
await pairTracker.CleanReturnAsync();
}
const string TestMap = "Maps/bagel.yml";
/// <summary>
/// Loads the default map, runs it for 5 ticks, then assert that it did not change.
/// </summary>
@@ -91,13 +93,13 @@ namespace Content.IntegrationTests.Tests
MapId mapId = default;
// Load saltern.yml as uninitialized map, and save it to ensure it's up to date.
// Load bagel.yml as uninitialized map, and save it to ensure it's up to date.
server.Post(() =>
{
mapId = mapManager.CreateMap();
mapManager.AddUninitializedMap(mapId);
mapManager.SetMapPaused(mapId, true);
mapLoader.LoadMap(mapId, "Maps/bagel.yml");
mapLoader.LoadMap(mapId, TestMap);
mapLoader.SaveMap(mapId, "load save ticks save 1.yml");
});
@@ -145,6 +147,78 @@ namespace Content.IntegrationTests.Tests
TestContext.Error.WriteLine(twoTmp);
}
});
await server.WaitPost(() => mapManager.DeleteMap(mapId));
await pairTracker.CleanReturnAsync();
}
/// <summary>
/// Loads the same uninitialized map at slightly different times, and then checks that they are the same
/// when getting saved.
/// </summary>
/// <remarks>
/// Should ensure that entities do not perform randomization prior to initialization and should prevents
/// bugs like the one discussed in github.com/space-wizards/RobustToolbox/issues/3870. This test is somewhat
/// similar to <see cref="LoadSaveTicksSaveBagel"/> and <see cref="SaveLoadSave"/>, but neither of these
/// caught the mentioned bug.
/// </remarks>
[Test]
public async Task LoadTickLoadBagel()
{
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
var server = pairTracker.Pair.Server;
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
var mapManager = server.ResolveDependency<IMapManager>();
var userData = server.ResolveDependency<IResourceManager>().UserData;
MapId mapId = default;
const string fileA = "/load tick load a.yml";
const string fileB = "/load tick load b.yml";
string yamlA;
string yamlB;
// Load & save the first map
server.Post(() =>
{
mapId = mapManager.CreateMap();
mapManager.AddUninitializedMap(mapId);
mapManager.SetMapPaused(mapId, true);
mapLoader.LoadMap(mapId, TestMap);
mapLoader.SaveMap(mapId, fileA);
});
await server.WaitIdleAsync();
await using (var stream = userData.Open(new ResourcePath(fileA), FileMode.Open))
using (var reader = new StreamReader(stream))
{
yamlA = await reader.ReadToEndAsync();
}
server.RunTicks(5);
// Load & save the second map
server.Post(() =>
{
mapManager.DeleteMap(mapId);
mapManager.CreateMap(mapId);
mapManager.AddUninitializedMap(mapId);
mapManager.SetMapPaused(mapId, true);
mapLoader.LoadMap(mapId, TestMap);
mapLoader.SaveMap(mapId, fileB);
});
await server.WaitIdleAsync();
await using (var stream = userData.Open(new ResourcePath(fileB), FileMode.Open))
using (var reader = new StreamReader(stream))
{
yamlB = await reader.ReadToEndAsync();
}
Assert.That(yamlA, Is.EqualTo(yamlB));
await server.WaitPost(() => mapManager.DeleteMap(mapId));
await pairTracker.CleanReturnAsync();
}
}

View File

@@ -9,11 +9,12 @@ using Robust.Shared.Prototypes;
using Content.Server.Storage.Components;
using Content.Server.VendingMachines;
using Content.Server.VendingMachines.Restock;
using Content.Server.Wires;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.VendingMachines;
using Content.Shared.Wires;
using Content.Server.Wires;
namespace Content.IntegrationTests.Tests
{
@@ -188,7 +189,7 @@ namespace Content.IntegrationTests.Tests
VendingMachineComponent machineComponent;
VendingMachineRestockComponent restockRightComponent;
VendingMachineRestockComponent restockWrongComponent;
WiresComponent machineWires;
WiresPanelComponent machineWiresPanel;
var testMap = await PoolManager.CreateTestMap(pairTracker);
@@ -206,7 +207,7 @@ namespace Content.IntegrationTests.Tests
Assert.True(entityManager.TryGetComponent(machine, out machineComponent!), $"Machine has no {nameof(VendingMachineComponent)}");
Assert.True(entityManager.TryGetComponent(packageRight, out restockRightComponent!), $"Correct package has no {nameof(VendingMachineRestockComponent)}");
Assert.True(entityManager.TryGetComponent(packageWrong, out restockWrongComponent!), $"Wrong package has no {nameof(VendingMachineRestockComponent)}");
Assert.True(entityManager.TryGetComponent(machine, out machineWires!), $"Machine has no {nameof(WiresComponent)}");
Assert.True(entityManager.TryGetComponent(machine, out machineWiresPanel!), $"Machine has no {nameof(WiresPanelComponent)}");
var systemRestock = entitySystemManager.GetEntitySystem<VendingMachineRestockSystem>();
var systemMachine = entitySystemManager.GetEntitySystem<VendingMachineSystem>();
@@ -215,8 +216,9 @@ namespace Content.IntegrationTests.Tests
Assert.That(systemRestock.TryAccessMachine(packageRight, restockRightComponent, machineComponent, user, machine), Is.False, "Right package is able to restock without opened access panel");
Assert.That(systemRestock.TryAccessMachine(packageWrong, restockWrongComponent, machineComponent, user, machine), Is.False, "Wrong package is able to restock without opened access panel");
var systemWires = entitySystemManager.GetEntitySystem<WiresSystem>();
// Open the panel.
machineWires.IsPanelOpen = true;
systemWires.TogglePanel(machine, machineWiresPanel, true);
// Test that the right package works for the right machine.
Assert.That(systemRestock.TryAccessMachine(packageRight, restockRightComponent, machineComponent, user, machine), Is.True, "Correct package is unable to restock with access panel opened");

View File

@@ -418,8 +418,31 @@ namespace Content.Server.Database
public string? Name { get; set; } = default!;
}
// Used by SS14.Admin
public interface IBanCommon<TUnban> where TUnban : IUnbanCommon
{
int Id { get; set; }
Guid? UserId { get; set; }
(IPAddress, int)? Address { get; set; }
byte[]? HWId { get; set; }
DateTime BanTime { get; set; }
DateTime? ExpirationTime { get; set; }
string Reason { get; set; }
Guid? BanningAdmin { get; set; }
TUnban? Unban { get; set; }
}
// Used by SS14.Admin
public interface IUnbanCommon
{
int Id { get; set; }
int BanId { get; set; }
Guid? UnbanningAdmin { get; set; }
DateTime UnbanTime { get; set; }
}
[Table("server_ban")]
public class ServerBan
public class ServerBan : IBanCommon<ServerUnban>
{
public int Id { get; set; }
public Guid? UserId { get; set; }
@@ -439,7 +462,7 @@ namespace Content.Server.Database
}
[Table("server_unban")]
public class ServerUnban
public class ServerUnban : IUnbanCommon
{
[Column("unban_id")] public int Id { get; set; }
@@ -489,7 +512,7 @@ namespace Content.Server.Database
}
[Table("server_role_ban")]
public sealed class ServerRoleBan
public sealed class ServerRoleBan : IBanCommon<ServerRoleUnban>
{
public int Id { get; set; }
public Guid? UserId { get; set; }
@@ -509,7 +532,7 @@ namespace Content.Server.Database
}
[Table("server_role_unban")]
public sealed class ServerRoleUnban
public sealed class ServerRoleUnban : IUnbanCommon
{
[Column("role_unban_id")] public int Id { get; set; }

View File

@@ -1,5 +1,7 @@
using System.Linq;
using Content.Server.Administration.Systems;
using Content.Server.AME.Components;
using Content.Server.Chat.Managers;
using Content.Server.Explosion.EntitySystems;
using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
@@ -27,6 +29,8 @@ namespace Content.Server.AME
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IChatManager _chat = default!;
public AMEControllerComponent? MasterController => _masterController;
private readonly List<AMEShieldComponent> _cores = new();
@@ -133,10 +137,21 @@ namespace Content.Server.AME
if (instability != 0)
{
overloading = true;
var integrityCheck = 100;
foreach(AMEShieldComponent core in _cores)
{
var oldIntegrity = core.CoreIntegrity;
core.CoreIntegrity -= instability;
if (oldIntegrity > 95
&& core.CoreIntegrity <= 95
&& core.CoreIntegrity < integrityCheck)
integrityCheck = core.CoreIntegrity;
}
// Admin alert
if (integrityCheck != 100 && _masterController != null)
_chat.SendAdminAlert($"AME overloading: {_entMan.ToPrettyString(_masterController.Owner)}");
}
}
// Note the float conversions. The maths will completely fail if not done using floats.

View File

@@ -1,5 +1,7 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Systems;
using Content.Server.Chat.Managers;
using Content.Server.Mind.Components;
using Content.Server.NodeContainer;
using Content.Server.Power.Components;
@@ -20,6 +22,7 @@ namespace Content.Server.AME.Components
[Dependency] private readonly IEntityManager _entities = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IChatManager _chat = default!;
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(AMEControllerUiKey.Key);
private bool _injecting;
@@ -183,6 +186,10 @@ namespace Content.Server.AME.Components
if (msg.Button == UiButton.ToggleInjection)
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{_entities.ToPrettyString(mindComponent.Owner):player} has set the AME to {humanReadableState}");
// Admin alert
if (GetCoreCount() * 2 == InjectionAmount - 2 && msg.Button == UiButton.IncreaseFuel)
_chat.SendAdminAlert(player, $"increased AME over safe limit to {InjectionAmount}", mindComponent);
}
GetAMENodeGroup()?.UpdateCoreVisuals();

View File

@@ -1,23 +0,0 @@
using Content.Shared.Damage;
namespace Content.Server.Abilities.Boxer
{
/// <summary>
/// Added to the boxer on spawn.
/// </summary>
[RegisterComponent]
public sealed class BoxerComponent : Component
{
[DataField("modifiers", required: true)]
public DamageModifierSet UnarmedModifiers = default!;
[DataField("rangeBonus")]
public float RangeBonus = 1.5f;
/// <summary>
/// Damage modifier with boxing glove stam damage.
/// </summary>
[DataField("boxingGlovesModifier")]
public float BoxingGlovesModifier = 1.75f;
}
}

View File

@@ -1,11 +0,0 @@
using Content.Shared.Damage;
namespace Content.Server.Abilities.Boxer
{
/// <summary>
/// Boxer gets a bonus for these, and their fists, but not other unarmed weapons.
/// </summary>
[RegisterComponent]
public sealed class BoxingGlovesComponent : Component
{}
}

View File

@@ -1,39 +0,0 @@
using Content.Shared.Damage.Events;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Containers;
namespace Content.Server.Abilities.Boxer
{
public sealed class BoxingSystem : EntitySystem
{
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BoxerComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<BoxerComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<BoxingGlovesComponent, StaminaMeleeHitEvent>(OnStamHit);
}
private void OnInit(EntityUid uid, BoxerComponent component, ComponentInit args)
{
if (TryComp<MeleeWeaponComponent>(uid, out var meleeComp))
meleeComp.Range *= component.RangeBonus;
}
private void OnMeleeHit(EntityUid uid, BoxerComponent component, MeleeHitEvent args)
{
args.ModifiersList.Add(component.UnarmedModifiers);
}
private void OnStamHit(EntityUid uid, BoxingGlovesComponent component, StaminaMeleeHitEvent args)
{
if (!_containerSystem.TryGetContainingContainer(uid, out var equipee))
return;
if (TryComp<BoxerComponent>(equipee.Owner, out var boxer))
args.Multiplier *= boxer.BoxingGlovesModifier;
}
}
}

View File

@@ -5,19 +5,20 @@ using System.Text;
using Content.Server.Database;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
namespace Content.Server.Administration.Commands
{
[AdminCommand(AdminFlags.Ban)]
public sealed class BanCommand : IConsoleCommand
public sealed class BanCommand : LocalizedCommands
{
public string Command => "ban";
public string Description => Loc.GetString("cmd-ban-desc");
public string Help => Loc.GetString("cmd-ban-help", ("Command", Command));
[Dependency] private readonly IConfigurationManager _cfg = default!;
public async void Execute(IConsoleShell shell, string argStr, string[] args)
public override string Command => "ban";
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player as IPlayerSession;
var plyMgr = IoCManager.Resolve<IPlayerManager>();
@@ -54,7 +55,7 @@ namespace Content.Server.Administration.Commands
var located = await locator.LookupIdByNameOrIdAsync(target);
if (located == null)
{
shell.WriteError(Loc.GetString("cmd-ban-player"));
shell.WriteError(LocalizationManager.GetString("cmd-ban-player"));
return;
}
@@ -64,7 +65,7 @@ namespace Content.Server.Administration.Commands
if (player != null && player.UserId == targetUid)
{
shell.WriteLine(Loc.GetString("cmd-ban-self"));
shell.WriteLine(LocalizationManager.GetString("cmd-ban-self"));
return;
}
@@ -100,43 +101,42 @@ namespace Content.Server.Administration.Commands
var response = new StringBuilder($"Banned {target} with reason \"{reason}\"");
response.Append(expires == null ?
" permanently."
: $" until {expires}");
response.Append(expires == null ? " permanently." : $" until {expires}");
shell.WriteLine(response.ToString());
if (plyMgr.TryGetSessionById(targetUid, out var targetPlayer))
{
targetPlayer.ConnectedClient.Disconnect(banDef.DisconnectMessage);
var message = banDef.FormatBanMessage(_cfg, LocalizationManager);
targetPlayer.ConnectedClient.Disconnect(message);
}
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
if (args.Length == 1)
{
var playerMgr = IoCManager.Resolve<IPlayerManager>();
var options = playerMgr.ServerSessions.Select(c => c.Name).OrderBy(c => c).ToArray();
return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-ban-hint"));
return CompletionResult.FromHintOptions(options, LocalizationManager.GetString("cmd-ban-hint"));
}
if (args.Length == 2)
return CompletionResult.FromHint(Loc.GetString("cmd-ban-hint-reason"));
return CompletionResult.FromHint(LocalizationManager.GetString("cmd-ban-hint-reason"));
if (args.Length == 3)
{
var durations = new CompletionOption[]
{
new("0", Loc.GetString("cmd-ban-hint-duration-1")),
new("1440", Loc.GetString("cmd-ban-hint-duration-2")),
new("4320", Loc.GetString("cmd-ban-hint-duration-3")),
new("10080", Loc.GetString("cmd-ban-hint-duration-4")),
new("20160", Loc.GetString("cmd-ban-hint-duration-5")),
new("43800", Loc.GetString("cmd-ban-hint-duration-6")),
new("0", LocalizationManager.GetString("cmd-ban-hint-duration-1")),
new("1440", LocalizationManager.GetString("cmd-ban-hint-duration-2")),
new("4320", LocalizationManager.GetString("cmd-ban-hint-duration-3")),
new("10080", LocalizationManager.GetString("cmd-ban-hint-duration-4")),
new("20160", LocalizationManager.GetString("cmd-ban-hint-duration-5")),
new("43800", LocalizationManager.GetString("cmd-ban-hint-duration-6")),
};
return CompletionResult.FromHintOptions(durations, Loc.GetString("cmd-ban-hint-duration"));
return CompletionResult.FromHintOptions(durations, LocalizationManager.GetString("cmd-ban-hint-duration"));
}
return CompletionResult.Empty;

View File

@@ -27,7 +27,7 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
{
_netManager.RegisterNetMessage<GamePrototypeLoadMessage>(ClientLoadsPrototype);
_netManager.Connected += NetManagerOnConnected;
//_replay.OnRecordingStarted += OnStartReplayRecording;
_replay.OnRecordingStarted += OnStartReplayRecording;
}
private void OnStartReplayRecording((MappingDataNode, List<object>) initReplayData)

View File

@@ -33,7 +33,7 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
_cfgManager.OnValueChanged(CCVars.ResourceUploadingStoreEnabled, value => StoreUploaded = value, true);
AutoDelete(_cfgManager.GetCVar(CCVars.ResourceUploadingStoreDeletionDays));
//_replay.OnRecordingStarted += OnStartReplayRecording;
_replay.OnRecordingStarted += OnStartReplayRecording;
}
private void OnStartReplayRecording((MappingDataNode, List<object>) initReplayData)

View File

@@ -83,6 +83,15 @@ namespace Content.Server.Administration.Systems
}
}
public PlayerInfo? GetCachedPlayerInfo(NetUserId? netUserId)
{
if (netUserId == null)
return null;
_playerList.TryGetValue(netUserId.Value, out var value);
return value ?? null;
}
private void OnIdentityChanged(IdentityChangedEvent ev)
{
if (!TryComp<ActorComponent>(ev.CharacterEntity, out var actor))

View File

@@ -35,7 +35,7 @@ public sealed class AdminTestArenaSystem : EntitySystem
}
ArenaMap[admin.UserId] = _mapManager.GetMapEntityId(_mapManager.CreateMap());
var grids = _map.LoadMap(Comp<MapComponent>(ArenaMap[admin.UserId]).WorldMap, ArenaMapPath);
var grids = _map.LoadMap(Comp<MapComponent>(ArenaMap[admin.UserId]).MapId, ArenaMapPath);
ArenaGrid[admin.UserId] = grids.Count == 0 ? null : grids[0];
return (ArenaMap[admin.UserId], ArenaGrid[admin.UserId]);

View File

@@ -6,6 +6,7 @@ using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.Cargo.Components;
using Content.Server.Cargo.Systems;
using Content.Server.Damage.Components;
using Content.Server.Doors.Components;
using Content.Server.Doors.Systems;
using Content.Server.Hands.Components;
@@ -123,7 +124,7 @@ public sealed partial class AdminVerbSystem
args.Verbs.Add(rejuvenate);
}
if (!_godmodeSystem.HasGodmode(args.Target))
if (!HasComp<GodmodeComponent>(args.Target))
{
Verb makeIndestructible = new()
{
@@ -695,7 +696,7 @@ public sealed partial class AdminVerbSystem
{
if (_adminManager.HasAdminFlag(player, AdminFlags.Mapping))
{
if (_mapManager.IsMapPaused(map.WorldMap))
if (_mapManager.IsMapPaused(map.MapId))
{
Verb unpauseMap = new()
{
@@ -704,7 +705,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/AdminActions/play.png")),
Act = () =>
{
_mapManager.SetMapPaused(map.WorldMap, false);
_mapManager.SetMapPaused(map.MapId, false);
},
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-unpause-map-description"),
@@ -721,7 +722,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/AdminActions/pause.png")),
Act = () =>
{
_mapManager.SetMapPaused(map.WorldMap, true);
_mapManager.SetMapPaused(map.MapId, true);
},
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-pause-map-description"),

View File

@@ -109,6 +109,8 @@ namespace Content.Server.Administration.Systems
{
_webhookUrl = url;
RaiseNetworkEvent(new BwoinkDiscordRelayUpdated(!string.IsNullOrWhiteSpace(url)));
if (url == string.Empty)
return;
@@ -395,13 +397,11 @@ namespace Content.Server.Administration.Systems
_messageQueues[msg.UserId].Enqueue(GenerateAHelpMessage(senderSession.Name, str, !personalChannel, admins.Count == 0));
}
if (admins.Count != 0)
if (admins.Count != 0 || sendsWebhook)
return;
// No admin online, let the player know
var systemText = sendsWebhook ?
Loc.GetString("bwoink-system-starmute-message-no-other-users-webhook") :
Loc.GetString("bwoink-system-starmute-message-no-other-users");
var systemText = Loc.GetString("bwoink-system-starmute-message-no-other-users");
var starMuteMsg = new BwoinkTextMessage(message.UserId, SystemUserId, systemText);
RaiseNetworkEvent(starMuteMsg, senderSession.ConnectedClient);
}

View File

@@ -19,7 +19,7 @@ namespace Content.Server.Alert.Click
if (entManager.TryGetComponent(player, out PilotComponent? pilotComponent) &&
pilotComponent.Console != null)
{
entManager.System<ShuttleConsoleSystem>().RemovePilot(pilotComponent);
entManager.System<ShuttleConsoleSystem>().RemovePilot(player, pilotComponent);
}
}
}

View File

@@ -1,3 +1,4 @@
using Content.Server.Power.Components;
using Content.Server.Station.Systems;
using Content.Shared.AlertLevel;
using Robust.Server.GameObjects;
@@ -13,6 +14,7 @@ public sealed class AlertLevelDisplaySystem : EntitySystem
{
SubscribeLocalEvent<AlertLevelChangedEvent>(OnAlertChanged);
SubscribeLocalEvent<AlertLevelDisplayComponent, ComponentInit>(OnDisplayInit);
SubscribeLocalEvent<AlertLevelDisplayComponent, PowerChangedEvent>(OnPowerChanged);
}
private void OnAlertChanged(AlertLevelChangedEvent args)
@@ -23,7 +25,7 @@ public sealed class AlertLevelDisplaySystem : EntitySystem
}
}
private void OnDisplayInit(EntityUid uid, AlertLevelDisplayComponent component, ComponentInit args)
private void OnDisplayInit(EntityUid uid, AlertLevelDisplayComponent alertLevelDisplay, ComponentInit args)
{
if (TryComp(uid, out AppearanceComponent? appearance))
{
@@ -34,4 +36,11 @@ public sealed class AlertLevelDisplaySystem : EntitySystem
}
}
}
private void OnPowerChanged(EntityUid uid, AlertLevelDisplayComponent alertLevelDisplay, ref PowerChangedEvent args)
{
if (!TryComp(uid, out AppearanceComponent? appearance))
return;
_appearance.SetData(uid, AlertLevelDisplay.Powered, args.Powered, appearance);
}
}

View File

@@ -157,15 +157,14 @@ public sealed partial class AnomalySystem
Audio.PlayPvs(component.GeneratingFinishedSound, uid);
var message = Loc.GetString("anomaly-generator-announcement");
_radio.SendRadioMessage(uid, message, _prototype.Index<RadioChannelPrototype>(component.ScienceChannel));
_radio.SendRadioMessage(uid, message, _prototype.Index<RadioChannelPrototype>(component.ScienceChannel), uid);
}
private void UpdateGenerator()
{
foreach (var (active, gen) in EntityQuery<GeneratingAnomalyGeneratorComponent, AnomalyGeneratorComponent>())
var query = EntityQueryEnumerator<GeneratingAnomalyGeneratorComponent, AnomalyGeneratorComponent>();
while (query.MoveNext(out var ent, out var active, out var gen))
{
var ent = active.Owner;
if (Timing.CurTime < active.EndTime)
continue;
active.AudioStream?.Stop();

View File

@@ -27,41 +27,45 @@ public sealed partial class AnomalySystem
private void OnScannerAnomalyShutdown(ref AnomalyShutdownEvent args)
{
foreach (var component in EntityQuery<AnomalyScannerComponent>())
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
_ui.TryCloseAll(component.Owner, AnomalyScannerUiKey.Key);
_ui.TryCloseAll(uid, AnomalyScannerUiKey.Key);
}
}
private void OnScannerAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
{
foreach (var component in EntityQuery<AnomalyScannerComponent>())
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(component.Owner, component);
UpdateScannerUi(uid, component);
}
}
private void OnScannerAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
{
foreach (var component in EntityQuery<AnomalyScannerComponent>())
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(component.Owner, component);
UpdateScannerUi(uid, component);
}
}
private void OnScannerAnomalyHealthChanged(ref AnomalyHealthChangedEvent args)
{
foreach (var component in EntityQuery<AnomalyScannerComponent>())
var query = EntityQueryEnumerator<AnomalyScannerComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ScannedAnomaly != args.Anomaly)
continue;
UpdateScannerUi(component.Owner, component);
UpdateScannerUi(uid, component);
}
}

View File

@@ -100,10 +100,9 @@ public sealed partial class AnomalySystem
private void OnVesselAnomalyShutdown(ref AnomalyShutdownEvent args)
{
foreach (var component in EntityQuery<AnomalyVesselComponent>())
var query = EntityQueryEnumerator<AnomalyVesselComponent>();
while (query.MoveNext(out var ent, out var component))
{
var ent = component.Owner;
if (args.Anomaly != component.Anomaly)
continue;
@@ -118,9 +117,9 @@ public sealed partial class AnomalySystem
private void OnVesselAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
{
foreach (var component in EntityQuery<AnomalyVesselComponent>())
var query = EntityQueryEnumerator<AnomalyVesselComponent>();
while (query.MoveNext(out var ent, out var component))
{
var ent = component.Owner;
if (args.Anomaly != component.Anomaly)
continue;
@@ -171,9 +170,9 @@ public sealed partial class AnomalySystem
private void UpdateVessels()
{
foreach (var vessel in EntityQuery<AnomalyVesselComponent>())
var query = EntityQueryEnumerator<AnomalyVesselComponent>();
while (query.MoveNext(out var vesselEnt, out var vessel))
{
var vesselEnt = vessel.Owner;
if (vessel.Anomaly is not { } anomUid)
continue;

Some files were not shown because too many files have changed in this diff Show More