Compare commits

...

532 Commits

Author SHA1 Message Date
Ed
c20ac07c5b constructuni 2025-04-10 21:20:25 +03:00
Ed
fb5ea85a36 Update t2_magma_caves.yml 2025-04-10 21:19:09 +03:00
Ed
bcfa724f36 Update walls.yml 2025-04-10 21:17:26 +03:00
Ed
dd687e8eaa Update natural.yml 2025-04-10 21:17:09 +03:00
Ed
8ce9d7643c Update tables.yml 2025-04-10 21:16:18 +03:00
Ed
fdaa9a0fa3 a 2025-04-10 00:16:20 +03:00
Ed
0decd375e4 Birch tree (#1154)
* birch

* wooden birch log and planks

* birch tile crafting

* add birch to worldgen

* Update grasslands.yml

* wooden planks (any)

* universal wood crafting

* birch wall
2025-04-09 15:54:38 +03:00
creamybag
d201dc0695 Beards (#1153)
* beards

* fix

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-04-08 17:40:01 +03:00
Ed
5b3688fc89 deep Comoss ocean (#1150)
* deep Comoss ocean

* Update migration.yml
2025-04-08 17:39:23 +03:00
Ed
f7b5e40f23 fix master (#1152) 2025-04-08 17:24:56 +03:00
Viator-MV
d0a185cca0 Empties (#1151)
добавлены пустые пресеты карт 2 биомов со всеми нужными компонентами
2025-04-08 16:04:45 +03:00
Ed
f7f7feb837 Marble update (#1146)
* all marble resprite

* Update meta.json

* marble table

* marble natural wall

* marble cave floor

* marble material

* marble small floor bricks

* marble in demiplanes
2025-04-07 21:27:20 +03:00
creamybag
06863d9986 StrawHat (#1132) 2025-04-07 17:15:56 +03:00
creamybag
d5ce5d9f37 Syurko update (#1148)
* Syurko\

* Translation editsЭ

* fix
2025-04-07 17:15:21 +03:00
Ed
56299c62d6 fix 2025-04-07 01:36:55 +03:00
Ed
e77645d9d6 old tiles YES (#1144) 2025-04-07 01:34:45 +03:00
Ed
d81dbe4c20 Update tiefling.yml 2025-04-06 20:32:52 +03:00
Nim
d3be599ccb carcat tail (#1141) 2025-04-06 17:26:36 +03:00
Ed
4efbb6f307 Update sell.yml 2025-04-06 15:04:18 +03:00
Ed
b4ab1a714c Update CP14SharedFarmingSystem.Interactions.cs 2025-04-06 14:05:04 +03:00
Ed
b04b95cae4 farm buff 2025-04-06 13:59:50 +03:00
Viator-MV
32b077af63 update (#1137) 2025-04-05 14:42:51 +03:00
Ed
52c06249ea f (#1136) 2025-04-05 13:46:23 +03:00
Ed
bb2fbd1baf Update secret_weights.yml 2025-04-05 12:43:46 +03:00
Ed
e308eec703 Hoe dirt preparing (#1135)
* seedbed returns

* modular hoe!

* hoe gameplay

* remove onion seeds
2025-04-05 01:00:39 +03:00
Nim
d5e54ce744 minor edits (#1130) 2025-04-04 17:30:41 +03:00
Nim
c91a6c3f59 Adapted watchers (#1129)
* watcher

* co

* sadly
2025-04-04 17:30:26 +03:00
Ed
b66ee390a6 Dynamic demiplane weather + farming hotfix (#1131)
* dynamic demiplane weather

* add skeleton sprite

* hotfix farming

* Update wheat.yml
2025-04-04 10:35:48 +03:00
Nim
e125605f25 fix constructions (#1125) 2025-04-03 17:13:39 +03:00
creamybag
dd9aea718c The guildmaster's rapier was not given out in the round. (#1123)
* fix

* fix2
2025-04-03 15:34:35 +03:00
Ed
48831380b4 Give some love to farming (#1124)
* give some love to farming

* Queryptimization

* Fuck soil!!!

* fuck soil in prototypes!

* seeds improve

* partial merge wild and farm

* some strange fix

* plant kills refactor, add compost

* fix compost

* Update migration.yml

* rain can watering plants

* sage update

* Update seeds.yml

* sage smoking update

* Update seeds.yml
2025-04-03 15:29:08 +03:00
creamybag
16c4f8be53 Furcoat carcat (#1122)
* FurcoatCat

* fix
2025-04-03 10:00:27 +03:00
Nim
879792be09 Fix mana damage (#1106)
* fix mana damage

* mana potion

* fix rev

* ehh

* hmm

* nop

* Update target_effect_creation_on_water.yml

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-04-02 16:11:48 +03:00
Ed
fa7aacc103 Update Dev.toml 2025-04-01 23:08:46 +03:00
Ed
937851a72c Update Dev.toml 2025-04-01 21:50:20 +03:00
Ed
504adb6738 Fools day end (#1115)
* Revert "April fools fix (#1113)"

This reverts commit e2dec03cbb.

* Revert "April fools fix (#1113)"

This reverts commit e2dec03cbb.

* Revert "Update secret_weights.yml"

This reverts commit 256476b576.

* Update Dev.toml
2025-04-01 21:40:43 +03:00
Nim
b9d191c7e4 Fix bandage (#1112)
* CP14Biological

* storePositionBuy
2025-04-01 11:26:17 +03:00
Ed
1573d1ee81 ru 2025-04-01 11:16:33 +03:00
Deserty0
e2dec03cbb April fools fix (#1113)
* fix

* fuck

* фы
2025-04-01 08:41:35 +03:00
Ed
6e96943df5 Merge branch 'master' of https://github.com/crystallpunk-14/crystall-punk-14 2025-04-01 00:11:16 +03:00
Ed
256476b576 Update secret_weights.yml 2025-04-01 00:10:51 +03:00
Ed
655cba7674 April 2025 fool (#1109)
* Новый геймплей кузнеца и алхимика (#1084)

* anvilvat

Vat is now anvil

* deleted layers

* я даун

* тесты скажите что не так

* fuck documentation

* finally ok

* Alloys

* test not give up

* fix tests mk2 and anvil rename

* anvilgril

* FUCK TABS

* cattle

* meow

* the чистка

* armor

* fuck

* Update tags.yml

* ДА КАК ЭТО Я ВООБЩЕ БЛЯТЬ МОГ СДЕЛАТЬ НАХУЙ

* garde

* yes

* сохранить забыл

* голова потекла

* упс

* b

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>

* Viator's april fools (#1091)

* uno reverse

* comos!

* desery special

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>

* [April Fools] Mob Pumpkin King!!! (#1092)

* MobPumpkinKing

* generation

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>

* asdsasdd (#1110)

* wait what???

* some fixes

* Поправка локализации на завтра (#1108)

* локаль

* упс

* Create TOPSECRET.xml

* Update entry.yml

* Update TOPSECRET.xml

* ч

---------

Co-authored-by: Deserty0 <86846189+Deserty0@users.noreply.github.com>
Co-authored-by: Viator-MV <egor44148@gmail.com>
Co-authored-by: Nim <128169402+Nimfar11@users.noreply.github.com>
2025-04-01 00:05:46 +03:00
Ed
edc67dd280 Storm nerf (#1107)
* weather lightning nerf

* port storm weather to gamerule events

* fix
2025-03-31 23:46:21 +03:00
creamybag
05de87e9e9 Merge pull request #1090 from creamybag/toadslippers
Frogerge
2025-03-31 23:01:14 +03:00
github-actions[bot]
e4bd418c45 @kvant8 has signed the CLA in crystallpunk-14/crystall-punk-14#1105 2025-03-31 17:52:57 +00:00
Ed
d6943c762c Merge pull request #1102 from ArZarLordOfMango/water
[Fix]CP14FloorWaterOptimized fix
2025-03-31 15:48:31 +03:00
ArZarLordOfMango
6ac00528e9 fix 2025-03-31 14:05:17 +02:00
ArZarLordOfMango
5ae9df1f0b water 2025-03-31 13:36:48 +02:00
Ed
41433d1414 Merge pull request #1100 from crystallpunk-14/ed-311-03-2025-upstream-2
Stable upstream sync
2025-03-31 13:15:22 +03:00
creamybag
4d1094cd6b scars (#1094) 2025-03-31 13:05:03 +03:00
Nim
2e85ac0263 Magic damage (#1047)
* magic damage

* mana-healing potion

* slimes

* ManaDepletion

* Examinable

* color
2025-03-31 13:03:42 +03:00
Ed
9d6e023bd0 Merge remote-tracking branch 'upstream/stable' into ed-311-03-2025-upstream-2
# Conflicts:
#	Content.Client/Administration/AdminNameOverlay.cs
#	Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml
#	Content.Client/Guidebook/Controls/GuideReagentReaction.xaml
#	Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
#	Content.Client/SubFloor/SubFloorHideSystem.cs
#	Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
#	Content.Server/Antag/AntagSelectionSystem.cs
#	Content.Server/Cloning/CloningSystem.cs
#	Content.Server/GameTicking/Rules/Components/ParadoxCloneRuleComponent.cs
#	Content.Server/GameTicking/Rules/ParadoxCloneRuleSystem.cs
#	Content.Server/Roles/ParadoxCloneRoleComponent.cs
#	Content.Shared.Database/LogType.cs
#	Content.Shared/CCVar/CCVars.Interface.cs
#	Content.Shared/Cloning/CloningEvents.cs
#	Content.Shared/Cloning/CloningSettingsPrototype.cs
#	Content.Shared/Humanoid/NamingSystem.cs
#	Content.Shared/Humanoid/Prototypes/SpeciesPrototype.cs
#	Content.Shared/Light/Components/SunShadowCycleComponent.cs
#	Content.Shared/Storage/StorageComponent.cs
#	Resources/Changelog/Admin.yml
#	Resources/Changelog/Changelog.yml
#	Resources/Credits/GitHub.txt
#	Resources/Locale/en-US/paradox-clone/role.ftl
#	Resources/Maps/bagel.yml
#	Resources/Maps/loop.yml
#	Resources/Prototypes/Chemistry/mixing_types.yml
#	Resources/Prototypes/Datasets/Names/last.yml
#	Resources/Prototypes/Entities/Effects/puddle.yml
#	Resources/Prototypes/Entities/Mobs/Player/clone.yml
#	Resources/Prototypes/Entities/Mobs/Species/base.yml
#	Resources/Prototypes/Entities/Objects/Deliveries/deliveries_tables.yml
#	Resources/Prototypes/Entities/Objects/Devices/pda.yml
#	Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml
#	Resources/Prototypes/GameRules/events.yml
#	Resources/Prototypes/Maps/Pools/default.yml
#	Resources/Prototypes/Objectives/paradoxClone.yml
#	Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml
#	Resources/Textures/Clothing/Eyes/Glasses/jensen.rsi/equipped-EYES-arachnid.png
2025-03-31 12:41:37 +03:00
Ed
987f00a493 s (#1096) 2025-03-30 20:31:37 +03:00
Ed
8a479c4e5e Update weather.yml 2025-03-30 18:43:07 +03:00
Ed
011e90a5d1 Weather gameplay effects (#1089)
* pipa

* Weather effects

* Weather in demiplanes!

* demiplane enter roofs

* Demiplane ruins

* Update weather.yml

* Update paper.yml

* Update paper.yml
2025-03-30 17:27:05 +03:00
Ed
abdd46c7d5 Random bugfixes and balance (#1088)
* shared magic energy examine

* fix #1067

* fix #984

* nerf slimes

* fireSpread nerf

* slimes demiplane examine + remove whistler
2025-03-29 22:08:58 +03:00
metalgearsloth
0c98ad8b38 Fix 1x1 storage windows (#35985) 2025-03-29 19:57:28 +01:00
ScarKy0
89ea21bc31 Fix admeme hand teleproter. (#36147)
* init

* changes
2025-03-29 17:51:46 +03:00
ArZarLordOfMango
f81f7a836e mana-fix (#1082) 2025-03-29 16:57:13 +03:00
F8ctor
03e0d66083 No life mobs (#1072)
* Slimeeeee!

* SimpleSpaceMobNoLifeBase

* No-no-no mr. Skeletik, you not alive

* Delete "bug"

* Revert "Delete "bug""

This reverts commit 4ce64f1cbc.

* Revert "No-no-no mr. Skeletik, you not alive"

This reverts commit f0c878c6a3.

* return, I'll see what's wrong

* Fix

* [ ] Work complete
2025-03-29 16:53:34 +03:00
Ed
fddbb010cf Skill requirements (#1085)
* prerequites refactor

* tiefling only spells

* metamagic update

* sort trying

* goblin speed port
2025-03-29 16:50:14 +03:00
ScarKy0
87be2dde27 Fix codermins appearing as red in-game OOC (#36148)
init
2025-03-29 12:33:25 +01:00
Ed
2248e2ad5c Merge branch 'master' of https://github.com/crystallpunk-14/crystall-punk-14 2025-03-29 14:24:31 +03:00
Ed
6706a14163 secret polymorph spell 2025-03-29 14:22:53 +03:00
Deserty0
baa48eb0e5 the aer attack (#1081) 2025-03-28 20:15:36 +03:00
Ed
d3f70aee7e Minor Skill Tree rebalance (#1080)
* save: no for visual effect

* some tweaks

* Update healing.yml
2025-03-28 17:45:19 +03:00
ArZarLordOfMango
f337fde3d9 paper fix (#1079) 2025-03-28 16:14:12 +03:00
Link
b9fad6cbd4 Mana no longer regenerates after death (#1027)
* Update CP14MagicEnergySystem.Draw.cs

* :nerd:

* Update CP14MagicEnergySystem.Draw.cs

* Update CP14MagicEnergySystem.Draw.cs

* oops...

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-03-28 11:10:42 +03:00
Nim
532f44eb3c coloured chainmail (#1077) 2025-03-28 11:09:39 +03:00
PJBot
e98df217e2 Automatic changelog update 2025-03-27 17:44:04 +00:00
lzk
8f049f174d make admin interacts with storages silent (#35417)
* make admin interacts with storages silent

* review

* silent insert and transfer

* i love code

---------

Co-authored-by: ScarKy0 <scarky0@onet.eu>
2025-03-27 18:42:57 +01:00
PJBot
f9320aacd7 Automatic changelog update 2025-03-27 17:20:43 +00:00
SlamBamActionman
5c505958a7 Add a new poster (#36104)
* Poster

* THAT tortilla...

* roombareview
2025-03-27 18:19:36 +01:00
Chaoticaa
db65e3241e Updates to Hydroponic sprites (#35004)
* changes to some hydroponics plant sprites

* tomato changes

* added tomatoes and further changes

* added tomatoes and adjustments

* added tomatoes and adjustments

* added apples and meatwheat

* watermelon + adjustments

* sugarcane

* blood tomatoes & pumpkin harvest

* final changes for a while

* poppy harvest repaint

* smoller melon + holy melon stages

* final changes + attributions added to json files

* oops

* changes

* changes x2

* egg success + tree changes and additions

* bagel mistake

* lemon lime garlic fly

* grapes and stuff

* Potate

* peas and attributes

* more veg while my monitor flashbangs me repeatedly trying to find source links

* soyyyyyyy

* eggplant and berries yuuumm

* corn life

* grape disaster

* my computer is slow

* Pray

---------

Co-authored-by: Your Name <[you@example.com])>
Co-authored-by: beck-thompson <beck314159@hotmail.com>
2025-03-27 10:11:02 -07:00
PJBot
56e0cb642a Automatic changelog update 2025-03-27 17:05:33 +00:00
slarticodefast
7c44038f63 Add paradox clone to admin antag control (#36105)
* make paradox clone receive the original's objectives

* antag control verb

* rename verb
2025-03-27 10:04:25 -07:00
Ed
2a524b4b4b Update CP14ClientSkillSystem.cs 2025-03-27 18:24:26 +03:00
Ed
735b4f5c7b Merge branch 'master' of https://github.com/crystallpunk-14/crystall-punk-14 2025-03-27 17:59:30 +03:00
Ed
4b13d876e8 Update skill_tree.yml 2025-03-27 17:53:25 +03:00
Nim
afea64252b Wrench sprite and fix mask (#1075)
* wrench

* stored

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-03-27 16:37:11 +02:00
Ed
1e36a61339 Skill progression system [Draft] (#1056)
* fuck all

* clean up

* remove knowledge books

* Update base.yml

* cl

* fix #991

* fix

* Update subgamemodes.yml

* manual migration + recipes fix

* Update comoss.yml

* setup data

* setup skills systems

* more blacksmithing skills

* Update base.yml

* Create CP14SkillEffectAction.cs

* skill button returns

* base graph UI window

* skill tree drawing

* UI improve

* pyro setup

* skill trees selection, dragging control

* refactor skill system: rename Skills to LearnedSkills, add experience tracking and learning logic

* Create available.png

* skill description generation setup

* auto parsing skill names and descriptions

* Hydrosophistry

* water light fire and metamagic ported to skill tre

* ice dagger spell returns

* Update ice_dagger.yml

* delete old files

* Update modular_garde.yml

* ice arrow spell

* link graph with parallax

* show experience counter

* polish

* puf

* p

* pipap

* finally ready to merg?

* fix

* fix 2
2025-03-27 17:20:20 +03:00
creamybag
6a6350a827 Blacksmith's gloves (#1045)
* gloves

* fix
2025-03-27 17:02:52 +03:00
creamybag
9271500fe4 mime (#1074) 2025-03-27 17:02:35 +03:00
PJBot
f4adb0bdb3 Automatic changelog update 2025-03-27 06:27:21 +00:00
Centronias
f45794002b Raw meatball cooks into cooked meatball (#36003)
meatballs can be cooked on their own
2025-03-26 23:26:13 -07:00
metalgearsloth
da2c9510b2 Update submodule to v250.0.0 (#36108) 2025-03-27 15:29:14 +11:00
Errant
e4a5043d4e Overlay stack sorting fix (#36103)
* round float before sorting

* weh
2025-03-26 21:40:13 +01:00
ScarKy0
5bedf1761a 1984 the unsafe gift from smuggler stashes (#36102)
1984
2025-03-26 20:42:08 +01:00
Tayrtahn
bf17f85ced Cleanup AdminVerbSystem (#36099)
* Fix 3 warnings in AdminVerbSystem.Tools

* Fix 3 warnings in AdminVerbSystem.Smites

* Use SetMapCoordinates directly
2025-03-26 19:36:29 +01:00
PJBot
18cc899897 Automatic changelog update 2025-03-26 16:14:09 +00:00
slarticodefast
c8494dd5c9 Improve paradox clone item copying (#35993)
* even better item copying for the paradox clone

* copy paper

* fix

* blacklist implanter

* string.Empty

---------

Co-authored-by: ScarKy0 <scarky0@onet.eu>
2025-03-26 17:13:02 +01:00
PJBot
f31a568ccc Automatic changelog update 2025-03-26 15:35:27 +00:00
slarticodefast
f838e6730d Fix faction icons for paradox clones (#35910)
* fix nukie icon

* add revs to cloning pod again
2025-03-26 16:34:17 +01:00
PJBot
e066dd3abe Automatic changelog update 2025-03-26 15:31:21 +00:00
slarticodefast
9ff43f344e Show paradox clones in deadchat (#35940)
show clones in deadchat
2025-03-26 16:30:14 +01:00
PJBot
6d63e3c1f4 Automatic changelog update 2025-03-26 15:21:22 +00:00
Velcroboy
b7b3167302 Add smuggler stashes (#19460)
* Add smuggler stashes

* Prevent anchor/collision test fail

* Enabled = false

* Oops, missed one

* NYAH!1984

* Split/Rebalance loot pools and fix test fail

* Errg, still with the canCollide thing

* Removed notes, additional balance tweaking, removed some blank lines

* Replace generator IDs

* Adjust briefcase fill

* Node moved

* Use noSpawn

* Goldschlonger

* Adjusts fills for grid-inv

* Replace removed items

* Replace removed items part 2

* Add empty satchel to clothesmate contraband inventory

* Merge master and switch spawning to roundstart event

* Cleaned up and converted to entity spawn tables + Added funny clown satchel

* Adds comp to prevent stacking bags

* Inital cleanup

* More changes

* ff

* Some fixes but yaml needs to be organized and a few bugs remain

* Final fixes

* Cleanup

* good

* One more

* minor tweaks

* Rename

* Combine dupe fields

* address review

* review

* make linter happy

* names, contraband status

* uplink

* small bugfix

---------

Co-authored-by: Jeff <velcroboy333@hotmail.com>
Co-authored-by: beck-thompson <beck314159@hotmail.com>
Co-authored-by: Milon <milonpl.git@proton.me>
Co-authored-by: ScarKy0 <scarky0@onet.eu>
2025-03-26 16:20:15 +01:00
github-actions[bot]
615af0b116 @F8ctor has signed the CLA in crystallpunk-14/crystall-punk-14#1072 2025-03-26 14:57:07 +00:00
Tayrtahn
9b28aedbc5 Cleanup TabletopSystem.Map (#36097)
* Add SharedMapSystem dependency

* IMapManager.MapExists -> SharedMapSystem.MapExists

* IMapManager.CreateMap & IMapManager.GetMapEntityId -> SharedMapSystem.CreateMap

* IMapManager.DeleteMap -> SharedMapSystem.DeleteMap

* Remove IMapManager dependency
2025-03-26 15:17:28 +01:00
Milon
b97de9d603 add predicted popups with PVS filtering (#36092)
add
2025-03-26 12:45:29 +01:00
Ed
87d757de45 Update furnace.yml 2025-03-26 14:29:49 +03:00
Ed
fd2c59f4bb Update spells.yml 2025-03-26 12:17:19 +03:00
Errant
2f30fe3ceb adminnotes command cleanup (#36086)
localize adminnotes command, autocomplete
2025-03-25 22:42:17 -07:00
Tayrtahn
462519b7da Cleanup WarpCommand (#36088)
* EntityCoordinates.GetGridUid -> SharedTransformSystem.GetGrid

* EntityCoordinates.GetMapId -> SharedTransformSystem.GetMapId

* Hey look, there's been a bug here this whole time

* TransformComponent.Coordinates.set -> SharedTransformSystem.SetCoordinates

* Now actually working!

* Formatting why not

* Remove unneeded GetComponent
2025-03-26 03:17:46 +01:00
BWTCK
9ca6353dcd Add code comment to antifreeze reagent (#36065)
* Recolored the metamorphic glass antifreeze sprite to reflect the actual color of the chemical

* Added recolor credit in meta.json

* The antifreeze shall be blue!

* removed weird fill-5 change
2025-03-26 00:06:04 +01:00
Tayrtahn
7270988961 Cleanup BiomeSystem.Commands (#36084)
* _mapManager.GetMapEntityId -> _mapSystem.GetMapOrInvalid

* _mapManager.MapExists -> _mapSystem.MapExists

* Unused using
2025-03-25 23:30:06 +01:00
Tayrtahn
1364bfd422 Cleanup SpecialRespawnSystem (#36087)
* grid.TileIndicesFor -> _map.TileIndicesFor

* coords.ToMap -> _transform.ToMapCoordinates

* grid.TryGetTileRef -> _map.TryGetTileRef

* grid.GridTileToWorldPos -> _map.GridTileToWorldPos

* grid.WorldToTile -> _map.WorldToTile

* grid.GridTileToLocal -> _map.GridTileToLocal

* Formatting why not
2025-03-25 23:16:48 +01:00
ArZarLordOfMango
33970b0429 syringe fix (#1071) 2025-03-26 00:57:37 +03:00
Tayrtahn
8dfa2e8f95 Cleanup PathfindingSystem (#36083)
* EntityCoordinates.GetMapUid -> SharedTransformSystem.GetMap

* EntityCoordinates.GetGridUid -> SharedTransformSystem.GetGrid

* EntityCoordinates.ToMapPos -> SharedTransformSystem.ToMapCoordinates().Position

* Formatting why not
2025-03-25 21:51:11 +01:00
PJBot
1732579c22 Automatic changelog update 2025-03-25 20:16:30 +00:00
Errant
c82d531a8f Admin Overlay stacking and ghost hiding (#35622)
* ghostbuster mouse and overlay stacks

* variable adjustment

* use map coords for distance check

* vertical stack ordering, and cvars

* skreee

* fix stack merge 'sidedness' issue

* overlays no longer try to stack to overlays at the wrong coordinates

* options slider for stack merge distance

* admin option sliders for ghost fade/hide

* Update AdminOptionsTab.xaml.cs

---------

Co-authored-by: ScarKy0 <scarky0@onet.eu>
2025-03-25 21:15:22 +01:00
TheProNoob678
098e594161 A Bunch of New Figurine Voicelines (#36039)
* Add a bunch of figurine voicelines and reduces delay

* Added footsoldier figurine voicelines

* Fixed voiceline count.

* Fixed Queen Xeno figurine formatting issues

* Fixed my terrible fucking grammar
2025-03-25 21:14:34 +01:00
PJBot
9148c21b2b Automatic changelog update 2025-03-25 18:42:03 +00:00
ScarKy0
c3d0b93ddf Fix admin "Spawn here" verb (#36080)
* init

* review

* review

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-25 19:40:54 +01:00
Pieter-Jan Briers
981eb42979 Enable parallel Pow3r solver on Vulture (#36079)
See if it still causes issues.
2025-03-25 18:53:19 +01:00
Pieter-Jan Briers
ecf590f223 Remove unused PowerConsumer from grilles (#36077)
This caused tons of completely wasted processing in the power system. Incredible.
2025-03-25 18:47:49 +01:00
Pieter-Jan Briers
290bffceec Make pow3r validation logic available on release (#36075)
I want to run this on live servers. It's behind a power_validate command, it still doesn't automatically get ran outside debug otherwise.
2025-03-25 10:02:39 -07:00
PJBot
9243d65e6f Automatic changelog update 2025-03-25 16:05:08 +00:00
Errant
72141abf8a Admin playerlist antag presentation rework (#35538)
* refactor(src): Minor refactor of Draw in "AdminNameOverlay. And new info about playtime player

* fix(src): Add configure classic admin owerlay

* fix

* antag status indication rework

* the cvars are free, you can just take them

* update playerlist on cvar change

* more overlay options

* tweak(src): Use _antagLabelClassic and tweak style

* tweak(src): Add config display overlay for startingJob and playTime

* tweak(src): Vector2 is replaced by var

* tweak(src): return to the end of the list

* add new option checkboxes

* passing ConfigurationManager through constructor, some format changes

* made sorting values more futureproof

* comments

* labels

* no point commenting this out when the overlay stack PR will uncomment it again anyway

* sorting prototype

* localize symbols because why not

* symmetry

* Revert "localize symbols because why not"

This reverts commit 922d4030300285a45777d62fcfd9c74b25fe7a60.

* layout and formatting stuff

* fix errant space

---------

Co-authored-by: Schrödinger <132720404+Schrodinger71@users.noreply.github.com>
2025-03-25 17:03:59 +01:00
creamybag
ee2846613a guildmaster's rapier (#1070) 2025-03-25 17:47:44 +03:00
ArZarLordOfMango
0bcc5ace8c [Fix]Updating the Alchemist's guidebook (#1069)
* first-ru

* ru-2

* en-1
2025-03-25 16:19:08 +03:00
Nim
0d3be998a0 Deleted trade amulet (#1066)
* deleted trade amulet

* comm
2025-03-25 09:37:23 +03:00
āda
1b74de6dbb Fix Wizard/Librarian PDA flashlight visual (#36064)
the other light
2025-03-25 02:21:59 +01:00
Tayrtahn
0096dedb18 Fix error when disconnecting the client while a projectile is embedded (#36048)
* Add test for disconnecting the client while a projectile is embedded

* Add check for non-terminating grid or map

* Add test that an embeddable detaches when the target is deleted.

* Remove Explicit tag from TestDisconnectWhileEmbedded
2025-03-25 01:16:13 +01:00
āda
2bc3561868 Fix misplaced pixel on Wizard/Librarian PDA (#36060)
* nudge that pixel

* new base

* whoops, leftovers
2025-03-25 01:11:04 +01:00
PJBot
99e62b4a49 Automatic changelog update 2025-03-24 23:56:24 +00:00
slarticodefast
9502ca0d23 Fix thermal regulation this time for real (#36062) 2025-03-24 16:55:16 -07:00
Partmedia
37c88debb5 Fix comment (#36054) 2025-03-24 20:47:48 +01:00
Tayrtahn
ae07c5d841 Allow NukeOps test to function with multiple RuleGrids (#36049) 2025-03-24 19:59:13 +01:00
Tayrtahn
67b76d81e5 Fix SpeakOnTrigger not working for messages starting with '.' (#36053) 2025-03-24 11:19:29 -07:00
PJBot
c9f567956a Automatic changelog update 2025-03-24 16:37:57 +00:00
Emisse
b1af9ac89e Relic improvements (#35507) 2025-03-24 10:36:44 -06:00
metalgearsloth
4f23016c72 Fix TrayScannerUser (#35959)
* Fix TrayScannerUser

* Ignore

* Update Content.Shared/SubFloor/TrayScannerUserComponent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-24 16:35:22 +01:00
Nim
b2095a01cc Trade orders (#1037)
* orders

* sprite

* fix orders

* different

* layers

* scrolls

* flora

* loot

* groups

* entity-group

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-03-24 17:15:44 +03:00
creamybag
b5a2508ebc Maid Update (#1064)
* MaidUpdate

* fix
2025-03-24 17:15:29 +03:00
Nim
44b775b308 Request editing (#1063)
* request editing

* skeleton

* no bank

* job
2025-03-24 17:07:48 +03:00
Ed
2dbc3e7a4d Back to Ru CBT + Bugfixes (#1065)
* Update Dev.toml

* fix #1059

* fix #1061

* fix #1060

* fix #1058
2025-03-24 17:06:09 +03:00
Vortebo
4530749f1d lol im dum 2025-03-23 20:05:55 -05:00
Tayrtahn
7c9e344cd2 Fix changelog entries with brackets crashing the client (#36033) 2025-03-24 00:46:34 +01:00
Vortebo
3e36b2c1f7 more touchups 2025-03-23 18:19:14 -05:00
Vortebo
4f1b8ea65d small touchups 2025-03-23 17:53:04 -05:00
Vortebo
b566eef796 pickup truck and beds 2025-03-23 16:56:30 -05:00
Killerqu00
fbf0679650 Fix admin changelog hard-crash (#36029)
fix changelog
2025-03-23 21:37:58 +01:00
Deserty0
b325a80a61 Фикс гайдбука (#1057)
* Update Alchemy.xml

* Звучит фигово

* Update Resources/ServerInfo/_CP14/Guidebook_RU/JobsTabs/AlchemistTabs/Alchemy.xml

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-03-23 22:32:31 +03:00
ScarKy0
c8f5b480cb Package loot tables part 2: Engineering (#36026)
* MAIL!!!!

* changes
2025-03-23 19:46:58 +01:00
Vortebo
35a619b1d5 aaaa the atmosphere the atmosphere 2025-03-23 13:10:11 -05:00
Myra
f4c5253f9c Increase IPIntel bad rating score & Enable warnings (#36021)
Admin requested change
2025-03-23 17:42:00 +01:00
Ed
4083b79217 Update Dev.toml 2025-03-23 17:07:21 +03:00
ScarKy0
9e1a150829 Package loot tables part 1: Medical (#35895)
* :3

* oops

* moved file, comments
2025-03-23 14:53:02 +01:00
ArZarLordOfMango
28d30571ca locale-fix (#1055) 2025-03-23 16:28:54 +03:00
Myra
57e3f0494e Upgrade GitHub actions in Workfows to node20 (#33668) 2025-03-23 13:54:56 +01:00
Ed
8656a7e1f0 Update floorLava.yml 2025-03-23 15:45:41 +03:00
ScarKy0
1859975ae6 Chemistry bottle cleanup (#35911)
* init

* clean

* god save me

* fuck relic

* i HATE HATE  HATE relic

* make it stop

* please make it stop

* CEASE

* PLEASE

* Revert "PLEASE"

This reverts commit 47d34f3c1e657adf869d84a5349f9c18fc33bfea.

* Revert "CEASE"

This reverts commit 147ab6697807b98e24b0e1ee05571a1995f3c41c.

* Revert "please make it stop"

This reverts commit f2a4f63e5f5b017f2b4ad3511e8c77700abed58b.

* Revert "make it stop"

This reverts commit b10c6344bd9e9e3f1989b29fc46a8de7829e382e.

* Revert "i HATE HATE  HATE relic"

This reverts commit a05d60c0055fa003f7746be7aec2ebf4acd6e136.

* Revert "fuck relic"

This reverts commit e44f3368bc8aa5938095dc5a60e9390fbaf8aba3.
2025-03-23 13:24:55 +01:00
Ed
29278ca98b localization (#1054) 2025-03-23 15:00:18 +03:00
Viator-MV
9c5662d7f5 Skeleton upgrade (#1053)
* skeleton upgrade

* armor upgradde

* skelute

* true, not real

* fix
2025-03-23 14:27:14 +03:00
Ed
eaf9c009c1 Slimes mob (#1049)
* import sprites

* pipia

* 3 slime types

* Delete generic_magic_effects.yml

* Update scrolls.yml

* demiplane integration

* Update fire.yml

* Update crystals.yml

* local

* Update fire.yml

* fix AI stuck

* Update base.yml

* loot

* Update mobs.yml
2025-03-23 14:14:08 +03:00
ArZarLordOfMango
5512e1a665 barrel (#1052) 2025-03-23 13:32:03 +03:00
Tayrtahn
d4c8ddb0ac Fix migrations not being applied to PostMapInitTest (#35933)
* Fix migrations not being applied to PostMapInitTest

* formatting

* Raise the event outside the loop so it only happens once
2025-03-23 21:07:01 +11:00
Emisse
c42d0913cb Fix bagel engineering power (#36018) 2025-03-23 02:26:14 -06:00
ArtisticRoomba
3f2befca9e fix bagel power 2025-03-23 01:04:49 -07:00
github-actions[bot]
dac6c53aa1 Update Credits (#36015)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2025-03-23 01:42:14 +01:00
PJBot
b5f142b568 Automatic changelog update 2025-03-23 00:22:38 +00:00
RedBookcase
64faddf77a Fixed some unintended salvage changes. (#36013)
* Fixed some unintended salvage changes.

* Update Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

---------

Co-authored-by: RedBookcase <Usualmoves@gmail.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-23 01:21:29 +01:00
Vortebo
7773b77a91 grilles 2025-03-22 18:31:42 -05:00
Vortebo
f2562aad06 mail teleporter 2025-03-22 17:48:55 -05:00
Vortebo
113e335ca8 Merge remote-tracking branch 'upstream/master' into relic-improvements
need to merge
2025-03-22 15:08:21 -05:00
ArZarLordOfMango
42e3f7ce97 bone mask fix (#1050) 2025-03-22 22:52:03 +03:00
github-actions[bot]
8da5776a4e @ArZarLordOfMango has signed the CLA in crystallpunk-14/crystall-punk-14#1050 2025-03-22 19:42:23 +00:00
Vortebo
923f147d9d working, authentic emergency shuttle (no gamekit) 2025-03-22 12:16:57 -05:00
PJBot
17424e2eb6 Automatic changelog update 2025-03-22 14:43:27 +00:00
Boaz1111
559d22c86c unrevivable lets you be cloned again (#36008)
weh
2025-03-22 15:42:20 +01:00
PJBot
38f3238b1d Automatic changelog update 2025-03-22 11:42:23 +00:00
metalgearsloth
a9a6b98f99 Fix alerts mispredict + log spam (#36004)
tstalker alerted me to it and noticed the classic case of shallow copies.
2025-03-22 12:41:16 +01:00
YoungThug
c2963d47a0 Prisoner Jumpsuit Description (#36005)
* PrisonerJumpsuitFix

* Update jumpskirts.yml
2025-03-22 00:39:33 -07:00
SlamBamActionman
71ae9257f7 Remove serverside StandingStateSystem (#35999)
Refactor system
2025-03-22 16:00:21 +11:00
Killerqu00
dacf0d915c Hover examine buttons (#35206)
* hover examine verbs (not aligned to the left yet)

* handle click hovers and align them to the left

* revert contrabandsystem changes (this is for another PR)

* add support for markup tags
2025-03-22 13:22:01 +11:00
PJBot
4027115e0c Automatic changelog update 2025-03-21 23:22:40 +00:00
SlamBamActionman
6856440084 Add antag notice to admin chat alerts (#35994)
Add antag notice to admin chat pop-ups
2025-03-22 00:21:32 +01:00
Vortebo
3f62dfe0b5 technically playable 2025-03-21 17:14:38 -05:00
Viator-MV
dd6d3f8bc7 Factoria upd (#1044)
* Update factoria.yml

* fact_dung

* Update Factoria.yml

* planetarize factoria

* Update factoria.yml

* Update factoria.yml

* Update factoria_d.yml

* meh

---------

Co-authored-by: Ed <edwardxperia2000@gmail.com>
2025-03-21 22:20:12 +03:00
Vortebo
3d873c6600 the ultimate lifeform, lightswitches 2025-03-21 08:55:40 -05:00
Ed
52e6e9b28f Carcat night vision (#1046)
* carcat night vision

* Update nightVision.yml
2025-03-21 16:53:59 +03:00
YoungThug
1b26a98d7f Arachnid Jensen Googles Fix. (#35987)
pleasespeedmerge
2025-03-21 13:00:23 +01:00
beck-thompson
97d0f14dae Predict pipe anchoring and unanchroing (#35977)
* yay prediction

* Added cool popups

* bruh

* this is better!
2025-03-21 12:43:35 +03:00
PJBot
2b6c0e296d Automatic changelog update 2025-03-21 09:41:42 +00:00
āda
2dc7236a71 Recolor some machine boards (#35715)
* recolor

* Revert for easier review

This reverts commit 20709a6e1f1ac9c99cb030ee56156c8ed4bcc291.

* spacing

* colors

* Revert "spacing"

This reverts commit 92d2d4fc6ee918d13cc8f1f82ce720b94e25d4a8.
2025-03-21 12:40:35 +03:00
TeenSarlacc
6e82ac9f81 Add a crate with foam force weapons to the cargo catalog (#35824)
* made up a nice lil crate

* changed rifle count to 4, added to cargo console

---------

Co-authored-by: TeenSarlacc <baddiepro123@gmail.com>
2025-03-21 12:39:54 +03:00
PJBot
9cba450a19 Automatic changelog update 2025-03-21 09:38:08 +00:00
Tiniest Shark
e72a086815 Grenade + Throwable Inhands (#35974)
* Added inhands to grenades, bolas, ninja stars, and some bombs.

* whoops bolas were wrong hands

* Couple more quick fixes whoops
2025-03-21 12:37:02 +03:00
ArtisticRoomba
280ac8b3ed Fix thermoregulation (#35981)
* fix thermoregulation

* req
2025-03-21 12:36:16 +03:00
PJBot
a5566b1bfa Automatic changelog update 2025-03-21 08:49:13 +00:00
Moomoobeef
534f9e771f Redid Singularity Generator Sprite (#31500)
changed singularity generator sprite
2025-03-21 11:48:06 +03:00
Dakota
a8a73a611e feat: Ghost Role Button only turns red when new ghost roles are added (#35970)
* feat: Ghost Role Button only turns red when new ghost roles are added

* fix: Make _prevNumberRoles private
2025-03-21 11:15:39 +11:00
PJBot
4a234923ad Automatic changelog update 2025-03-21 00:14:07 +00:00
K-Dynamic
8a3ae8e5ca dragon ai faction fix (#35578)
* dragon ai faction fix

* xeno faction
2025-03-21 01:13:00 +01:00
PJBot
d504357aab Automatic changelog update 2025-03-20 23:02:42 +00:00
SlamBamActionman
85a6ac90ba Add stamina and mob damage playtest modifiers (#35599)
* Add stamina and mob damage playtest modifiers

* Fix typo

* Add FTL

* Review fixes

* Update Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-21 00:01:35 +01:00
PJBot
09901e6551 Automatic changelog update 2025-03-20 22:41:39 +00:00
slarticodefast
4d50a5a903 Fix thermal regulation (#35971) 2025-03-20 23:40:31 +01:00
PJBot
1535fe731a Automatic changelog update 2025-03-20 21:47:58 +00:00
SonicHDC
4415c2448d More coat zips! (#35029)
* Update meta.json

* Sprites Exp

* Update meta.json

* More zips for coats
2025-03-20 22:46:51 +01:00
PJBot
7174195208 Automatic changelog update 2025-03-20 21:03:04 +00:00
Tayrtahn
8da4f9765e Fix erased paper sprites looking written (#35967) 2025-03-20 22:01:57 +01:00
Tayrtahn
b780b74bbd Validate some SpeciesPrototype fields (#35965)
* Convert SpeciesPrototype strings to ProtoIds

* Simplify protoman indexing calls
2025-03-20 21:15:30 +01:00
Tayrtahn
ecf22daff7 Fix wrong assert message in DeviceLinkingTest (#35964) 2025-03-20 20:58:09 +01:00
PJBot
5dd1cd4bdb Automatic changelog update 2025-03-20 19:57:58 +00:00
SlamBamActionman
43d08100b9 "New player" admin logging improvements (#35961)
* Initial commit

* Adjust a whoooole bunch of logs

* Also spears

* Track going crit

* Review fix

* Review fixes
2025-03-20 20:56:51 +01:00
Ed
07a8a02522 vox inhands displacements (#35947)
vox inhands
2025-03-20 18:01:39 +01:00
PJBot
f5b8b248f2 Automatic changelog update 2025-03-20 16:40:06 +00:00
Tobias Berger
0d04f541d2 Fix LatheMenu DefaultProductionAmount getting ignored (#35951) 2025-03-20 17:38:59 +01:00
PJBot
09c7c6b7b4 Automatic changelog update 2025-03-20 16:34:54 +00:00
psykana
98730a5485 C4 helmet unequip delay (#35922) 2025-03-20 09:33:47 -07:00
metalgearsloth
4009cea235 Update engine to 249.0.0 (#35956) 2025-03-21 01:05:55 +11:00
metalgearsloth
9292e3a43c Sloth's subfloor vismask adventure (#35347)
* Add a subfloor vismask

Significantly cuts down on sent entity count.

* More optimisations

* Fix command

* Fixes

* namespace cleanup

* Review

* Vismasks

* Content update

* Bandaid

* awewa

* Revert these

* reh

* Update Content.Shared/SubFloor/TrayScannerComponent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-21 00:57:04 +11:00
paige404
2e7f01b99e Fix broken layer hiding on clothes with multiple equipment slots (#34080)
* Fix broken layer hiding on clothes with multiple equipment slots

* Refactor ToggleVisualLayers, HideLayerClothingComponent, and ClothingComponent to allow more
precise layer hide behavior and more CPU efficient layer toggling.

* Adjust HumanoidAppearaceSystem to track which slots are hiding a given layer (e.g. gas mask and welding mask)
Add documentation
Change gas masks to use the new HideLayerClothingComponent structure as an example of its usage

* Fix the delayed snout bug

* Misc cleanup

* Make `bool permanent` implicit from SlotFlags

any non-permanent visibility toggle with `SlotFlags.None` isn't supported with how its set up. And similarly, the slot flags argument does nothing if permanent = true. So IMO it makes more sense to infer it from a nullable arg.

* Split into separate system

Too much pasta

* Remove (hopefully unnecessary) refresh

* Fisk mask networking

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

* Keep old behaviour, use clearer names?

I'm just guessing at what this was meant to do

* english

* Separate slot name & flag

* dirty = true

* fix comment

* Improved SetLayerVisibility with dirtying logic suggested by @ElectroJr

* Only set mask toggled if DisableOnFold is true

* FoldableClothingSystem fixes

* fix bandana state

* Better comment

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2025-03-21 00:30:47 +11:00
claustro305
65f393bb14 Fixed Wizard Thrust (#35948)
fixed wizard thruster
2025-03-20 12:54:59 +01:00
Ed
52a145f7f1 Support separate displacement maps for left and right hand (#35820)
* Update HandsSystem.cs

* Update HandsComponent.cs
2025-03-20 00:06:55 -07:00
PJBot
6351398bb6 Automatic changelog update 2025-03-20 02:19:07 +00:00
SeamLesss
a0c78e7b18 Medical Item In-Hand Sprites (#34984)
* Bruizepack fix and Gauze

* tourniquet sprites added

* medipen sprites

* bodybag sprites

* handheld crew moniter sprites

* implanter sprites

* rollerbed sprites

* health analyzer sprite

* bloodpack sprite

* small rollerbed change

* attributuions + spacing fix

* fixed?

* RAAAAAGH ITS DONE

* actually good code

* Update Resources/Textures/Objects/Specific/Medical/handheldcrewmonitor.rsi/meta.json

* Update Resources/Textures/Objects/Specific/Medical/healthanalyzer.rsi/meta.json
2025-03-19 22:18:01 -04:00
PJBot
115492e9bd Automatic changelog update 2025-03-20 02:16:50 +00:00
Errant
ba56fe8ebc fix uncuff popups (#35743)
* fix uncuff popups

* them too
2025-03-19 19:15:44 -07:00
PJBot
887edf2d7b Automatic changelog update 2025-03-20 01:51:25 +00:00
GaussiArson
672c96ef6c Removed the heat damage from disablers and disabler SMGs (#35834)
removed the heat damage from disablers and disabler SMGs
2025-03-19 18:50:18 -07:00
Tayrtahn
e2097d473c Fix strip menu revealing true identity (#35862)
* Fix strip menu revealing true identity

* Ghosts don't see through identity
2025-03-20 02:44:01 +01:00
mubururu_
d3ee9f8bc5 some robotics inhands (#33676)
* real

* spacing stuff and fix tiny issue
2025-03-19 21:43:00 -04:00
PJBot
b9f56be959 Automatic changelog update 2025-03-20 01:33:46 +00:00
Velken
003b667aa6 Mail Bag (#35702)
* mail bag

* fix

* cute envelope in the bag sprite

* Update Resources/Textures/Objects/Specific/Cargo/mail_bag.rsi/meta.json

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-19 18:32:39 -07:00
PJBot
ed9bbd9fff Automatic changelog update 2025-03-20 01:05:48 +00:00
SeamLesss
4bb1a62f22 Add In-hand Sprites for miscellaneous items (#35433)
* guh???

* Merge branch 'master' of https://github.com/SeamLesss/space-station-14

* incomplete baseball bat

* bling

* attribution

* camera bug

* damp rag

* cap cap

* centcom cap

* Update Resources/Textures/Clothing/Head/Hats/capcap.rsi/meta.json
2025-03-19 21:04:41 -04:00
PJBot
fc544d713b Automatic changelog update 2025-03-20 00:54:55 +00:00
mubururu_
eb5610b745 inhand sprites for Produce (#35151)
* awakening

* fix test fail

* attribution fix

* tomater killer inhandered

* extrorange inhand spin rate nerfed

* fuck webedit
2025-03-19 20:53:48 -04:00
PJBot
791d7c8f98 Automatic changelog update 2025-03-20 00:36:41 +00:00
MisterImp
7a539b3568 Fix recipe and animation for copypasta (#35925)
* Fixed animation and recipe for Copypasta

* Update Resources/Prototypes/Entities/Objects/Consumable/Food/noodles.yml

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-19 17:35:34 -07:00
mubururu_
752477bff3 consistent grapes (#35125)
* grape

* seedtributions
2025-03-19 20:09:50 -04:00
PJBot
7909f87d00 Automatic changelog update 2025-03-19 23:15:25 +00:00
Tiniest Shark
b1c89d059c snake can now be seen inhand and worn on neck like friend (#35323)
* snake can now be seen inhand and worn like friend

* Roomba's additions

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>

* Update Resources/Textures/Objects/Fun/toys.rsi/meta.json

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>

* Spacing adjustment

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2025-03-19 16:14:17 -07:00
PJBot
97c32d0d70 Automatic changelog update 2025-03-19 22:34:11 +00:00
āda
ef9c896972 Donk Co. Microwave heats twice as fast (#35937)
hot donk!
2025-03-19 15:33:02 -07:00
slarticodefast
988cb08760 Add a code comment to the trait prototype files (#35936)
code comment
2025-03-19 15:25:53 -07:00
Emisse
6f1642eb9a loop station minor evac fix (#35912) 2025-03-19 15:40:49 -06:00
TytosB
a4eac94670 Merge branch 'don' of https://github.com/TytosB/space-station-14-loop into don 2025-03-19 15:56:18 -05:00
TytosB
d0ce213b50 maints firelocks 2025-03-19 15:55:58 -05:00
Tayrtahn
86aa82f2b6 Cleanup: Remove redundant prototype name specifications (#35793)
* Remove redundant prototype name specifications

* These can stay
2025-03-19 19:30:31 +01:00
PJBot
916661944b Automatic changelog update 2025-03-19 17:50:05 +00:00
Errant
8394753c30 lock bwoinkwindow bottom bar height (#35896) 2025-03-19 18:48:58 +01:00
Errant
150f58a6a5 lock bwoinkwindow bottom bar height (#35896) 2025-03-19 18:43:13 +01:00
SlamBamActionman
1d4ff1b0d1 Metagame improvements to antag-before-job selection system (#35830)
* Initial commit

* Update the selection to only count for people who have one of the preferences assigned; latejoin on delay no longer applies pre-selection.
2025-03-19 18:28:25 +01:00
Tayrtahn
398d92a064 Fix artifacts swapping places with ghosts (#35074)
* Prevent artifacts swapping position with ghosts

* Filter for MobStateComponent instead

* Update Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs

* bluh
2025-03-19 12:11:53 -04:00
PJBot
5b08838420 Automatic changelog update 2025-03-19 15:08:42 +00:00
claustro305
2516868bdc Adjust small light hitbox (#35920) 2025-03-19 16:07:35 +01:00
Ed
a951193dba Merge branch 'master' of https://github.com/crystallpunk-14/crystall-punk-14 2025-03-19 14:04:35 +03:00
Ed
4002b0a41c Update CP14SellWhitelistService.cs 2025-03-19 13:45:59 +03:00
Арт
709b78080f Weapon Sharpening System Update & Bread Slicing Fix (#915)
* SharpeningUpdate

* BreadSlicingFix

Before that, bread slices could be cut endlessly into new bread slices.

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-03-19 13:36:46 +03:00
creamybag
d71fd8ef80 jager2 (#1042) 2025-03-19 12:58:30 +03:00
Ed
1867903c46 Planetarization (#1040)
* tiers to level demiplanes

* Update demiplane_keys.yml

* demiplane on planets

* migrate to wizden dayCycle + planetarize Comoss

* Update comoss_d.yml

* Update audio_music.yml

* Update dev_map.yml

* add shadows to demiplanes

* remove outdated systems

* fix silvas

* silva fix

* Update factoria.yml

* Update island.yml
2025-03-19 12:52:37 +03:00
Tayrtahn
e76b81d291 Remove non-networked Dirty call in GuardianSystem (#35916) 2025-03-18 21:37:14 -04:00
YoungThug
097b93886b Renaming the "Mime Cap" to "White Cap" (#35901)
* MimeCapRename

* FixedTheName

* FIXITAGAIN
2025-03-18 16:54:02 -07:00
PJBot
e27d4b9459 Automatic changelog update 2025-03-18 23:46:27 +00:00
Smith
a5027e430c Smite Vendor Restock and General Soda Machine Balance (#35144)
* Inventory Buff and Enabling Restock

* Smite rebalance

* Rebalance and swapping contraband inventory positions

* Yet another rebalance

* Spaceup rebalanced, removed Smite from machine.
2025-03-18 16:45:19 -07:00
TytosB
0eb30d522b Merge branch 'space-wizards:master' into don 2025-03-18 16:44:59 -05:00
TytosB
196eb0327c evac fix 2025-03-18 16:44:21 -05:00
PJBot
cbcd1091d5 Automatic changelog update 2025-03-18 20:08:15 +00:00
slarticodefast
943d703685 Paradox Clones spawn with their suit sensors off (#35909)
* sensors off

* remove import

* Update Content.Server/Medical/SuitSensors/SuitSensorSystem.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

---------

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
2025-03-18 16:07:06 -04:00
creamybag
d7c4bc0a5c A set of "jagermeister" clothes. (#1039)
* jagermeister

* fix
2025-03-18 17:26:39 +03:00
Nim
e4eea533a5 Decorative sprite pack (#1009)
* cobweb

* statue

* demiplan fun

* flowers

* head

* head

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2025-03-18 16:33:11 +03:00
PJBot
0a166e2af0 Automatic changelog update 2025-03-18 08:01:51 +00:00
slarticodefast
c72fd448cd Killer tomatos take damage from weedkiller and plantbgone (#35898)
* tomatobgone

* formatting
2025-03-18 11:00:44 +03:00
PJBot
47dbbabe3e Automatic changelog update 2025-03-18 05:23:04 +00:00
slarticodefast
6c46fe5307 Paradox Clones receive the implants the original has (#35906)
* copy implants to paradox clones

* Minor fixes

---------

Co-authored-by: beck-thompson <beck314159@hotmail.com>
2025-03-17 22:21:56 -07:00
Tayrtahn
95055b43bf Add a test to verify that all device signal sink ports can trigger (#35891)
* Add test of all device link sink ports

* Revert the fixed problem to prove that the test works.
Revert "Fix SpawnAndDeleteAllEntitiesInTheSameSpot heisentest (#32330)"

This reverts commit 4704309b4e.

* Revert "Revert the fixed problem to prove that the test works."

This reverts commit cf0dbe797243552d8a63afefced2acd6829c3887.

* Assert that test devices aren't deleted between port triggers

* Test each port on a different map too

* Convert Linq to guard clauses

* Update Content.IntegrationTests/Tests/DeviceLinking/DeviceLinkingTest.cs

* More informative failure message

* Delete map after each test

* Don't bother sorting by ID

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-18 00:44:38 +01:00
PJBot
0c73b24da8 Automatic changelog update 2025-03-17 18:40:13 +00:00
beck-thompson
15a5cebdcd Chameleon vests now act like winter coats (#34929)
First commit
2025-03-17 19:39:04 +01:00
PJBot
1367ae5703 Automatic changelog update 2025-03-17 18:00:03 +00:00
SlamBamActionman
dc4e8a2972 Increase storage size of Syndicate Backpack (#35888) 2025-03-17 10:58:56 -07:00
PJBot
55f70f9d2c Automatic changelog update 2025-03-17 16:28:15 +00:00
Errant
2b83d9bf89 add missing unknown shuttle ghostrole mindroles (#35892) 2025-03-17 17:27:08 +01:00
slarticodefast
08cd8d0543 Merge stable into master (#35883) 2025-03-17 01:03:47 +01:00
slarticodefast
e4864ac423 Hotfix: Fix AntagRandomSpawn location preview (#35864)
fix AntagRandomSpawn location preview
2025-03-17 00:50:23 +01:00
MilenVolf
f8ccff1363 Localize criminal records reason placeholder dataset (#35810)
* Localize criminal records reason placeholder dataset

* Forgor
2025-03-16 19:43:37 -04:00
PJBot
bf59896922 Automatic changelog update 2025-03-16 22:25:54 +00:00
slarticodefast
197ee78bfa make paradox clone receive the original's objectives (#35829)
* make paradox clone receive the original's objectives

* remove redundant indexing

* Minor comment change

* fix ninja objectives

---------

Co-authored-by: beck-thompson <beck314159@hotmail.com>
2025-03-16 15:24:47 -07:00
PJBot
03dc35ac92 Automatic changelog update 2025-03-16 22:12:37 +00:00
Errant
29cbc4a190 Mark all hostile mind roles as antag (#35832)
* dummy antag prototypes

* I'll deal with YOU later!

* remove redundant soloantag definitions

* doctor, we left the scalpel in the patient

* minor cleanup
2025-03-16 23:11:31 +01:00
PJBot
1b34884823 Automatic changelog update 2025-03-16 22:03:26 +00:00
slarticodefast
d8ed9fe152 Paradox clones get all storage items the original has. (#35838)
* recursive storage copying

* include slime storage

* future proofing

* remove survival box
2025-03-16 15:02:19 -07:00
Tayrtahn
deb3ed3ed2 Let LocalizedDatasetPrototypeTest report multiple failures (#35876) 2025-03-16 22:32:08 +01:00
Tayrtahn
04b9088c85 Add viewer parameter to Identity.Entity (#35861)
* Add viewer parameter to Identity.Entity

* Docs
2025-03-16 14:07:46 -07:00
Vortebo
a7f6ceec58 bridge and security have gone byond the impossible 2025-03-16 14:42:34 -05:00
Vortebo
71f2cf4d54 garbage. in the disposal. 2025-03-16 13:48:28 -05:00
Tayrtahn
4b9d9da074 Fix development and debug configurations for tests (#35625)
* Move settings from debug.toml to development.toml

* Don't force disable dev config for integration tests

* Force on instead?

* Remove change to PoolManager
2025-03-16 19:17:45 +01:00
PJBot
eabd0b7f24 Automatic changelog update 2025-03-16 18:16:49 +00:00
Tayrtahn
6ee3ae80a5 Fix salvage sites ejecting borg brains when they despawn (#35855)
* Fix salvage sites ejecting borg brains when they despawn

* Extra check in while loop

* Move mobStateQuery to InitializeMagnet
2025-03-16 19:15:39 +01:00
Tayrtahn
af36b3983c Make NukeOpsTest list RuleGrids on failure (#35873) 2025-03-16 12:20:13 -04:00
Myra
e0a8718f78 Stable merge (#35870) 2025-03-16 15:12:19 +01:00
Vasilis The Pikachu
1a756a6574 Merge remote-tracking branch 'upstream/staging' into stable 2025-03-16 15:09:05 +01:00
PJBot
6cd9c3e16d Automatic changelog update 2025-03-16 00:42:57 +00:00
Kyle Tyo
b378c5e455 Fix holopads phasing through walls. (#34300)
* change holopad mask from subfloormask lowimpassable to tabletopmachinemask opaque

* change masks to prevent laser collisions

followed the artifact analyzer for this one. I don't quite understand how fixtures work so I'm a bit perplexed by this.

* Boolean I command you: LOWERCASE
2025-03-16 01:41:50 +01:00
github-actions[bot]
411a89ce31 Update Credits (#35860)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2025-03-16 01:40:44 +01:00
slarticodefast
d5372db359 Merge staging into master (#35859) 2025-03-15 23:25:04 +01:00
slarticodefast
b878e80929 HOTFIX: Fix paradox clone event (#35858)
fix paradox clone event
2025-03-15 23:10:24 +01:00
Ed
45593b1db7 Puddles on the floor sticking to the walls (#35856)
Update puddle.yml
2025-03-15 17:35:49 -04:00
saga3152
36f6438c8e Light replacer is back on the menu (#35857)
Lights on
2025-03-15 17:26:38 -04:00
Milon
7f4672f963 clear buyer conditions in StoreDiscountAndRefundTest (#35847)
* fun

* Update Content.IntegrationTests/Tests/StoreTests.cs

Co-authored-by: Hannah Giovanna Dawson <karakkaraz@gmail.com>

* Update Content.IntegrationTests/Tests/StoreTests.cs

Co-authored-by: Hannah Giovanna Dawson <karakkaraz@gmail.com>

---------

Co-authored-by: Hannah Giovanna Dawson <karakkaraz@gmail.com>
2025-03-15 21:58:13 +01:00
PJBot
8848d74ccc Automatic changelog update 2025-03-15 16:44:56 +00:00
K-Dynamic
222331cb49 Take 2: Rename ammunition box (.50), Liberation Station .50 stock (#35326)
ammunition box (.50), .50 shell pellet

also die robust toolbox commits
2025-03-15 09:43:49 -07:00
PJBot
11cac44bc4 Automatic changelog update 2025-03-15 16:25:31 +00:00
pathetic meowmeow
4576555e5b NanoTask (#34095) 2025-03-15 09:24:23 -07:00
PJBot
c7022ae7c5 Automatic changelog update 2025-03-15 15:58:46 +00:00
K-Dynamic
2fe53c3722 Reduce base electrocution stun time from 8 to 5 seconds (#34578)
* reduce shock time from 8 to 3 seconds

* shocktime 5 second, 1.25 mv time multiplier, 1.5 hv time mulitplier
2025-03-15 16:57:35 +01:00
Tayrtahn
5efcccc81f Add interaction tests for vending machines (#35801)
* Add interaction test for vending machines

* Add test of UI basic UI interactions

* Added test for dispensing an item

* Simplify and internalize test yaml

* Add check for restocking with wrong restock box

* Add test for breaking and repairing
2025-03-15 17:07:04 +11:00
Tayrtahn
23d7cd0a29 Fix thrown item prediction weirdness (#35843)
Don't predict thrown item landing/stopping
2025-03-15 17:06:00 +11:00
PJBot
5c5dc1207a Automatic changelog update 2025-03-14 20:23:38 +00:00
Centronias
b980c94d89 Moths can eat lizard plushes again (#35835)
* tags back

* Update Resources/Prototypes/Entities/Objects/Fun/toys.yml

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-14 21:22:30 +01:00
Vortebo
9ca4254e1a station is now moth-friendly 2025-03-14 14:29:14 -05:00
PJBot
e7719518c0 Automatic changelog update 2025-03-14 15:32:18 +00:00
Quantum-cross
fd59427cb5 Corrupt borg speech if they are damaged or low power (#35318)
* - Corrupt borg speech the more damaged they are
- Corrupt long borg messages if battery is low or empty

* twiddle values

* Remove RNG based loop, hardcode repeating values for p=0.25 up to 10 repeats.

* Make sure that DamagedSiliconAccentSystem is AFTER ReplacementAccentSystem

* add missing base initializer call

* use Entity<T> pattern for event listener and clarify default values

* Move corruption parameters to datafields

* Add datafields to enable and disable the two types of corruption, and add datafields to override damage values and charge levels to support entities that don't have damageable components or power cells.

* Use nullables for override values

* Move DamagedSiliconAccentComponent to Shared and make it networked

* Add DamagedSiliconAccent to cloning whitelist
2025-03-15 02:31:09 +11:00
PJBot
50525a11be Automatic changelog update 2025-03-14 06:50:33 +00:00
Coolsurf6
5d296d2dbb Added Bacchus' Blessing Drink (#35306)
* added start to bacchus blessing with few more things left to do

* added sprites and trying to get the empty sprite to work

* fixed empty sprite will fill layer

* added missing fill image

* made flavor, physical description, recipe reaction and tweaked reagent threshold

* fixed fill levels

* removed name from drinks.yml, updated suffix instead

* delay is weird and broken, removing the difference

* updated copyright
2025-03-13 23:49:26 -07:00
PJBot
0ed1f84f45 Automatic changelog update 2025-03-13 20:22:50 +00:00
SlamBamActionman
22ecd58083 Enable antag-before-job rolling for roundstart antags (#35823)
Enable antag-before-job rolling for certain antags
2025-03-13 21:21:42 +01:00
SlamBamActionman
1945c7d7c6 Improvements to antag-before-job selection system (#35822)
* Fix the latejoin-antag-deficit bug, add datafield, add logging

* Fix multiple roles being made for single-role defs,
2025-03-13 19:07:52 +01:00
PJBot
33edf9692b Automatic changelog update 2025-03-13 17:10:14 +00:00
slarticodefast
bce9b4b05b Paradox Clone (#35794)
* polymorph fixes

* paradox clone

* forensics cleanup

* bump doors

* 4

* attribution

* polymorphn't

* clean up objectives

* Update Resources/ServerInfo/Guidebook/Antagonist/MinorAntagonists.xml

* review

* add virtual items to blacklist

* allow them to roll sleeper agent
2025-03-13 10:09:07 -07:00
Lusatia
1b2d3d6ab9 Update Lobby Music Attribtions (#35817)
Biggest change is updating the attributions and links for Sunbeamstress' to reflect the changes in their online profile as the previous link is now a dead link.
Updated Comet Haley's link to go directly to Stellardrone's Bandcamp instead of diverting to Free Music Archive
Fixed a double the in the comment for Space Asshole
2025-03-13 17:00:23 +03:00
PJBot
4a4d3d6a07 Automatic changelog update 2025-03-13 13:13:34 +00:00
ScarKy0
d4b7a6d582 Whitehole/Singularity grenade price adjustments + whitehole grenade fix (#35821)
* prices + adjustments

* teehee
2025-03-13 14:12:27 +01:00
PJBot
66a02010f2 Automatic changelog update 2025-03-13 12:50:33 +00:00
Crude Oil
90dc674c96 Add the ability to pet the mail teleporter (#35819)
good mailbox
2025-03-13 13:49:24 +01:00
PJBot
0b1e25b68e Automatic changelog update 2025-03-13 07:22:33 +00:00
Plykiya
96501f4966 Adds popup when firing gun while gun has no ammo (#34816)
* Adds popup when firing gun while gun has no ammo

* simplify

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-13 10:21:24 +03:00
slarticodefast
48a4aa3929 Cleanup Objective files, add PickSpecificPersonComponent (#35802)
* cleanup objectives

* remove unrelated access restriction

* review
2025-03-13 01:41:50 +01:00
PJBot
3f8be60a8d Automatic changelog update 2025-03-13 00:31:24 +00:00
K-Dynamic
e1762d91fa Locks nitrous oxide canisters (#35785)
lock nitrous oxide canisters
2025-03-12 17:30:16 -07:00
Ed
63ecf4241a IconSmooth additional smoothing keys (#35790)
* additionalKeys

* Update lava.yml

* Update Content.Client/IconSmoothing/IconSmoothComponent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-13 00:51:48 +01:00
PJBot
f9a48463ba Automatic changelog update 2025-03-12 22:48:05 +00:00
onesch
b3482fd737 Tools/Devices: In-hand Sprites (#33689)
* Adds in-hand sprites to the barber scissors.

* adds in-hand sprites to the floodlight.

* adds in-hand sprites to the gas analyzer.

* adds in-hand sprites to the gps.

* Update copyright wording, linting

* resprite gps inhand sprites.

* adds in-hand sprites to the mass scanner.

* adds in-hand sprites to the spray_painter.

* resprite in-hand sprites to the mass_scanner.

* fix in-hand sprites to the mass_scanner.

* Resprite mass_scanner in-hand sprites.
2025-03-13 01:46:58 +03:00
PJBot
e4b268088a Automatic changelog update 2025-03-12 22:46:29 +00:00
Firewars763
212bf99688 Add Gold and Coal Rock Anomalies (#34809)
* This commit adds 2 new Rock Anomaly types, Coal and Gold. It also adds Resource Crabs, colored crystals, and lights for both.

* Added crafting recipes for yellow and black light tubes. Somehow I forgot that the first time.

* Sorted tags.yml alphabetically this time instead of not doing that.

* Updated Texture Copyright information

* Attempted to fix Merge Conflict

* Added bulb light variants for both yellow and black crystals.
2025-03-13 01:45:22 +03:00
Łukasz Lindert
8f81e55711 Cryo and grinder cleanup (#34842)
* cryopod and grinder cleanup

* lower case name

* 4 spaces

* prototype clean

* looks like there is some kind of test that prevents removing this

* grinder too

* both should be empty

* cleanup
2025-03-13 01:44:05 +03:00
Velcroboy
9005183e6e Add wallmount N2 closets, Revived (#34042)
* Add standard, wallmount and improvised N2 closets, Revived

* remove improvised locker

* Parent>ID

* Undo sprite replacement

* Update meta.json

---------

Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
Co-authored-by: Milon <milonpl.git@proton.me>
2025-03-13 01:42:15 +03:00
ninruB
b7759cccbd Fix anomaly doublelogging (#34297)
cull doublelogging
2025-03-13 01:39:42 +03:00
PJBot
28ff4eddf5 Automatic changelog update 2025-03-12 22:37:50 +00:00
Winkarst
0d16bd5d2b New Feature: Warden job rolls before security officer/cadet/detective (#35313)
Commit
2025-03-13 01:36:41 +03:00
slarticodefast
ccc8837b69 fix more syndicate names (#35788) 2025-03-12 15:16:16 -04:00
slarticodefast
d8ac1524ef polymorph popup fixes (#35796)
polymorph fixes
2025-03-12 19:48:45 +01:00
slarticodefast
45e5fbfcdf forensics cleanup (#35795) 2025-03-12 18:57:06 +01:00
SlamBamActionman
2ff59f153e Add support for antag-before-job selection (#35789)
* Add support for antag-before-job selection

* Include logging
2025-03-12 16:48:39 +01:00
SlamBamActionman
02aec8fe54 Update Space Law to reflect Implant changes (#35701)
* Change implanter Space Law

* Add clarification regarding unidentified implanter vs. unidentified implant sentensing
2025-03-12 15:33:33 +01:00
metalgearsloth
44c8e05d1f Update submodule to 248.0.2 (#35787) 2025-03-12 23:47:28 +11:00
Emisse
d12e0b8ddf Amber Station - Added Mail Room (#35786) 2025-03-12 02:50:23 -06:00
Southbridge
06ee81d1fe Added mail room 2025-03-12 04:34:06 -04:00
MilenVolf
5db89ab7e9 Localize rat king commands datasets (#35780) 2025-03-11 22:49:32 -07:00
MilenVolf
b5728c228d Localize news dataset (#35774)
* Localize news dataset

* Remove the `"`
2025-03-11 22:44:19 -07:00
Errant
3d898ed25a Roleban command error handling (#35784)
roleban command jobid fail handling
2025-03-11 22:41:01 -07:00
slarticodefast
175f5e6c2f TriggerSystem improvements (#35762)
* desynchronizer real

* yaml stuff from slarti branch

* C# stuff

* oops

* fix triggers

* atomize PR

---------

Co-authored-by: Flareguy <woaj9999@outlook.com>
2025-03-11 22:31:33 -07:00
PJBot
a384cbed89 Automatic changelog update 2025-03-12 01:23:08 +00:00
valquaint
4baaff2a23 Update to borg ion storms (#35751)
* Updates ion storms for borgs.

* Remove additional ion laws into future PR
2025-03-12 02:21:59 +01:00
Vortebo
3276deeca0 pipes. done. maybe 2025-03-11 16:57:53 -05:00
imcb
231847a36d Fixes and refactoring to discord changelog script (#33859)
* Fixes and refactoring to discord changelog script

Upstreamed from https://github.com/impstation/imp-station-14/pull/1023

* Add some prints back in
2025-03-11 20:14:40 +01:00
PJBot
0575a3afd6 Automatic changelog update 2025-03-11 16:48:10 +00:00
Errant
a6d66e682f Restore the order of admin overlay elements (#35783)
admin overlay order fix
2025-03-11 17:47:03 +01:00
PJBot
9c84acdd92 Automatic changelog update 2025-03-11 13:53:45 +00:00
SlamBamActionman
ab72f682ce Fix Chameleon PDAs renaming the user in station records (#35782) 2025-03-11 14:52:38 +01:00
Princess Cheeseballs
81a1ae1623 Mail Resprite (#35776)
* init commit

* init commit

* delete those

* added github to copyright info
2025-03-11 13:44:32 +01:00
PJBot
6d99887746 Automatic changelog update 2025-03-11 09:42:20 +00:00
ScarKy0
4d98b9d621 Removable mindshields and revolutionary tweaks. (#35769)
* I fucking hate revs

* Update preset-revolutionary.ftl

* fixy fix
2025-03-11 10:41:13 +01:00
Emisse
314b64226c Convex random maints fix (#35777) 2025-03-11 00:16:54 -06:00
Spessmann
de98dbb400 convex fix 2025-03-10 22:40:16 -07:00
SpaceManiac
38615b72e5 Merge showsubfloorforever into showsubfloor (#33682) 2025-03-11 11:01:11 +11:00
PJBot
3b31b72ed0 Automatic changelog update 2025-03-10 23:18:32 +00:00
Velken
4e37bcc40e Performer's Wig (#35764)
* miku wig

* fix to correct json convention

Co-authored-by: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com>

---------

Co-authored-by: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com>
2025-03-10 19:17:23 -04:00
PJBot
12a3a67ca9 Automatic changelog update 2025-03-10 23:09:33 +00:00
RedBookcase
80e674a9ae Added New Cocktails and new fill level sprites to existing drinks. (#33570)
* Added New Cocktails and new fill level sprites to existing drinks

* Updated copyright info and fixed recipies for Caipirinha/Mojito.

---------

Co-authored-by: RedBookcase <Usualmoves@gmail.com>
2025-03-10 19:08:23 -04:00
TytosB
a8d5e08d69 Merge branch 'space-wizards:master' into don 2025-03-10 17:41:46 -05:00
Winkarst
ca60f22c4d Cleanup: Add missing locale `cmd-planet-map-prototype` (#35766)
Cleanup
2025-03-10 16:34:27 +01:00
Vortebo
f4873e9c56 cowdoy in the city TWO 2025-03-10 10:16:38 -05:00
Winkarst
8d93eebceb Cleanup: Fix `PaperWriteEvent in PaperSystem` (#35763)
* Cleanup + fix

* Revert
2025-03-10 15:52:57 +01:00
Evelyn Gordon
e0d6944822 Ensure speech bubble cap is always respected (#32223)
Ensure speech bubble cap is respected, even when messages are sent very fast
2025-03-10 13:28:08 +01:00
PJBot
d1b714bcf8 Automatic changelog update 2025-03-10 09:41:43 +00:00
Errant
c7d9a45dab Fix Ahelp window playerlist resize (#35747)
reorganize bwoink window layout
2025-03-10 20:40:36 +11:00
PJBot
2742429341 Automatic changelog update 2025-03-10 04:39:39 +00:00
metalgearsloth
70fca49063 Tweak sun shadow rotations (#35758)
Won't use the entity's rotation for the matrix, I just forgot to do this. Means shadows will always point in the same direction and the points will correctly adjust as the entity rotates.
2025-03-10 15:38:33 +11:00
PJBot
71ac80eb6c Automatic changelog update 2025-03-10 04:19:00 +00:00
metalgearsloth
b8b6634c0f Fix sun shadows in ANGLE (#35757)
I think I fat-fingered a ctrl-Z on this at some point but the intermediate blur is necessary.
2025-03-10 15:17:53 +11:00
MilenVolf
b1ddc1a20d Localize traitor codeverbs datasets (#35737)
* Localize verbs dataset

* Localize adjectives dataset

* Localize corporations dataset

* Update TraitorRuleSystem to use LocalizedDatasetPrototype instead of DatasetPrototype
2025-03-09 22:20:05 -04:00
metalgearsloth
75a7407e33 Predict some power PowerReceiver stuff (#33834)
* Predict some power PowerReceiver stuff

Need it for some atmos device prediction.

* Also this
2025-03-10 13:00:49 +11:00
Emisse
6689cae5a1 bagel update (#35754) 2025-03-09 19:30:42 -06:00
slarticodefast
84792f88d6 fix nukeops commander name (#35753) 2025-03-10 02:21:56 +01:00
Vortebo
38faab470b removed some stuff 2025-03-09 16:52:35 -05:00
Vortebo
008e51a5f2 more accurate emergency shuttle 2025-03-09 16:40:48 -05:00
Prole
b5b92d5f3d Python Suit Storage Visual (#35593)
* Python-SUITSTORAGE-Visuals

Signed-off-by: Prole <172158352+Prole0@users.noreply.github.com>

* REVised Sprite

Signed-off-by: Prole <172158352+Prole0@users.noreply.github.com>

* Copyright

Signed-off-by: Prole <172158352+Prole0@users.noreply.github.com>

* Update Resources/Textures/Objects/Weapons/Guns/Revolvers/python.rsi/meta.json

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>

---------

Signed-off-by: Prole <172158352+Prole0@users.noreply.github.com>
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2025-03-09 22:06:21 +01:00
ScarKy0
469a4196e3 Slightly better letter loot table (#35748)
* init

* review

---------

Co-authored-by: Milon <milonpl.git@proton.me>
2025-03-09 21:54:10 +01:00
Milon
8e10ff1f08 fix UpdateBankAccount (#35749)
* trolled

* fun

* fuck me
2025-03-09 21:50:24 +01:00
PJBot
03a8dee379 Automatic changelog update 2025-03-09 19:43:02 +00:00
slarticodefast
7a6b947e60 Steal the mail thieving objective (#35746)
* mail theft

* networked
2025-03-09 20:41:53 +01:00
Vortebo
47c3dc65fa big bang little bang 2025-03-09 09:12:05 -05:00
MilenVolf
bcf3390c88 Remove unneeded Loc.GetString (#35739) 2025-03-09 11:06:11 +01:00
ScarKy0
39a8bae2d2 Convex Mail Teleporter (#35742)
Mail!
2025-03-09 03:40:58 -06:00
ScarKy0
ddc5758d00 Plasma Mail Teleporter (#35741)
Mail!
2025-03-09 03:38:15 -06:00
PJBot
66f89cece6 Automatic changelog update 2025-03-09 08:50:04 +00:00
Deerstop
217845b7ae Elkridge Mail Update (#35738)
add mail teleporter and mailing unit system
2025-03-09 01:49:33 -07:00
Emisse
4ed99ca367 derotate core (#35740)
Update default.yml
2025-03-09 01:48:55 -07:00
ArtisticRoomba
fc1c149820 Core mail update (#35719)
* core mail update

* empty
2025-03-09 01:47:43 -07:00
TytosB
f753bb9af4 Loop mail teleporter (#35729)
* latejoin

* youve got mail
2025-03-09 01:47:20 -07:00
github-actions[bot]
7215ae2d5c Update Credits (#35733)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2025-03-09 02:18:00 +01:00
ArtisticRoomba
2de3c58145 Bagel Engineering Improvements (#35717)
* woe, better engineering be upon ye

* im going to lose it

* radical plan

* oopsie

* Revert "oopsie"

This reverts commit 45ab057f55b46acd795e58257c3cc5967e5cb946.

* Revert "radical plan"

This reverts commit 57b1ae081725a47aef3ae03111cecbc91b4f47a8.

* Revert "im going to lose it"

This reverts commit e7b4afaf5d9a10a42e89831ffc9294d3b9bd96d4.

* Revert "woe, better engineering be upon ye"

This reverts commit 471dc3716b58a39631aa8bee00de79e981391d63.

* complete revamp

* revision

* oops 2 electric boogaloo

* another one

* every time i push to fix a minor mistake i found in walking around i get closer to my limit
2025-03-08 18:08:35 -07:00
ScarKy0
9d7cf27469 Remove a bonus Loc.GetString (#35731)
oops
2025-03-08 23:30:48 +01:00
ScarKy0
e57325b797 Fixed delivery popups (#35724)
* :)

* cool stuff
2025-03-08 22:08:41 +01:00
ScarKy0
6f39ee8688 Initial delivery balance changes (#35728)
* init

* small balance

* guess not

* Update Content.Server/Delivery/CargoDeliveryDataComponent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-08 21:48:02 +01:00
TytosB
c64a6b03a3 youve got mail 2025-03-08 14:10:24 -06:00
TytosB
52d7479c50 Merge branch 'space-wizards:master' into don 2025-03-08 13:46:37 -06:00
slarticodefast
4735097385 Fix integration tests (#35727)
* test

* fix names

* fix more
2025-03-08 20:38:18 +01:00
MilenVolf
1abd2d3a08 Localize all dataset names (#32893)
* Use `LocalizedDatasetPrototype` instead of `DatasetPrototype` in `RoleLoadoutPrototype`

* Localize ai names

* Replace to `LocalizedDatasetPrototype` in `NamingSystem`

* Localize arachnid first and last names

* Localize atv names

* Localize autoborg names

* Forgot to change type to localizedDataset

* Localize borer names

* Localize borg names

* Localize cargo shuttle names

* Localize clown names

* Localize death_commando names

* Localize diona names

* Localize fake_human names

* Localize first and last names

* Localize first male and female names

* Localize fortunes descriptions

* Forgot about equal sign

* Localize golem names

* Localize hologram names

* Localize military names

* Localize moth first male and female names

* Localize moth last names

* Fix autoborg name error

* Localize mushman first and last names

* Localize ninja names

* Localize operation names

* Localize regalrat names

* Fix mushman_first

* Forgot about `Loc.GetString`

* Move comments into comment section & fix names

* Localize reptilian male and female names

* Localize revenant names

* Fix locale word order in operation

* Localize rollie (btw it was never used and was added as "for the futuгe" long time ago)

* Localize skeleton_first names

* Localize syndicate names

* Localize vox names

* Localize wizard first and last names

* `{owner}-name-dataset` -> `names-{owner}-dataset`

* Change `DatasetPrototype` to `LocalizedDatasetPrototype` and make sure it works properly

GetFTLName is no more the static method, we need it to be able to use `Loc.GetString`

* I hate those mothname comments

* Combine name datasets prototypes

* Move every ftl from` /en-US/names` to ` /en-US/datasets/names`

* Remove ftl files

* Get every dataset yml back

* Remove changes for planets. Move it in another PR

* Revert these changes (Moved to another PR)

* How

* Apply suggested changes
2025-03-08 20:04:26 +01:00
MilenVolf
b1fabb5a1a [Part of #32893] Localize misc dataset names (#33404)
* Localize cargo_shuttle names

* Localize death_commando names

* Localize fortunes

* Localize military names

* Localize rollie names

* fortunes.ftl -> cookie_fortune.ftl

* Correct prototype ids to follow naming conventions
2025-03-08 20:04:01 +01:00
MilenVolf
3ccd9e4b6d [Part of #32893] Localize first male & female dataset names (#33402)
* Localize first_name

* Localize first_female

* names-male/female-first-dataset -> names-first-male/female-dataset

* Correct prototype ids to follow naming conventions

* Combine first_male.yml and first_female.yml into base_gendered.yml
2025-03-08 20:03:51 +01:00
MilenVolf
9200a24dcf [Part of #32893] Localize first & last dataset names (#33401)
* Localize first names

* Localize last names

* Correct prototype ids to follow naming conventions

* Combine first.yml and last.yml into base.yml

* Forgot about = in last
2025-03-08 20:03:38 +01:00
MilenVolf
7806afb284 [Part of #32893] Localize vox dataset names (#33396)
* Localize vox names

* Correct prototype id to follow naming conventions

* Upstream names
2025-03-08 20:03:24 +01:00
MilenVolf
177a323fd4 [Part of #32893] Localize humanoid species dataset names (#33395)
* Localize diona names

* Localize moth names

* Localize mushman names

* Localize reptilian names

* Localize skeleton names

* Upstream diona names

* names-moth-male/female-first-dataset -> names-moth-first-male/female-dataset

* Correct prototype ids to follow naming conventions

* NamesSkeletonFirst -> NamesSkeleton

* Combine moth_first_female.yml, moth_first_male.yml and moth_last.yml

* Forgot about skeleton prototype

* Upstream names

* Update Resources/Locale/en-US/datasets/names/diona_last.ftl

* Update Resources/Locale/en-US/datasets/names/diona_last.ftl

* keep first name for skeleton

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-08 20:03:07 +01:00
MilenVolf
0480e1554f [Part of #32893] Localize antagonists dataset names (#33393)
* Localize fake human names

* Localize ninja names

* Localize operation names

* Localize regalrat names

* Localize revenant names

* Localize syndicate names

* Localize wizard names

* Correct prototype ids to follow naming conventions

* Combine fake_human_first.yml and fake_human_last.yml

* Move contents of ninja_title.yml into ninja.yml

* Combine Operation_prefix.yml and Operation_suffix.yml

* Combine wizard_first.yml and wizard_last.yml

* Upstream names

* fix wizard

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-08 20:02:46 +01:00
MilenVolf
7242a1d69d [Part of #32893] Localize summonable creatures dataset names (#33392)
* Localize clown names

* Localize golem names

* Localize hologram names

* Correct prototype ids to follow naming conventions

* Update Resources/Locale/en-US/datasets/names/golem.ftl

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-08 20:02:36 +01:00
MilenVolf
28174a5062 [Part of #32893] Localize arachnid dataset names (#33353)
* Localize arachnid dataset names

* Correct prototype ids to follow naming conventions

* Combine arachnid_first.yml and arachnid_last.yml

* Upstream names
2025-03-08 20:02:22 +01:00
MilenVolf
965bd1c5ac [Part of #32893] Localize silicon dataset names (#33352)
* Localize ai names

* Apply requested changes

* Localize autoborg

* Localize borg names

* Localize atv names

* Correct prototypes ids to follow naming conventions

* Remove AI localization (Moved to another PR)

* Weh
2025-03-08 20:02:12 +01:00
PJBot
804addfff7 Automatic changelog update 2025-03-08 15:22:34 +00:00
Momo
2412b4f634 Aroace pride pin, scarf, and cloak (#35718)
cloak, pin, and scarf added yayyyy
2025-03-08 16:21:21 +01:00
compilatron
bc083f9d49 Plasma fixes 4 (#35716)
Fixes 15

Co-authored-by: jbox1 <40789662+jbox144@users.noreply.github.com>
2025-03-08 01:47:49 -07:00
ScarKy0
315f5a21a9 Fland Mail Teleporter (#35711)
Mail!
2025-03-08 01:47:41 -07:00
ScarKy0
a1487c21bb Marathon Mail Teleporter (#35710)
Mail!
2025-03-08 01:47:15 -07:00
ScarKy0
8d6cc7b2a0 Meta Mail Teleporter (#35709)
Mail!
2025-03-08 01:47:03 -07:00
ScarKy0
d8b020ca54 Oasis Mail Teleporter (#35708)
Mail!
2025-03-08 01:46:55 -07:00
ScarKy0
6c4d1acb35 Box Mail Teleporter (#35707)
Mail!
2025-03-08 01:46:43 -07:00
ScarKy0
9f3ae33e77 Packed Mail Teleporter (#35706)
Mail!
2025-03-08 01:46:32 -07:00
ScarKy0
4c9199dd59 Omega Mail Teleporter (#35705)
Mail!
2025-03-08 01:46:20 -07:00
PJBot
2c40dde9bc Automatic changelog update 2025-03-08 05:08:48 +00:00
metalgearsloth
f51b9bc86e Add sun shadows (planet lighting stage 2) (#35145)
* Implements a Dynamic Lighting System on maps.

* Edit: the night should be a little bit brighter and blue now.

* Major edit: everything must be done on the client side now, with certain datafield replicated.
Changes were outlined in the salvage to accommodate the new lighting system.

* Edit: The offset is now serverside, this makes the time accurate in all situations.

* Removing ununsed import

* Minor tweaks

* Tweak in time precision

* Minor tweak + Unused import removed

* Edit: apparently RealTime is better for what I'm looking for

* Fix: Now the time is calculated correctly.

* Minor tweaks

* Adds condition for when the light should be updated

* Add planet lighting

* she

* close-ish

* c

* bittersweat

* Fixes

* Revert "Merge branch '22719' into 2024-09-29-planet-lighting"

This reverts commit 9f2785bb16aee47d794aa3eed8ae15004f97fc35, reversing
changes made to 19649c07a5fb625423e08fc18d91c9cb101daa86.

* Europa and day-night

* weh

* rooves working

* Clean

* Remove Europa

* Fixes

* fix

* Update

* Fix caves

* Update for engine

* Add sun shadows (planet lighting v2)

For now mostly targeting walls and having the shadows change over time. Got the basic proof-of-concept working just needs a hell of a lot of polish.

* Documentation

* a

* Fixes

* Move blur to an overlay

* Slughands

* Fixes

* Apply RoofOverlay per-grid not per-map

* Fix light render scales

* sangas

* Juice it a bit

* Better angle

* Fixes

* Add color support

* Rounding bandaid

* Wehs

* Better

* Remember I forgot to do this when writing docs

---------

Co-authored-by: DoutorWhite <thedoctorwhite@gmail.com>
2025-03-08 16:07:42 +11:00
metalgearsloth
db96cc7881 Update submodule to 248.0.0 (#35720) 2025-03-08 15:51:29 +11:00
metalgearsloth
a695a527f0 Update b2dynamictree (#30630) 2025-03-08 14:49:13 +11:00
PJBot
31a45a427c Automatic changelog update 2025-03-08 02:43:56 +00:00
Łukasz Mędrek
0be41cebb9 Text related keybinds can now be changed in Controls (#35630)
* Add ability to rebind text related keybinds

* fix placement of locales
2025-03-08 13:42:50 +11:00
PJBot
67f2c1ed58 Automatic changelog update 2025-03-08 02:40:11 +00:00
slarticodefast
531f5619be add forceghost admin command (#35518)
* add forceghost admin command

* sweep linq under the rug

* braces

* ûse LocalizedEntityCommands
2025-03-08 13:39:04 +11:00
deltanedas
cca537fb33 Add AssertMultiple to ContrabandTest (#35662)
* add AssertMultiple to ContrabandTest

* do the same for magazine visuals test

* :trollface:

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2025-03-08 13:37:26 +11:00
Vortebo
3fb80927cf clown gone 2025-03-07 17:02:46 -06:00
PJBot
00fec734f3 Automatic changelog update 2025-03-07 13:52:18 +00:00
ScarKy0
3281f408eb Cargo Mail System (#35429)
* shitcode init

* biocoding, SpawnTableOnUse, Moving shit to shared

* server :(

* fixes

* ok works

* Discard changes to Content.Shared/Interaction/Events/GettingUsedAttemptEvent.cs

* Discard changes to Content.Shared/Forensics/Components/FingerprintMaskComponent.cs

* Discard changes to Content.Shared/Forensics/Components/FingerprintComponent.cs

* Discard changes to Content.Server/Forensics/Systems/ForensicsSystem.cs

* Discard changes to Content.Server/StationRecords/Systems/StationRecordsSystem.cs

* Discard changes to Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs

* Discard changes to Content.Shared/Interaction/Events/GettingUsedAttemptEvent.cs

* big stuff

* preperation

* temperory spawning thing for testing

* Update CargoDeliveryDataComponent.cs

* kinda proper spawning idk god save me

* cleanup (kinda)

* preparation 2.0

* stuff i think

* entity table work

* renames

* spawn ratio based on players

* comment

* letter tables

* more spam

* package tables

* comment

* biocodedn't

* builds correctly

* cleaning

* Update deliveries_tables.yml

* labels

* package sprites

* mail teleporter

* revert testing value

* fix test

* fix other test

* i love tests

* mail teleporter enabled by default

* random cooldowns

* fixtures

* Discard changes to Content.Shared/FingerprintReader/FingerprintReaderComponent.cs

* Discard changes to Content.Shared/FingerprintReader/FingerprintReaderSystem.cs

* Discard changes to Content.Shared/Interaction/Events/GettingUsedAttemptEvent.cs

* Discard changes to Resources/Locale/en-US/fingerprint-reader/fingerprint-reader.ftl

* clean

* fuck paper scrap

* oops

* fuck SpawnTableOnUse

* mail teleporter board in QM locker + addressed review

* oops

* clean

* sound on delivery spawn

* address review

* partial review address

* partial review addressing

* addressing partial review

* pratarial revivew address

* misprediction hell

* stuff

* more stuff

* unrelated

* TODO

* link

* partial review

* DirtyField

---------

Co-authored-by: Milon <milonpl.git@proton.me>
2025-03-07 14:51:08 +01:00
Deerstop
5c12c1bf08 Elkridge Tesla and TEG Improvements + Other stuff (#35684)
* better tesla, better TEG, better sci maints, chef gets chef closet

* added storage room for tesla parts, added captain bathroom, changed vault so nuke can be armed

* ran fixgridatmos and added some vacuum markers

* unflatpacked containment shit
2025-03-07 01:25:05 -07:00
War Pigeon
fdb3082b90 Add firelocks and locked external airlocks to ATS (#35516)
* Add firelocks and locked airlocks to ATS

* Add fire alarms
2025-03-06 11:58:44 -07:00
Vortebo
e82bf065dc lightz 2025-03-05 20:06:10 -06:00
Vortebo
821baa0900 one hundred per cent historically authentic 2025-03-05 12:38:14 -06:00
PJBot
0a232908a4 Automatic changelog update 2025-03-05 16:26:49 +00:00
Errant
6f23e10495 Players with unknown playtimes now are tagged as new players, take 2 (#35648)
* your commit? our commit.

* skreee

* show joined players before lobby players; comments

* comments

* playerinfo retains playtime data after disconnect

* new connection status symbols
2025-03-05 08:25:42 -08:00
āda
b57b534380 Lathe menu UI displays a count of available recipes (#35570)
* commit

* jumped the gun

* changes
2025-03-05 23:31:48 +11:00
PJBot
657899f8b5 Automatic changelog update 2025-03-05 10:27:39 +00:00
Boaz1111
3bf38a4d46 More scars! (#35644)
* :3

* whitespace, stomach scar
2025-03-05 11:26:31 +01:00
Emisse
4c0ebb7f32 centcomm update (#35674) 2025-03-05 02:22:05 -07:00
PJBot
74e02022d6 Automatic changelog update 2025-03-05 09:15:11 +00:00
SlamBamActionman
27cfc0939c Add undergarments & "Censor Nudity" toggle to options (#33185)
* Initial commit

* Attribution

* Review changes

* Added comment for upstream
2025-03-05 10:14:01 +01:00
Vortebo
d3e1718da5 evacuate the dance floor 2025-03-04 17:04:12 -06:00
slarticodefast
8785085be6 Merge stable into master (#35669) 2025-03-04 22:24:29 +01:00
nikthechampiongr
e8c13fe325 Make implants unshielded (#35667) 2025-03-04 21:56:44 +01:00
Ps3Moira
0d01bb8894 Open State for cowtools (#35666)
Open State
2025-03-04 21:38:33 +01:00
Killerqu00
2d32e08bee CVar - Toggle display of round-end greentext (#35651)
* hide greentext if cvar false

* change IFs around a lil

* reviews
2025-03-04 08:59:44 -08:00
Vortebo
346bd8dd8b lights out 2025-03-04 09:24:51 -06:00
Vortebo
e67c7a7409 engineering walls more accurate 2025-03-04 09:24:16 -06:00
MisterImp
5774b71b9b Fix name of cotton dough rope (#35657)
changed in-game name of cotton dough rope to differentiate from normal dough rope
2025-03-04 03:56:48 +01:00
Vortebo
14c94968fc is this better? i cannot tell if it is better 2025-03-03 19:31:29 -06:00
Tayrtahn
50f7846bb1 Delete SolutionContainerVisualsComponent.InitialName (#35654) 2025-03-03 23:58:04 +01:00
PJBot
67b8f35a3c Automatic changelog update 2025-03-03 22:05:32 +00:00
DuckManZach
ff6c212335 Made butter require less milk (#35650)
made butter take less milk
2025-03-03 23:04:26 +01:00
Vortebo
f41c98b053 i dont have anything clever to say for this one 2025-03-03 15:08:23 -06:00
PJBot
3f7a9cad7c Automatic changelog update 2025-03-03 16:38:35 +00:00
rokudara-sen
8b7f175f84 Added decelerator percentage drain (#35643)
* Added variable PercentageDrain to SinguloFoodComponent

* Set percentageDrain to 0.03 (3%) for anti particles

* Added percentageDrain logic in public OnConsumed

* Simplify SinguloFoodComponent and set percentageDrain to negative

* EnergyFactor now applies to positive values too

* Better commenting on EnergyFactor

* Update Content.Server/Singularity/Components/SinguloFoodComponent.cs

* Documentation of EnergyFactor

* Fixing spelling mistake

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-03 11:37:28 -05:00
PJBot
69115870ea Automatic changelog update 2025-03-03 15:55:50 +00:00
Velken
7a89fe5d33 Wizard's Magical Pen (#35623)
* wizard pen

* description change
2025-03-03 16:54:43 +01:00
PJBot
ee690d9ee4 Automatic changelog update 2025-03-03 11:13:05 +00:00
Coolsurf6
913894a041 Changed Damage Overlay to check Burn Damage (#34535)
* updated BruteLevel to be PainLevel with burn damage checks in DamageOverlayUiController.cs

* dehardcoded pain level by adding damage groups to paindamagegroups to affect

* re-added the name for painDamageGroups

* fixed overlay default and added minimum limit to component check first

* renamed to PainDamageGroups and removed obsolete tag
2025-03-03 12:11:58 +01:00
PJBot
f42c1bc933 Automatic changelog update 2025-03-03 10:05:42 +00:00
Hannah Giovanna Dawson
78b2b361e8 Save Space Station 14 from the Toilet Gibber Forever (#35587)
* The evil is defeated

* Tag body bags

* uwu, cwush me cwusher-chan

* absolute 18+ sloggery

* botos binted? 👽
2025-03-03 11:04:33 +01:00
Errant
184edfe71d Merge stable to master (#35640) 2025-03-03 08:04:07 +01:00
Tayrtahn
7e7d12d437 Add GetBaseName method to NameModifierSystem (#35633)
* Add GetBaseName method to NameModifierSystem

* Use Name
2025-03-03 02:03:16 +01:00
PJBot
36021f1702 Automatic changelog update 2025-03-02 20:59:22 +00:00
HTML/Crystal
8fc78f63d9 Better Insectoid Glasses (#31812)
Sprites and file changes

Adds the variants for arachnid and moth glasses, adds the code for those in the meta.json files, and adds the speciesID tag in both arachnid and moth prototype files.
2025-03-02 15:58:15 -05:00
Emisse
5b078e3978 centcomm update (#35627) 2025-03-02 13:53:56 -07:00
slarticodefast
6f1df2b62f Merge stable into master (#35626) 2025-03-02 21:36:14 +01:00
PJBot
469bb1a9ec Automatic changelog update 2025-03-02 15:51:20 +00:00
slarticodefast
ceff2bea00 Cloning Refactor and bugfixes (#35555)
* cloning refactor

* cleanup and fixes

* don't pick from 0

* give dwarves the correct species

* fix dna and bloodstream reagent data cloning

* don't copy helmets

* be less redundant
2025-03-02 16:50:12 +01:00
Myra
02d3595faa Stable merge (#35620) 2025-03-02 13:58:59 +01:00
PJBot
ce7bb813d2 Automatic changelog update 2025-03-02 12:56:18 +00:00
Myra
51754f09ce #32209 changelog (#35619)
Since it was merged into staging no changelog was made, but we should at least have it for next release. (And vulture)
2025-03-02 13:55:10 +01:00
PJBot
7ea586cc1c Automatic changelog update 2025-03-02 02:49:00 +00:00
metalgearsloth
a8ebcac5c9 Predict vending machine UI (#33412) 2025-03-02 13:47:52 +11:00
PJBot
ba1504d0d6 Automatic changelog update 2025-03-02 02:31:03 +00:00
metalgearsloth
d9e86b3e81 Revert "Make radioactive material radioactive" (#35330) 2025-03-02 13:29:54 +11:00
deltanedas
66e926843f fix cluwne pda pen slot (#35611)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2025-03-02 00:33:24 +01:00
Vortebo
4a937edd27 goodbye salvage, you dont exist at all. no more salvage. my map cant account for having to deal with you so you arent real now 2025-03-01 16:53:33 -06:00
Ed
0563e0d67e Reagent guidebook reactions UI dividers (#35608)
* Update GuideReagentReaction.xaml

* Update Content.Client/Guidebook/Controls/GuideReagentReaction.xaml

Co-authored-by: Thomas <87614336+Aeshus@users.noreply.github.com>

* Update Content.Client/Guidebook/Controls/GuideReagentReaction.xaml

Co-authored-by: Thomas <87614336+Aeshus@users.noreply.github.com>

---------

Co-authored-by: Thomas <87614336+Aeshus@users.noreply.github.com>
2025-03-01 16:21:33 -06:00
hivehum
a926c53979 Give the station map inhand sprites (#35605)
map has inhands
2025-03-01 21:31:44 +01:00
PJBot
bb0c4c66fa Automatic changelog update 2025-03-01 20:26:00 +00:00
SlamBamActionman
9c970d203d Remove cellular resistance for slimes (#35583)
* Remove cellular resistance for slimes

* Update guidebook
2025-03-01 21:24:54 +01:00
ScarKy0
a54960eb81 Fingerprint Reader System (#35600)
* init

* public api

* stuff

* weh
2025-03-01 10:41:37 -08:00
PJBot
5bdc93b102 Automatic changelog update 2025-03-01 18:04:34 +00:00
ArtisticRoomba
deea33a36a DetGadget Hat Revitalization (#35438)
* DetGadget Hat

* uh... half-assed item description

* Reduce hat range to one tile, you have to stand on someone to steal their hat items

* Fix Integration Errors

* Only the wearer can access voice commands

* init work - handscomp is unable to be pulled

* second bit of progress

* basic working implementation

* nuke storageslots and add adminlogging

* disallow trolling nukies or hiding objective items

* remove unnecessary tags additions

* finish nuking unused tags

* death to yamllinter

* int tests be damned

* milon is a furry

* address review

* upd desc

* address reviews part 2

* address more reviews

* remove unused refs

* fix order of dependencies

* add ShowVerb to SharedStorageSystem.cs

This will allow or disallow showing the "Open Storage" verb if defined on the component.

* orks is a nerd

* add proper locale, fix adminlogging

* orks is a nerd 2

---------

Co-authored-by: Coenx-flex <coengmurray@gmail.com>
2025-03-01 19:03:27 +01:00
chromiumboy
10c868011e Sentry turrets - Part 3: Turret AI (#35058)
* Initial commit

* Updated Access/command.yml

* Fix for Access/AccessLevelPrototype.cs

* Added silicon access levels to admin items

* Included self-recharging battery changes

* Revert "Included self-recharging battery changes"

* Addressed reviewers comments

* Additional reviewer comments
2025-03-01 18:42:33 +01:00
FungiFellow
e8c812f90f Changed Pride to Hubris in ion_storm.yml (#35602)
Update ion_storm.yml
2025-03-01 18:19:19 +01:00
PJBot
212e942d21 Automatic changelog update 2025-03-01 14:09:40 +00:00
ScarKy0
5169ad4e8f Fix being able to write on/stamp/fax paper scrap (#35596)
* init

* item

* requested changes

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-01 15:08:34 +01:00
PJBot
e540f9cd50 Automatic changelog update 2025-03-01 09:57:36 +00:00
LaCumbiaDelCoronavirus
aa05cbb49b make slime hair less transparent (#35158)
* blabl blump or something

* +0.3

* blimpuf
2025-03-01 20:56:29 +11:00
Errant
1b20121114 Increase line spacing of the admin overlay (#35591)
line spacing
2025-03-01 03:17:07 +01:00
PJBot
6b84315928 Automatic changelog update 2025-03-01 02:13:31 +00:00
Velken
30a6ebdb26 Wizard PDA (#35572)
* wizard PDA

* colour change to brown
2025-03-01 03:12:24 +01:00
PJBot
01e4029a11 Automatic changelog update 2025-02-28 20:52:39 +00:00
Schrödinger
8ea888d821 [ADMIN] Minor Refactor AdminNameOverlay (#35520)
* refactor(src): Minor refactor of Draw in "AdminNameOverlay. And new info about playtime player

* fix(src): Add configure classic admin owerlay

* fix

* tweak(src): Use _antagLabelClassic and tweak style

* tweak(src): Add config display overlay for startingJob and playTime

* tweak(src): Vector2 is replaced by var

* tweak(src): return to the end of the list
2025-02-28 21:51:30 +01:00
Vortebo
e60318e59f this was annoying me 2025-02-28 13:30:37 -06:00
Vortebo
2a7c9ed267 its the tiny details that make a map feel finished 2025-02-28 12:21:30 -06:00
Vortebo
7462f9a376 lil flower shop 2025-02-28 09:01:02 -06:00
Southbridge
0c6db4db18 Amber Station - A Couple Changes (#35548) 2025-02-27 23:48:18 -07:00
Vortebo
63a6ffaa52 the walls, they move 2025-02-27 21:22:43 -06:00
Pancake
4442d5e277 Unheck Admin Smites (#35348)
* Fix admin verb names

Fixed admin verb names.

* Add antag verb names

* Adjust antag verb icons
2025-02-28 01:05:34 +01:00
PJBot
d8838e31d5 Automatic changelog update 2025-02-27 23:37:00 +00:00
Smith
38d72434fb Reptilians Can Eat Chicken Nuggets (#35569)
Added meat tag to misc.yml for chicken nuggets.
2025-02-28 00:35:52 +01:00
Smith
6b6ac9ac53 Doxarubixadone Description Fix (#35568)
Changed medicine.ftl for Doxa.
2025-02-28 00:18:36 +01:00
SlamBamActionman
1047e32944 Add new implants to deimplant list (#35563)
Initial commit
2025-02-27 20:23:59 +01:00
Vortebo
98c7010b16 Recklessly deleted power cables and atmos, excited to see what I accidentally broke in two weeks 2025-02-27 09:50:23 -06:00
Vortebo
ac7f99d46e atmos themed nightclub 2025-02-26 14:41:16 -06:00
Vortebo
213e88820a it hurts 2025-02-25 18:23:03 -06:00
Vortebo
30bdcd58fb Bridge window wall adjusted. 2025-02-25 16:33:35 -06:00
Vortebo
d364efb886 Bridge is now separated from the greytide only by a thin sheet of glass. 2025-02-25 15:57:37 -06:00
Vortebo
c781fde830 Addressed several playtest issues. 2025-02-25 11:04:05 -06:00
Vortebo
daccf98cca hotplate 2025-02-24 17:23:09 -06:00
TytosB
b788d15da7 latejoin 2025-02-17 16:21:16 -06:00
Nikolai Korolev
ee0ce4b220 Empty commit to rerun tests 2024-11-30 22:54:41 +00:00
Nikolai Korolev
ecb6540c61 Upgrade Github actions in Workfows to node20 2024-11-30 22:35:11 +00:00
2068 changed files with 118465 additions and 89521 deletions

View File

@@ -11,7 +11,7 @@ jobs:
name: Run Benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
with:
submodules: 'recursive'
- name: Get Engine version

View File

@@ -8,7 +8,7 @@ jobs:
docfx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
- name: Setup submodule
run: |
git submodule update --init --recursive
@@ -19,7 +19,7 @@ jobs:
cd RobustToolbox/
git submodule update --init --recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x

View File

@@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout Master
uses: actions/checkout@v3.6.0
uses: actions/checkout@v4.2.2
- name: Setup Submodule
run: |
@@ -34,7 +34,7 @@ jobs:
git submodule update --init --recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x

View File

@@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout Master
uses: actions/checkout@v3.6.0
uses: actions/checkout@v4.2.2
- name: Setup Submodule
run: |
@@ -34,7 +34,7 @@ jobs:
git submodule update --init --recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x

View File

@@ -10,6 +10,6 @@ jobs:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
- name: Check for CRLF
run: Tools/check_crlf.py

View File

@@ -16,11 +16,11 @@ jobs:
- name: Install dependencies
run: sudo apt-get install -y python3-paramiko python3-lxml
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
with:
submodules: 'recursive'
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x

View File

@@ -11,14 +11,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3.6.0
uses: actions/checkout@v4.2.2
- name: Get changed files
id: files
uses: Ana06/get-changed-files@v2.3.0
with:
format: 'space-delimited'
filter: |
filter: |
**.rsi
**.png

View File

@@ -34,7 +34,7 @@ jobs:
steps:
- name: Checkout Master
uses: actions/checkout@v3.6.0
uses: actions/checkout@v4.2.2
- name: Setup Submodule
run: |
@@ -49,7 +49,7 @@ jobs:
git submodule update --init --recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x

View File

@@ -4,19 +4,19 @@ on:
workflow_dispatch:
schedule:
- cron: 0 0 * * 0
jobs:
get_credits:
runs-on: ubuntu-latest
# Hey there fork dev! If you like to include your own contributors in this then you can probably just change this to your own repo
# Do this in dump_github_contributors.ps1 too into your own repo
if: github.repository == 'space-wizards/space-station-14'
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
with:
ref: master
- name: Get this week's Contributors
shell: pwsh
env:
@@ -25,25 +25,25 @@ jobs:
# TODO
#- name: Get this week's Patreons
# run: Tools/script2dumppatreons > Resources/Credits/Patrons.yml
# run: Tools/script2dumppatreons > Resources/Credits/Patrons.yml
# MAKE SURE YOU ENABLED "Allow GitHub Actions to create and approve pull requests" IN YOUR ACTIONS, OTHERWISE IT WILL MOST LIKELY FAIL
# For this you can use a pat token of an account with direct push access to the repo if you have protected branches.
# For this you can use a pat token of an account with direct push access to the repo if you have protected branches.
# Uncomment this and comment the other line if you do this.
# https://github.com/stefanzweifel/git-auto-commit-action#push-to-protected-branches
#- name: Commit new credit files
# uses: stefanzweifel/git-auto-commit-action@v4
# with:
# commit_message: Update Credits
# commit_author: PJBot <pieterjan.briers+bot@gmail.com>
# This will make a PR
- name: Set current date as env variable
run: echo "NOW=$(date +'%Y-%m-%dT%H-%M-%S')" >> $GITHUB_ENV
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:

View File

@@ -12,7 +12,7 @@ jobs:
if: github.actor != 'PJBot' && github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
- name: Setup Submodule
run: git submodule update --init
- name: Pull engine updates

View File

@@ -13,7 +13,7 @@ jobs:
name: Validate RSIs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
- name: Setup Submodule
run: git submodule update --init
- name: Pull engine updates

View File

@@ -12,7 +12,7 @@ jobs:
if: github.actor != 'PJBot' && github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
- name: Setup Submodule
run: git submodule update --init
- name: Pull engine updates

View File

@@ -13,7 +13,7 @@ jobs:
if: github.actor != 'PJBot' && github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
- uses: actions/checkout@v4.2.2
- name: Setup submodule
run: |
git submodule update --init --recursive
@@ -24,7 +24,7 @@ jobs:
cd RobustToolbox/
git submodule update --init --recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x
- name: Install dependencies

View File

@@ -1,7 +1,10 @@
using System.Linq;
using System.Numerics;
using Content.Client.Administration.Systems;
using Content.Client.Stylesheets;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.Ghost;
using Content.Shared.Mind;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
@@ -14,32 +17,54 @@ namespace Content.Client.Administration;
internal sealed class AdminNameOverlay : Overlay
{
[Dependency] private readonly IConfigurationManager _config = default!;
private readonly AdminSystem _system;
private readonly IEntityManager _entityManager;
private readonly IEyeManager _eyeManager;
private readonly EntityLookupSystem _entityLookup;
private readonly IUserInterfaceManager _userInterfaceManager;
private readonly Font _font;
private readonly Font _fontBold;
private bool _overlayClassic;
private bool _overlaySymbols;
private bool _overlayPlaytime;
private bool _overlayStartingJob;
private float _ghostFadeDistance;
private float _ghostHideDistance;
private int _overlayStackMax;
private float _overlayMergeDistance;
//TODO make this adjustable via GUI
private readonly ProtoId<RoleTypePrototype>[] _filter =
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"];
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
private readonly Color _antagColorClassic = Color.OrangeRed;
public AdminNameOverlay(AdminSystem system, IEntityManager entityManager, IEyeManager eyeManager, IResourceCache resourceCache, EntityLookupSystem entityLookup, IUserInterfaceManager userInterfaceManager)
public AdminNameOverlay(
AdminSystem system,
IEntityManager entityManager,
IEyeManager eyeManager,
IResourceCache resourceCache,
EntityLookupSystem entityLookup,
IUserInterfaceManager userInterfaceManager,
IConfigurationManager config)
{
IoCManager.InjectDependencies(this);
_system = system;
_entityManager = entityManager;
_eyeManager = eyeManager;
_entityLookup = entityLookup;
_userInterfaceManager = userInterfaceManager;
ZIndex = 200;
_font = new VectorFont(resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
// Setting these to a specific ttf would break the antag symbols
_font = resourceCache.NotoStack();
_fontBold = resourceCache.NotoStack(variation: "Bold");
config.OnValueChanged(CCVars.AdminOverlayClassic, (show) => { _overlayClassic = show; }, true);
config.OnValueChanged(CCVars.AdminOverlaySymbols, (show) => { _overlaySymbols = show; }, true);
config.OnValueChanged(CCVars.AdminOverlayPlaytime, (show) => { _overlayPlaytime = show; }, true);
config.OnValueChanged(CCVars.AdminOverlayStartingJob, (show) => { _overlayStartingJob = show; }, true);
config.OnValueChanged(CCVars.AdminOverlayGhostHideDistance, (f) => { _ghostHideDistance = f; }, true);
config.OnValueChanged(CCVars.AdminOverlayGhostFadeDistance, (f) => { _ghostFadeDistance = f; }, true);
config.OnValueChanged(CCVars.AdminOverlayStackMax, (i) => { _overlayStackMax = i; }, true);
config.OnValueChanged(CCVars.AdminOverlayMergeDistance, (f) => { _overlayMergeDistance = f; }, true);
}
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
@@ -47,75 +72,147 @@ internal sealed class AdminNameOverlay : Overlay
protected override void Draw(in OverlayDrawArgs args)
{
var viewport = args.WorldAABB;
var colorDisconnected = Color.White;
var uiScale = _userInterfaceManager.RootControl.UIScale;
var lineoffset = new Vector2(0f, 14f) * uiScale;
var drawnOverlays = new List<(Vector2,Vector2)>() ; // A saved list of the overlays already drawn
//TODO make this adjustable via GUI
var classic = _config.GetCVar(CCVars.AdminOverlayClassic);
var playTime = _config.GetCVar(CCVars.AdminOverlayPlaytime);
var startingJob = _config.GetCVar(CCVars.AdminOverlayStartingJob);
foreach (var playerInfo in _system.PlayerList)
// Get all player positions before drawing overlays, so they can be sorted before iteration
var sortable = new List<(PlayerInfo, Box2, EntityUid, Vector2)>();
foreach (var info in _system.PlayerList)
{
var entity = _entityManager.GetEntity(playerInfo.NetEntity);
var entity = _entityManager.GetEntity(info.NetEntity);
// Otherwise the entity can not exist yet
if (entity == null || !_entityManager.EntityExists(entity))
{
// If entity does not exist or is on a different map, skip
if (entity == null
|| !_entityManager.EntityExists(entity)
|| _entityManager.GetComponent<TransformComponent>(entity.Value).MapID != args.MapId)
continue;
}
// if not on the same map, continue
if (_entityManager.GetComponent<TransformComponent>(entity.Value).MapID != args.MapId)
{
continue;
}
var aabb = _entityLookup.GetWorldAABB(entity.Value);
// if not on screen, continue
// if not on screen, skip
if (!aabb.Intersects(in viewport))
{
continue;
}
var uiScale = _userInterfaceManager.RootControl.UIScale;
var lineoffset = new Vector2(0f, 14f) * uiScale;
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center +
new Angle(-_eyeManager.CurrentEye.Rotation).RotateVec(
aabb.TopRight - aabb.Center)) + new Vector2(1f, 7f);
// Get on-screen coordinates of player
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center).Rounded();
sortable.Add((info, aabb, entity.Value, screenCoordinates));
}
// Draw overlays for visible players, starting from the top of the screen
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
{
var playerInfo = info.Item1;
var aabb = info.Item2;
var entity = info.Item3;
var screenCoordinatesCenter = info.Item4;
//the center position is kept separately, for simpler position comparison later
var centerOffset = new Vector2(28f, -18f) * uiScale;
var screenCoordinates = screenCoordinatesCenter + centerOffset;
var alpha = 1f;
//TODO make a smarter system where the starting offset can be modified by the predicted position and size of already-drawn overlays/stacks?
var currentOffset = Vector2.Zero;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? Color.Aquamarine : Color.White);
// Ghosts near the cursor are made transparent/invisible
// TODO would be "cheaper" if playerinfo already contained a ghost bool, this gets called every frame for every onscreen player!
if (_entityManager.HasComponent<GhostComponent>(entity))
{
// We want the map positions here, so we don't have to worry about resolution and such shenanigans
var mobPosition = aabb.Center;
var mousePosition = _eyeManager
.ScreenToMap(_userInterfaceManager.MousePositionScaled.Position * uiScale)
.Position;
var dist = Vector2.Distance(mobPosition, mousePosition);
if (dist < _ghostHideDistance)
continue;
alpha = Math.Clamp((dist - _ghostHideDistance) / (_ghostFadeDistance - _ghostHideDistance), 0f, 1f);
colorDisconnected.A = alpha;
}
// If the new overlay text block is within merge distance of any previous ones
// merge them into a stack so they don't hide each other
var stack = drawnOverlays.FindAll(x =>
Vector2.Distance(_eyeManager.ScreenToMap(x.Item1).Position, aabb.Center) <= _overlayMergeDistance);
if (stack.Count > 0)
{
screenCoordinates = stack.First().Item1 + centerOffset;
// Replacing this overlay's coordinates for the later save with the stack root's coordinates
// so that other overlays don't try to stack to these coordinates
screenCoordinatesCenter = stack.First().Item1;
var i = 1;
foreach (var s in stack)
{
// additional entries after maximum stack size is reached will be drawn over the last entry
if (i <= _overlayStackMax - 1)
currentOffset = lineoffset + s.Item2 ;
i++;
}
}
// Character name
var color = Color.Aquamarine;
color.A = alpha;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? color : colorDisconnected);
currentOffset += lineoffset;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? Color.Yellow : Color.White);
// Username
color = Color.Yellow;
color.A = alpha;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? color : colorDisconnected);
currentOffset += lineoffset;
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && playTime)
// Playtime
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && _overlayPlaytime)
{
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.PlaytimeString, uiScale, playerInfo.Connected ? Color.Orange : Color.White);
color = Color.Orange;
color.A = alpha;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.PlaytimeString, uiScale, playerInfo.Connected ? color : colorDisconnected);
currentOffset += lineoffset;
}
if (!string.IsNullOrEmpty(playerInfo.StartingJob) && startingJob)
// Job
if (!string.IsNullOrEmpty(playerInfo.StartingJob) && _overlayStartingJob)
{
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, Loc.GetString(playerInfo.StartingJob), uiScale, playerInfo.Connected ? Color.GreenYellow : Color.White);
color = Color.GreenYellow;
color.A = alpha;
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, Loc.GetString(playerInfo.StartingJob), uiScale, playerInfo.Connected ? color : colorDisconnected);
currentOffset += lineoffset;
}
if (classic && playerInfo.Antag)
// Classic Antag Label
if (_overlayClassic && playerInfo.Antag)
{
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, _antagLabelClassic, uiScale, Color.OrangeRed);
var symbol = _overlaySymbols ? Loc.GetString("player-tab-antag-prefix") : string.Empty;
var label = _overlaySymbols
? Loc.GetString("player-tab-character-name-antag-symbol",
("symbol", symbol),
("name", _antagLabelClassic))
: _antagLabelClassic;
color = Color.OrangeRed;
color.A = alpha;
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
currentOffset += lineoffset;
}
else if (!classic && _filter.Contains(playerInfo.RoleProto))
// Role Type
else if (!_overlayClassic && _filter.Contains(playerInfo.RoleProto))
{
var label = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
var color = playerInfo.RoleProto.Color;
var symbol = _overlaySymbols && playerInfo.Antag ? playerInfo.RoleProto.Symbol : string.Empty;
var role = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
var label = _overlaySymbols
? Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", role))
: role;
color = playerInfo.RoleProto.Color;
color.A = alpha;
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
currentOffset += lineoffset;
}
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, label, uiScale, color);
currentOffset += lineoffset;
}
//Save the coordinates and size of the text block, for stack merge check
drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
}
}
}

View File

@@ -14,6 +14,7 @@ namespace Content.Client.Administration.Systems
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
private AdminNameOverlay _adminNameOverlay = default!;
@@ -22,7 +23,14 @@ namespace Content.Client.Administration.Systems
private void InitializeOverlay()
{
_adminNameOverlay = new AdminNameOverlay(this, EntityManager, _eyeManager, _resourceCache, _entityLookup, _userInterfaceManager);
_adminNameOverlay = new AdminNameOverlay(
this,
EntityManager,
_eyeManager,
_resourceCache,
_entityLookup,
_userInterfaceManager,
_configurationManager);
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
}

View File

@@ -2,14 +2,14 @@
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls">
<PanelContainer StyleClasses="BackgroundDark">
<SplitContainer Orientation="Vertical">
<SplitContainer Orientation="Vertical" ResizeMode="NotResizable">
<SplitContainer Orientation="Horizontal" VerticalExpand="True">
<cc:PlayerListControl Access="Public" Name="ChannelSelector" HorizontalExpand="True" SizeFlagsStretchRatio="2" />
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="2">
<BoxContainer Access="Public" Name="BwoinkArea" VerticalExpand="True" />
</BoxContainer>
</SplitContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal" SetHeight="30" >
<CheckBox Name="AdminOnly" Access="Public" Text="{Loc 'admin-ahelp-admin-only'}" ToolTip="{Loc 'admin-ahelp-admin-only-tooltip'}" />
<Control HorizontalExpand="True" MinWidth="5" />
<CheckBox Name="PlaySound" Access="Public" Text="{Loc 'admin-bwoink-play-sound'}" Pressed="True" />

View File

@@ -2,11 +2,13 @@ using System.Linq;
using Content.Client.Administration.Systems;
using Content.Client.UserInterface.Controls;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using static Content.Client.Administration.UI.Tabs.PlayerTab.PlayerTabHeader;
using static Robust.Client.UserInterface.Controls.BaseButton;
@@ -16,6 +18,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
public sealed partial class PlayerTab : Control
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly IPlayerManager _playerMan = default!;
private const string ArrowUp = "↑";
@@ -41,6 +44,10 @@ public sealed partial class PlayerTab : Control
_adminSystem.OverlayEnabled += OverlayEnabled;
_adminSystem.OverlayDisabled += OverlayDisabled;
_config.OnValueChanged(CCVars.AdminPlayerlistSeparateSymbols, PlayerListSettingsChanged);
_config.OnValueChanged(CCVars.AdminPlayerlistHighlightedCharacterColor, PlayerListSettingsChanged);
_config.OnValueChanged(CCVars.AdminPlayerlistRoleTypeColor, PlayerListSettingsChanged);
OverlayButton.OnPressed += OverlayButtonPressed;
ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed;
@@ -106,6 +113,11 @@ public sealed partial class PlayerTab : Control
#region ListContainer
private void PlayerListSettingsChanged(bool _)
{
RefreshPlayerList(_adminSystem.PlayerList);
}
private void RefreshPlayerList(IReadOnlyList<PlayerInfo> players)
{
_players = players;
@@ -196,8 +208,7 @@ public sealed partial class PlayerTab : Control
Header.Username => Compare(x.Username, y.Username),
Header.Character => Compare(x.CharacterName, y.CharacterName),
Header.Job => Compare(x.StartingJob, y.StartingJob),
Header.Antagonist => x.Antag.CompareTo(y.Antag),
Header.RoleType => Compare(x.RoleProto.Name , y.RoleProto.Name),
Header.RoleType => y.SortWeight - x.SortWeight,
Header.Playtime => TimeSpan.Compare(x.OverallPlaytime ?? default, y.OverallPlaytime ?? default),
_ => 1
};

View File

@@ -19,11 +19,6 @@
HorizontalExpand="True"
ClipText="True"/>
<customControls:VSeparator/>
<Label Name="AntagonistLabel"
SizeFlagsStretchRatio="1"
HorizontalExpand="True"
ClipText="True"/>
<customControls:VSeparator/>
<Label Name="RoleTypeLabel"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"

View File

@@ -1,8 +1,10 @@
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
@@ -14,17 +16,25 @@ public sealed partial class PlayerTabEntry : PanelContainer
public PlayerTabEntry(PlayerInfo player, StyleBoxFlat styleBoxFlat)
{
RobustXamlLoader.Load(this);
var config = IoCManager.Resolve<IConfigurationManager>();
UsernameLabel.Text = player.Username;
if (!player.Connected)
UsernameLabel.StyleClasses.Add("Disabled");
JobLabel.Text = player.StartingJob;
CharacterLabel.Text = player.CharacterName;
var separateAntagSymbols = config.GetCVar(CCVars.AdminPlayerlistSeparateSymbols);
var genericAntagSymbol = player.Antag ? Loc.GetString("player-tab-antag-prefix") : string.Empty;
var roleSymbol = player.Antag ? player.RoleProto.Symbol : string.Empty;
var symbol = separateAntagSymbols ? roleSymbol : genericAntagSymbol;
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
if (player.Antag && config.GetCVar(CCVars.AdminPlayerlistHighlightedCharacterColor))
CharacterLabel.FontColorOverride = player.RoleProto.Color;
if (player.IdentityName != player.CharacterName)
CharacterLabel.Text += $" [{player.IdentityName}]";
AntagonistLabel.Text = Loc.GetString(player.Antag ? "player-tab-is-antag-yes" : "player-tab-is-antag-no");
RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name);
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
if (config.GetCVar(CCVars.AdminPlayerlistRoleTypeColor))
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
BackgroundColorPanel.PanelOverride = styleBoxFlat;
OverallPlaytimeLabel.Text = player.PlaytimeString;
PlayerEntity = player.NetEntity;

View File

@@ -25,13 +25,6 @@
Text="{Loc player-tab-job}"
MouseFilter="Pass"/>
<cc:VSeparator/>
<Label Name="AntagonistLabel"
SizeFlagsStretchRatio="1"
HorizontalExpand="True"
ClipText="True"
Text="{Loc player-tab-antagonist}"
MouseFilter="Pass"/>
<cc:VSeparator/>
<Label Name="RoleTypeLabel"
SizeFlagsStretchRatio="2"
HorizontalExpand="True"

View File

@@ -18,7 +18,6 @@ public sealed partial class PlayerTabHeader : Control
UsernameLabel.OnKeyBindDown += UsernameClicked;
CharacterLabel.OnKeyBindDown += CharacterClicked;
JobLabel.OnKeyBindDown += JobClicked;
AntagonistLabel.OnKeyBindDown += AntagonistClicked;
RoleTypeLabel.OnKeyBindDown += RoleTypeClicked;
PlaytimeLabel.OnKeyBindDown += PlaytimeClicked;
}
@@ -30,7 +29,6 @@ public sealed partial class PlayerTabHeader : Control
Header.Username => UsernameLabel,
Header.Character => CharacterLabel,
Header.Job => JobLabel,
Header.Antagonist => AntagonistLabel,
Header.RoleType => RoleTypeLabel,
Header.Playtime => PlaytimeLabel,
_ => throw new ArgumentOutOfRangeException(nameof(header), header, null)
@@ -42,7 +40,6 @@ public sealed partial class PlayerTabHeader : Control
UsernameLabel.Text = Loc.GetString("player-tab-username");
CharacterLabel.Text = Loc.GetString("player-tab-character");
JobLabel.Text = Loc.GetString("player-tab-job");
AntagonistLabel.Text = Loc.GetString("player-tab-antagonist");
RoleTypeLabel.Text = Loc.GetString("player-tab-roletype");
PlaytimeLabel.Text = Loc.GetString("player-tab-playtime");
}
@@ -73,11 +70,6 @@ public sealed partial class PlayerTabHeader : Control
HeaderClicked(args, Header.Job);
}
private void AntagonistClicked(GUIBoundKeyEventArgs args)
{
HeaderClicked(args, Header.Antagonist);
}
private void RoleTypeClicked(GUIBoundKeyEventArgs args)
{
HeaderClicked(args, Header.RoleType);
@@ -97,7 +89,6 @@ public sealed partial class PlayerTabHeader : Control
UsernameLabel.OnKeyBindDown -= UsernameClicked;
CharacterLabel.OnKeyBindDown -= CharacterClicked;
JobLabel.OnKeyBindDown -= JobClicked;
AntagonistLabel.OnKeyBindDown -= AntagonistClicked;
RoleTypeLabel.OnKeyBindDown -= RoleTypeClicked;
PlaytimeLabel.OnKeyBindDown -= PlaytimeClicked;
}
@@ -108,7 +99,6 @@ public sealed partial class PlayerTabHeader : Control
Username,
Character,
Job,
Antagonist,
RoleType,
Playtime
}

View File

@@ -52,7 +52,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
if (args.Current is not AlertComponentState cast)
return;
alerts.Comp.Alerts = cast.Alerts;
alerts.Comp.Alerts = new(cast.Alerts);
UpdateHud(alerts);
}

View File

@@ -0,0 +1,5 @@
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem;

View File

@@ -0,0 +1,32 @@
<Control xmlns="https://spacestation14.io" xmlns:system="clr-namespace:System;assembly=System.Runtime">
<BoxContainer Name="MainContainer"
Orientation="Horizontal"
SetWidth="250">
<Button Name="MainButton"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="ButtonSquare"
Margin="-1 0 0 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Margin="-5 0 0 0">
<Label Name="TaskLabel"
StyleClasses="LabelSubText" />
<Label Name="TaskForLabel"
StyleClasses="LabelSubText"
Margin="0 -5 0 0" />
</BoxContainer>
</BoxContainer>
</Button>
<Button Name="DoneButton"
VerticalExpand="True"
Text="{Loc 'nano-task-ui-done'}">
<Button.StyleClasses>
<system:String>ButtonSmall</system:String>
<system:String>OpenLeft</system:String>
</Button.StyleClasses>
</Button>
</BoxContainer>
</Control>

View File

@@ -0,0 +1,33 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Maths;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// Represents a single control for a single NanoTask item
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class NanoTaskItemControl : Control
{
public Action<int>? OnMainPressed;
public Action<int>? OnDonePressed;
public NanoTaskItemControl(NanoTaskItemAndId item)
{
RobustXamlLoader.Load(this);
TaskLabel.Text = item.Data.Description;
TaskLabel.FontColorOverride = Color.White;
TaskForLabel.Text = item.Data.TaskIsFor;
MainButton.OnPressed += _ => OnMainPressed?.Invoke(item.Id);
DoneButton.OnPressed += _ => OnDonePressed?.Invoke(item.Id);
MainButton.Disabled = item.Data.IsTaskDone;
DoneButton.Text = item.Data.IsTaskDone ? Loc.GetString("nano-task-ui-revert-done") : Loc.GetString("nano-task-ui-done");
}
}

View File

@@ -0,0 +1,67 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc nano-task-ui-item-title}"
MinSize="300 300">
<PanelContainer StyleClasses="AngleRect">
<BoxContainer Orientation="Vertical" Margin="4">
<!-- Task Description Input -->
<BoxContainer Orientation="Vertical" Margin="0 4">
<Label Text="{Loc nano-task-ui-description-label}"
StyleClasses="LabelHeading" />
<PanelContainer StyleClasses="ButtonSquare">
<LineEdit Name="DescriptionInput"
PlaceHolder="{Loc nano-task-ui-description-placeholder}" />
</PanelContainer>
</BoxContainer>
<!-- Task Requester Input -->
<BoxContainer Orientation="Vertical" Margin="0 4">
<Label Text="{Loc nano-task-ui-requester-label}"
StyleClasses="LabelHeading" />
<PanelContainer StyleClasses="ButtonSquare">
<LineEdit Name="RequesterInput"
PlaceHolder="{Loc nano-task-ui-requester-placeholder}" />
</PanelContainer>
</BoxContainer>
<!-- Severity Buttons -->
<BoxContainer Orientation="Horizontal"
HorizontalAlignment="Center"
Margin="0 8 0 0">
<Button Name="LowButton"
Text="{Loc nano-task-ui-priority-low}"
StyleClasses="OpenRight"
MinSize="60 0" />
<Button Name="MediumButton"
Text="{Loc nano-task-ui-priority-medium}"
StyleClasses="ButtonSquare"
MinSize="60 0" />
<Button Name="HighButton"
Text="{Loc nano-task-ui-priority-high}"
StyleClasses="OpenLeft"
MinSize="60 0" />
</BoxContainer>
<!-- Verb Buttons -->
<BoxContainer Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="0 8 0 0">
<Button Name="CancelButton"
Text="{Loc nano-task-ui-cancel}"
StyleClasses="OpenRight"
MinSize="60 0" />
<Button Name="DeleteButton"
Text="{Loc nano-task-ui-delete}"
StyleClasses="ButtonSquare"
MinSize="60 0" />
<Button Name="PrintButton"
Text="{Loc nano-task-ui-print}"
StyleClasses="ButtonSquare"
MinSize="60 0" />
<Button Name="SaveButton"
Text="{Loc nano-task-ui-save}"
StyleClasses="OpenLeft"
MinSize="60 0" />
</BoxContainer>
</BoxContainer>
</PanelContainer>
</DefaultWindow>

View File

@@ -0,0 +1,109 @@
using System.Linq;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.UserInterface.Controls;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// Popup displayed to edit a NanoTask item
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class NanoTaskItemPopup : DefaultWindow
{
private readonly ButtonGroup _priorityGroup = new();
private int? _editingTaskId = null;
public Action<int, NanoTaskItem>? TaskSaved;
public Action<int>? TaskDeleted;
public Action<NanoTaskItem>? TaskCreated;
public Action<NanoTaskItem>? TaskPrinted;
private NanoTaskItem MakeItem()
{
return new(
description: DescriptionInput.Text,
taskIsFor: RequesterInput.Text,
isTaskDone: false,
priority: _priorityGroup.Pressed switch {
var item when item == LowButton => NanoTaskPriority.Low,
var item when item == MediumButton => NanoTaskPriority.Medium,
var item when item == HighButton => NanoTaskPriority.High,
_ => NanoTaskPriority.Medium,
}
);
}
public NanoTaskItemPopup()
{
RobustXamlLoader.Load(this);
LowButton.Group = _priorityGroup;
MediumButton.Group = _priorityGroup;
HighButton.Group = _priorityGroup;
CancelButton.OnPressed += _ => Close();
DeleteButton.OnPressed += _ =>
{
if (_editingTaskId is int id)
{
TaskDeleted?.Invoke(id);
}
};
PrintButton.OnPressed += _ =>
{
TaskPrinted?.Invoke(MakeItem());
};
SaveButton.OnPressed += _ =>
{
if (_editingTaskId is int id)
{
TaskSaved?.Invoke(id, MakeItem());
}
else
{
TaskCreated?.Invoke(MakeItem());
}
};
DescriptionInput.OnTextChanged += args =>
{
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
DescriptionInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
};
RequesterInput.OnTextChanged += args =>
{
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
RequesterInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
};
}
public void SetEditingTaskId(int? id)
{
_editingTaskId = id;
DeleteButton.Visible = id is not null;
}
public void ResetInputs(NanoTaskItem? item)
{
if (item is NanoTaskItem task)
{
var button = task.Priority switch {
NanoTaskPriority.High => HighButton,
NanoTaskPriority.Medium => MediumButton,
NanoTaskPriority.Low => LowButton,
};
button.Pressed = true;
DescriptionInput.Text = task.Description;
RequesterInput.Text = task.TaskIsFor;
}
else
{
MediumButton.Pressed = true;
DescriptionInput.Text = "";
RequesterInput.Text = "";
}
}
}

View File

@@ -0,0 +1,82 @@
using System.Linq;
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// UI fragment responsible for displaying NanoTask controls in a PDA and coordinating with the NanoTaskCartridgeSystem for state
/// </summary>
public sealed partial class NanoTaskUi : UIFragment
{
private NanoTaskUiFragment? _fragment;
private NanoTaskItemPopup? _popup;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new NanoTaskUiFragment();
_popup = new NanoTaskItemPopup();
_fragment.NewTask += () =>
{
_popup.ResetInputs(null);
_popup.SetEditingTaskId(null);
_popup.OpenCentered();
};
_fragment.OpenTask += id =>
{
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
return;
_popup.ResetInputs(task.Data);
_popup.SetEditingTaskId(task.Id);
_popup.OpenCentered();
};
_fragment.ToggleTaskCompletion += id =>
{
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
return;
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, new(
description: task.Data.Description,
taskIsFor: task.Data.TaskIsFor,
isTaskDone: !task.Data.IsTaskDone,
priority: task.Data.Priority
))))));
};
_popup.TaskSaved += (id, data) =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, data)))));
_popup.Close();
};
_popup.TaskDeleted += id =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskDeleteTask(id))));
_popup.Close();
};
_popup.TaskCreated += data =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskAddTask(data))));
_popup.Close();
};
_popup.TaskPrinted += data =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskPrintTask(data))));
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not NanoTaskUiState nanoTaskState)
return;
_fragment?.UpdateState(nanoTaskState.Tasks);
}
}

View File

@@ -0,0 +1,58 @@
<cartridges:NanoTaskUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns="https://spacestation14.io" Margin="1 0 2 0">
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical" Margin="8" SeparationOverride="8">
<!-- Heading for High Priority Items -->
<BoxContainer Orientation="Horizontal">
<PanelContainer SetWidth="7" Margin="0 0 8 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#e93d58"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="HighPriority" StyleClasses="LabelHeading"/>
</BoxContainer>
<!-- Location for High Priority Items -->
<GridContainer Name="HighContainer"
HorizontalExpand="True"
Access="Public"
Columns="2" />
<!-- Heading for Medium Priority Items -->
<BoxContainer Orientation="Horizontal">
<PanelContainer SetWidth="7" Margin="0 0 8 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#ef973c"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="MediumPriority" StyleClasses="LabelHeading"/>
</BoxContainer>
<!-- Location for Medium Priority Items -->
<GridContainer Name="MediumContainer"
HorizontalExpand="True"
Access="Public"
Columns="2" />
<!-- Location for Low Priority Items -->
<BoxContainer Orientation="Horizontal">
<PanelContainer SetWidth="7" Margin="0 0 8 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#3dd425"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="LowPriority" StyleClasses="LabelHeading"/>
</BoxContainer>
<!-- Location for Low Priority Items -->
<GridContainer Name="LowContainer"
HorizontalExpand="True"
Access="Public"
Columns="2" />
<Button Name="NewTaskButton" Text="{Loc 'nano-task-ui-new-task'}" HorizontalAlignment="Right"/>
</BoxContainer>
</ScrollContainer>
</BoxContainer>
</cartridges:NanoTaskUiFragment>

View File

@@ -0,0 +1,52 @@
using System.Linq;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// Class displaying the main UI of NanoTask
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class NanoTaskUiFragment : BoxContainer
{
public Action<int>? OpenTask;
public Action<int>? ToggleTaskCompletion;
public Action? NewTask;
public List<NanoTaskItemAndId> Tasks = new();
public NanoTaskUiFragment()
{
RobustXamlLoader.Load(this);
Orientation = LayoutOrientation.Vertical;
HorizontalExpand = true;
VerticalExpand = true;
NewTaskButton.OnPressed += _ => NewTask?.Invoke();
}
public void UpdateState(List<NanoTaskItemAndId> tasks)
{
Tasks = tasks;
HighContainer.RemoveAllChildren();
MediumContainer.RemoveAllChildren();
LowContainer.RemoveAllChildren();
HighPriority.Text = Loc.GetString("nano-task-ui-heading-high-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.High)));
MediumPriority.Text = Loc.GetString("nano-task-ui-heading-medium-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Medium)));
LowPriority.Text = Loc.GetString("nano-task-ui-heading-low-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Low)));
foreach (var task in tasks)
{
var container = task.Data.Priority switch {
NanoTaskPriority.High => HighContainer,
NanoTaskPriority.Medium => MediumContainer,
NanoTaskPriority.Low => LowContainer,
};
var control = new NanoTaskItemControl(task);
container.AddChild(control);
control.OnMainPressed += id => OpenTask?.Invoke(id);
control.OnDonePressed += id => ToggleTaskCompletion?.Invoke(id);
}
}
}

View File

@@ -131,13 +131,13 @@ public sealed partial class ChangelogTab : Control
Margin = new Thickness(6, 0, 0, 0),
};
authorLabel.SetMessage(
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", author))));
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", FormattedMessage.EscapeText(author)))));
ChangelogBody.AddChild(authorLabel);
foreach (var change in groupedEntry.SelectMany(c => c.Changes))
{
var text = new RichTextLabel();
text.SetMessage(FormattedMessage.FromMarkupOrThrow(change.Message));
text.SetMessage(FormattedMessage.FromUnformatted(change.Message));
ChangelogBody.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,

View File

@@ -169,7 +169,7 @@ public sealed class ClientClothingSystem : ClothingSystem
var state = $"equipped-{correctedSlot}";
if (clothing.EquippedPrefix != null)
if (!string.IsNullOrEmpty(clothing.EquippedPrefix))
state = $"{clothing.EquippedPrefix}-equipped-{correctedSlot}";
if (clothing.EquippedState != null)

View File

@@ -3,6 +3,7 @@ using Content.Shared.Access.Systems;
using Content.Shared.Administration;
using Content.Shared.CriminalRecords;
using Content.Shared.Dataset;
using Content.Shared.Random.Helpers;
using Content.Shared.Security;
using Content.Shared.StationRecords;
using Robust.Client.AutoGenerated;
@@ -32,7 +33,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
public readonly EntityUid Console;
[ValidatePrototypeId<DatasetPrototype>]
[ValidatePrototypeId<LocalizedDatasetPrototype>]
private const string ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
public Action<uint?>? OnKeySelected;
@@ -333,8 +334,8 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
var field = "reason";
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
var placeholders = _proto.Index<DatasetPrototype>(ReasonPlaceholders);
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders.Values))); // just funny it doesn't actually get used
var placeholders = _proto.Index<LocalizedDatasetPrototype>(ReasonPlaceholders);
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used
var prompt = Loc.GetString("criminal-records-console-reason");
var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder);
var entries = new List<QuickDialogEntry>() { entry };

View File

@@ -4,6 +4,7 @@ using Content.Shared.Verbs;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.Utility;
using Robust.Shared.Utility;
@@ -40,7 +41,17 @@ public sealed class ExamineButton : ContainerButton
Disabled = true;
}
ToolTip = verb.Message ?? verb.Text;
TooltipSupplier = sender =>
{
var label = new RichTextLabel();
label.SetMessage(FormattedMessage.FromMarkupOrThrow(verb.Message ?? verb.Text));
var tooltip = new Tooltip();
tooltip.GetChild(0).Children.Clear();
tooltip.GetChild(0).Children.Add(label);
return tooltip;
};
Icon = new TextureRect
{

View File

@@ -298,10 +298,28 @@ namespace Content.Client.Examine
{
Name = "ExamineButtonsHBox",
Orientation = LayoutOrientation.Horizontal,
HorizontalAlignment = Control.HAlignment.Right,
HorizontalAlignment = Control.HAlignment.Stretch,
VerticalAlignment = Control.VAlignment.Bottom,
};
var hoverExamineBox = new BoxContainer
{
Name = "HoverExamineHBox",
Orientation = LayoutOrientation.Horizontal,
HorizontalAlignment = Control.HAlignment.Left,
VerticalAlignment = Control.VAlignment.Center,
HorizontalExpand = true
};
var clickExamineBox = new BoxContainer
{
Name = "ClickExamineHBox",
Orientation = LayoutOrientation.Horizontal,
HorizontalAlignment = Control.HAlignment.Right,
VerticalAlignment = Control.VAlignment.Center,
HorizontalExpand = true
};
// Examine button time
foreach (var verb in verbs)
{
@@ -316,8 +334,15 @@ namespace Content.Client.Examine
var button = new ExamineButton(examine);
button.OnPressed += VerbButtonPressed;
buttonsHBox.AddChild(button);
if (examine.HoverVerb)
{
hoverExamineBox.AddChild(button);
}
else
{
button.OnPressed += VerbButtonPressed;
clickExamineBox.AddChild(button);
}
}
var vbox = _examineTooltipOpen?.GetChild(0).GetChild(0);
@@ -334,6 +359,8 @@ namespace Content.Client.Examine
{
vbox.Children.Remove(hbox.First());
}
buttonsHBox.AddChild(hoverExamineBox);
buttonsHBox.AddChild(clickExamineBox);
vbox.AddChild(buttonsHBox);
}

View File

@@ -29,24 +29,25 @@
VerticalAlignment="Center"
Access="Public"
Visible="False" />
<!-- CP14 random reactions begin -->
<BoxContainer Name="RandomVariations"
Orientation="Vertical"
VerticalExpand="True"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<controls:SplitBar MinHeight="10">
</controls:SplitBar>
<Label Name="RandomVariationsLabel"
Text="{Loc 'cp14-guidebook-random-variations-title'}"
Visible="False"
HorizontalAlignment="Center"
FontColorOverride="#1e6651" />
<controls:SplitBar MinHeight="10">
</controls:SplitBar>
</BoxContainer>
<!-- CP14 random reactions end -->
</BoxContainer>
<!-- CP14 random reactions begin -->
<BoxContainer Name="RandomVariations"
Orientation="Vertical"
VerticalExpand="True"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<controls:SplitBar MinHeight="10">
</controls:SplitBar>
<Label Name="RandomVariationsLabel"
Text="{Loc 'cp14-guidebook-random-variations-title'}"
Visible="False"
HorizontalAlignment="Center"
FontColorOverride="#1e6651" />
<controls:SplitBar MinHeight="10">
</controls:SplitBar>
</BoxContainer>
<!-- CP14 random reactions end -->
</BoxContainer>
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5" />
</BoxContainer>

View File

@@ -2,6 +2,7 @@ using Content.Shared.CCVar;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Robust.Client.GameObjects;
using Robust.Shared.Configuration;
@@ -48,7 +49,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
}
private static bool IsHidden(HumanoidAppearanceComponent humanoid, HumanoidVisualLayers layer)
=> humanoid.HiddenLayers.Contains(layer) || humanoid.PermanentlyHidden.Contains(layer);
=> humanoid.HiddenLayers.ContainsKey(layer) || humanoid.PermanentlyHidden.Contains(layer);
private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent sprite)
{
@@ -57,7 +58,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
// add default species layers
var speciesProto = _prototypeManager.Index(component.Species);
var baseSprites = _prototypeManager.Index<HumanoidSpeciesBaseSpritesPrototype>(speciesProto.SpriteSet);
var baseSprites = _prototypeManager.Index(speciesProto.SpriteSet);
foreach (var (key, id) in baseSprites.Sprites)
{
oldLayers.Remove(key);
@@ -214,7 +215,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
humanoid.MarkingSet = markings;
humanoid.PermanentlyHidden = new HashSet<HumanoidVisualLayers>();
humanoid.HiddenLayers = new HashSet<HumanoidVisualLayers>();
humanoid.HiddenLayers = new Dictionary<HumanoidVisualLayers, SlotFlags>();
humanoid.CustomBaseLayers = customBaseLayers;
humanoid.Sex = profile.Sex;
humanoid.Gender = profile.Gender;
@@ -402,23 +403,21 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
}
}
protected override void SetLayerVisibility(
EntityUid uid,
HumanoidAppearanceComponent humanoid,
public override void SetLayerVisibility(
Entity<HumanoidAppearanceComponent> ent,
HumanoidVisualLayers layer,
bool visible,
bool permanent,
SlotFlags? slot,
ref bool dirty)
{
base.SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty);
base.SetLayerVisibility(ent, layer, visible, slot, ref dirty);
var sprite = Comp<SpriteComponent>(uid);
var sprite = Comp<SpriteComponent>(ent);
if (!sprite.LayerMapTryGet(layer, out var index))
{
if (!visible)
return;
else
index = sprite.LayerMapReserveBlank(layer);
index = sprite.LayerMapReserveBlank(layer);
}
var spriteLayer = sprite[index];
@@ -428,13 +427,14 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
spriteLayer.Visible = visible;
// I fucking hate this. I'll get around to refactoring sprite layers eventually I swear
// Just a week away...
foreach (var markingList in humanoid.MarkingSet.Markings.Values)
foreach (var markingList in ent.Comp.MarkingSet.Markings.Values)
{
foreach (var marking in markingList)
{
if (_markingManager.TryGetMarking(marking, out var markingPrototype) && markingPrototype.BodyPart == layer)
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite);
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, ent, sprite);
}
}
}

View File

@@ -84,6 +84,9 @@ namespace Content.Client.Input
human.AddFunction(ContentKeyFunctions.Arcade1);
human.AddFunction(ContentKeyFunctions.Arcade2);
human.AddFunction(ContentKeyFunctions.Arcade3);
//CP14 Keys
human.AddFunction(ContentKeyFunctions.CP14OpenSkillMenu);
//CP14 Keys end
// actions should be common (for ghosts, mobs, etc)
common.AddFunction(ContentKeyFunctions.OpenActionsMenu);
@@ -123,10 +126,6 @@ namespace Content.Client.Input
common.AddFunction(ContentKeyFunctions.OpenDecalSpawnWindow);
common.AddFunction(ContentKeyFunctions.OpenAdminMenu);
common.AddFunction(ContentKeyFunctions.OpenGuidebook);
//CP14 Keys
human.AddFunction(ContentKeyFunctions.CP14OpenKnowledgeMenu);
//CP14 Keys end
}
}
}

View File

@@ -68,21 +68,13 @@ public sealed partial class LatheMenu : DefaultWindow
{
ServerListButton.Visible = false;
}
AmountLineEdit.SetText(latheComponent.DefaultProductionAmount.ToString());
}
MaterialsList.SetOwner(Entity);
}
protected override void Opened()
{
base.Opened();
if (_entityManager.TryGetComponent<LatheComponent>(Entity, out var latheComp))
{
AmountLineEdit.SetText(latheComp.DefaultProductionAmount.ToString());
}
}
/// <summary>
/// Populates the list of all the recipes
/// </summary>

View File

@@ -4,7 +4,20 @@
<BoxContainer Orientation="Vertical">
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
<BoxContainer Orientation="Vertical" Margin="8">
<Label Text="{Loc 'ui-options-admin-player-panel'}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="PlayerlistSeparateSymbolsCheckBox" Text="{Loc 'ui-options-admin-playerlist-separate-symbols'}" />
<CheckBox Name="PlayerlistCharacterColorCheckBox" Text="{Loc 'ui-options-admin-playerlist-character-color'}" />
<CheckBox Name="PlayerlistRoleTypeColorCheckBox" Text="{Loc 'ui-options-admin-playerlist-roletype-color'}" />
<Label Text="{Loc 'ui-options-admin-overlay-title'}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="EnableClassicOverlayCheckBox" Text="{Loc 'ui-options-enable-classic-overlay'}" />
<CheckBox Name="EnableOverlaySymbolsCheckBox" Text="{Loc 'ui-options-enable-overlay-symbols'}" />
<CheckBox Name="EnableOverlayPlaytimeCheckBox" Text="{Loc 'ui-options-enable-overlay-playtime'}" />
<CheckBox Name="EnableOverlayStartingJobCheckBox" Text="{Loc 'ui-options-enable-overlay-starting-job'}" />
<ui:OptionSlider Name="OverlayMergeDistanceSlider" Title="{Loc 'ui-options-overlay-merge-distance'}"/>
<ui:OptionSlider Name="OverlayGhostFadeSlider" Title="{Loc 'ui-options-overlay-ghost-fade-distance'}"/>
<ui:OptionSlider Name="OverlayGhostHideSlider" Title="{Loc 'ui-options-overlay-ghost-hide-distance'}"/>
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />

View File

@@ -8,13 +8,45 @@ namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class AdminOptionsTab : Control
{
private const float OverlayMergeMin = 0.05f;
private const float OverlayMergeMax = 0.95f;
private const int OverlayGhostFadeMin = 0;
private const int OverlayGhostFadeMax = 10;
private const int OverlayGhostHideMin = 0;
private const int OverlayGhostHideMax = 5;
public AdminOptionsTab()
{
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CCVars.AdminPlayerlistSeparateSymbols, PlayerlistSeparateSymbolsCheckBox);
Control.AddOptionCheckBox(CCVars.AdminPlayerlistHighlightedCharacterColor, PlayerlistCharacterColorCheckBox);
Control.AddOptionCheckBox(CCVars.AdminPlayerlistRoleTypeColor, PlayerlistRoleTypeColorCheckBox);
Control.AddOptionCheckBox(CCVars.AdminOverlayClassic, EnableClassicOverlayCheckBox);
Control.AddOptionCheckBox(CCVars.AdminOverlaySymbols, EnableOverlaySymbolsCheckBox);
Control.AddOptionCheckBox(CCVars.AdminOverlayPlaytime, EnableOverlayPlaytimeCheckBox);
Control.AddOptionCheckBox(CCVars.AdminOverlayStartingJob, EnableOverlayStartingJobCheckBox);
Control.Initialize();
Control.AddOptionPercentSlider(
CCVars.AdminOverlayMergeDistance,
OverlayMergeDistanceSlider,
OverlayMergeMin,
OverlayMergeMax);
Control.AddOptionSlider(
CCVars.AdminOverlayGhostFadeDistance,
OverlayGhostFadeSlider,
OverlayGhostFadeMin,
OverlayGhostFadeMax);
Control.AddOptionSlider(
CCVars.AdminOverlayGhostHideDistance,
OverlayGhostHideSlider,
OverlayGhostHideMin,
OverlayGhostHideMax);
}
}

View File

@@ -312,7 +312,7 @@ namespace Content.Client.Options.UI.Tabs
//CP14
AddHeader("ui-options-header-cp14");
AddButton(ContentKeyFunctions.CP14OpenKnowledgeMenu);
AddButton(ContentKeyFunctions.CP14OpenSkillMenu);
//CP14 end
foreach (var control in _keyControls.Values)

View File

@@ -1,7 +1,7 @@
using System.Numerics;
using Content.Client.Parallax;
using Content.Client.Weather;
using Content.Shared._CP14.DayCycle.Components;
using Content.Shared._CP14.CloudShadow;
using Content.Shared.Salvage;
using Content.Shared.Weather;
using Robust.Client.GameObjects;
@@ -62,7 +62,7 @@ public sealed partial class StencilOverlay : Overlay
{
foreach (var (proto, weather) in comp.Weather)
{
if (!_protoManager.TryIndex<WeatherPrototype>(proto, out var weatherProto))
if (!_protoManager.TryIndex(proto, out var weatherProto))
continue;
var alpha = _weather.GetPercent(weather, mapUid);

View File

@@ -11,13 +11,21 @@ public sealed class PaperVisualizerSystem : VisualizerSystem<PaperVisualsCompone
if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<PaperStatus>(uid, PaperVisuals.Status , out var writingStatus, args.Component))
if (AppearanceSystem.TryGetData<PaperStatus>(uid, PaperVisuals.Status, out var writingStatus, args.Component))
args.Sprite.LayerSetVisible(PaperVisualLayers.Writing, writingStatus == PaperStatus.Written);
if (AppearanceSystem.TryGetData<string>(uid, PaperVisuals.Stamp, out var stampState, args.Component))
{
args.Sprite.LayerSetState(PaperVisualLayers.Stamp, stampState);
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, true);
if (stampState != string.Empty)
{
args.Sprite.LayerSetState(PaperVisualLayers.Stamp, stampState);
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, true);
}
else
{
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, false);
}
}
}
}

View File

@@ -5,7 +5,7 @@ namespace Content.Client.Parallax.Data;
/// <summary>
/// Prototype data for a parallax.
/// </summary>
[Prototype("parallax")]
[Prototype]
public sealed partial class ParallaxPrototype : IPrototype
{
/// <inheritdoc/>

View File

@@ -1,7 +1,9 @@
using System.Numerics;
using System.Numerics;
using Content.Client.Parallax.Data;
using Content.Client.Parallax.Managers;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
@@ -17,27 +19,50 @@ public sealed class ParallaxControl : Control
[Dependency] private readonly IParallaxManager _parallaxManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private string _parallaxPrototype = "FastSpace";
[ViewVariables(VVAccess.ReadWrite)] public Vector2 Offset { get; set; }
[ViewVariables(VVAccess.ReadWrite)] public float SpeedX { get; set; } = 0.0f;
[ViewVariables(VVAccess.ReadWrite)] public float SpeedY { get; set; } = 0.0f;
[ViewVariables(VVAccess.ReadWrite)] public float ScaleX { get; set; } = 1.0f;
[ViewVariables(VVAccess.ReadWrite)] public float ScaleY { get; set; } = 1.0f;
[ViewVariables(VVAccess.ReadWrite)] public string ParallaxPrototype
{
get => _parallaxPrototype;
set
{
_parallaxPrototype = value;
_parallaxManager.LoadParallaxByName(value);
}
}
public ParallaxControl()
{
IoCManager.InjectDependencies(this);
Offset = new Vector2(_random.Next(0, 1000), _random.Next(0, 1000));
RectClipContent = true;
_parallaxManager.LoadParallaxByName("FastSpace");
_parallaxManager.LoadParallaxByName(_parallaxPrototype);
}
protected override void Draw(DrawingHandleScreen handle)
{
foreach (var layer in _parallaxManager.GetParallaxLayers("FastSpace"))
var currentTime = (float) _timing.RealTime.TotalSeconds;
var offset = Offset + new Vector2(currentTime * SpeedX, currentTime * SpeedY);
foreach (var layer in _parallaxManager.GetParallaxLayers(_parallaxPrototype))
{
var tex = layer.Texture;
var texSize = (tex.Size.X * (int) Size.X, tex.Size.Y * (int) Size.X) * layer.Config.Scale.Floored() / 1920;
var texSize = new Vector2i(
(int)(tex.Size.X * Size.X * layer.Config.Scale.X / 1920 * ScaleX),
(int)(tex.Size.Y * Size.X * layer.Config.Scale.Y / 1920 * ScaleY)
);
var ourSize = PixelSize;
var currentTime = (float) _timing.RealTime.TotalSeconds;
var offset = Offset + new Vector2(currentTime * 100f, currentTime * 0f);
//Protection from division by zero.
texSize.X = Math.Max(texSize.X, 1);
texSize.Y = Math.Max(texSize.Y, 1);
if (layer.Config.Tiled)
{

View File

@@ -237,6 +237,12 @@ namespace Content.Client.Popups
PopupEntity(message, uid, recipient.Value, type);
}
public override void PopupPredicted(string? message, EntityUid uid, EntityUid? recipient, Filter filter, bool recordReplay, PopupType type = PopupType.Small)
{
if (recipient != null && _timing.IsFirstTimePredicted)
PopupEntity(message, uid, recipient.Value, type);
}
public override void PopupPredicted(string? recipientMessage, string? othersMessage, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
{
if (recipient != null && _timing.IsFirstTimePredicted)

View File

@@ -1,12 +1,15 @@
using Content.Shared.DrawDepth;
using Content.Client.UserInterface.Systems.Sandbox;
using Content.Shared.SubFloor;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Player;
namespace Content.Client.SubFloor;
public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!;
private bool _showAll;
@@ -18,8 +21,13 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
{
if (_showAll == value) return;
_showAll = value;
_ui.GetUIController<SandboxUIController>().SetToggleSubfloors(value);
UpdateAll();
var ev = new ShowSubfloorRequestEvent()
{
Value = value,
};
RaiseNetworkEvent(ev);
}
}
@@ -28,6 +36,20 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
base.Initialize();
SubscribeLocalEvent<SubFloorHideComponent, AppearanceChangeEvent>(OnAppearanceChanged);
SubscribeNetworkEvent<ShowSubfloorRequestEvent>(OnRequestReceived);
SubscribeLocalEvent<LocalPlayerDetachedEvent>(OnPlayerDetached);
}
private void OnPlayerDetached(LocalPlayerDetachedEvent ev)
{
// Vismask resets so need to reset this.
ShowAll = false;
}
private void OnRequestReceived(ShowSubfloorRequestEvent ev)
{
// When client receives request Queue an update on all vis.
UpdateAll();
}
private void OnAppearanceChanged(EntityUid uid, SubFloorHideComponent component, ref AppearanceChangeEvent args)

View File

@@ -14,6 +14,7 @@ public sealed partial class GhostGui : UIWidget
public event Action? RequestWarpsPressed;
public event Action? ReturnToBodyPressed;
public event Action? GhostRolesPressed;
private int _prevNumberRoles;
public GhostGui()
{
@@ -26,6 +27,7 @@ public sealed partial class GhostGui : UIWidget
GhostWarpButton.OnPressed += _ => RequestWarpsPressed?.Invoke();
ReturnToBodyButton.OnPressed += _ => ReturnToBodyPressed?.Invoke();
GhostRolesButton.OnPressed += _ => GhostRolesPressed?.Invoke();
GhostRolesButton.OnPressed += _ => GhostRolesButton.StyleClasses.Remove(StyleBase.ButtonCaution);
}
public void Hide()
@@ -41,14 +43,13 @@ public sealed partial class GhostGui : UIWidget
if (roles != null)
{
GhostRolesButton.Text = Loc.GetString("ghost-gui-ghost-roles-button", ("count", roles));
if (roles > 0)
if (roles > _prevNumberRoles)
{
GhostRolesButton.StyleClasses.Add(StyleBase.ButtonCaution);
}
else
{
GhostRolesButton.StyleClasses.Remove(StyleBase.ButtonCaution);
}
_prevNumberRoles = (int)roles;
}
TargetWindow.Populate();

View File

@@ -1,3 +1,4 @@
using Content.Client._CP14.UserInterface.Systems.Skill;
using Content.Client.UserInterface.Systems.Actions;
using Content.Client.UserInterface.Systems.Admin;
using Content.Client.UserInterface.Systems.Bwoink;
@@ -24,7 +25,7 @@ public sealed class GameTopMenuBarUIController : UIController
[Dependency] private readonly SandboxUIController _sandbox = default!;
[Dependency] private readonly GuidebookUIController _guidebook = default!;
[Dependency] private readonly EmotesUIController _emotes = default!;
[Dependency] private readonly CP14KnowledgeUIController _knowledge = default!; //CP14
[Dependency] private readonly CP14SkillUIController _skill = default!; //CP14
private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>();
@@ -48,7 +49,7 @@ public sealed class GameTopMenuBarUIController : UIController
_action.UnloadButton();
_sandbox.UnloadButton();
_emotes.UnloadButton();
_knowledge.UnloadButton(); //CP14
_skill.UnloadButton(); //CP14
}
public void LoadButtons()
@@ -62,6 +63,6 @@ public sealed class GameTopMenuBarUIController : UIController
_action.LoadButton();
_sandbox.LoadButton();
_emotes.LoadButton();
_knowledge.LoadButton(); //CP14
_skill.LoadButton(); //CP14
}
}

View File

@@ -35,11 +35,11 @@
/>
<!-- CP14 UI part -->
<ui:MenuButton
Name="CP14KnowledgeButton"
Name="CP14SkillButton"
Access="Internal"
Icon="{xe:Tex '/Textures/Interface/students-cap.svg.192dpi.png'}"
ToolTip="{Loc 'cp14-game-hud-open-knowledge-menu-button-tooltip'}"
BoundKey = "{x:Static is:ContentKeyFunctions.CP14OpenKnowledgeMenu}"
ToolTip="{Loc 'cp14-game-hud-open-skill-menu-button-tooltip'}"
BoundKey = "{x:Static is:ContentKeyFunctions.CP14OpenSkillMenu}"
MinSize="42 64"
HorizontalExpand="True"
AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}"

View File

@@ -39,7 +39,6 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
[UISystemDependency] private readonly DebugPhysicsSystem _debugPhysics = default!;
[UISystemDependency] private readonly MarkerSystem _marker = default!;
[UISystemDependency] private readonly SandboxSystem _sandbox = default!;
[UISystemDependency] private readonly SubFloorHideSystem _subfloorHide = default!;
private SandboxWindow? _window;
@@ -117,10 +116,11 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
_window.OnOpen += () => { SandboxButton!.Pressed = true; };
_window.OnClose += () => { SandboxButton!.Pressed = false; };
// TODO: These need moving to opened so at least if they're not synced properly on open they work.
_window.ToggleLightButton.Pressed = !_light.Enabled;
_window.ToggleFovButton.Pressed = !_eye.CurrentEye.DrawFov;
_window.ToggleShadowsButton.Pressed = !_light.DrawShadows;
_window.ToggleSubfloorButton.Pressed = _subfloorHide.ShowAll;
_window.ShowMarkersButton.Pressed = _marker.MarkersVisible;
_window.ShowBbButton.Pressed = (_debugPhysics.Flags & PhysicsDebugFlags.Shapes) != 0x0;
@@ -219,4 +219,16 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
_window.Close();
}
}
#region Buttons
public void SetToggleSubfloors(bool value)
{
if (_window == null)
return;
_window.ToggleSubfloorButton.Pressed = value;
}
#endregion
}

View File

@@ -1,4 +1,5 @@
using Robust.Client.AutoGenerated;
using Content.Client.SubFloor;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@@ -7,8 +8,18 @@ namespace Content.Client.UserInterface.Systems.Sandbox.Windows;
[GenerateTypedNameReferences]
public sealed partial class SandboxWindow : DefaultWindow
{
[Dependency] private readonly IEntityManager _entManager = null!;
public SandboxWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
protected override void Opened()
{
base.Opened();
// Make sure state is up to date.
ToggleSubfloorButton.Pressed = _entManager.System<SubFloorHideSystem>().ShowAll;
}
}

View File

@@ -42,6 +42,9 @@ public sealed class StorageWindow : BaseWindow
private ValueList<EntityUid> _contained = new();
private ValueList<EntityUid> _toRemove = new();
// Manually store this because you can't have a 0x0 GridContainer but we still need to add child controls for 1x1 containers.
private Vector2i _pieceGridSize;
private TextureButton? _backButton;
private bool _isDirty;
@@ -408,11 +411,14 @@ public sealed class StorageWindow : BaseWindow
_contained.Clear();
_contained.AddRange(storageComp.Container.ContainedEntities.Reverse());
var width = boundingGrid.Width + 1;
var height = boundingGrid.Height + 1;
// Build the grid representation
if (_pieceGrid.Rows - 1 != boundingGrid.Height || _pieceGrid.Columns - 1 != boundingGrid.Width)
if (_pieceGrid.Rows != _pieceGridSize.Y || _pieceGrid.Columns != _pieceGridSize.X)
{
_pieceGrid.Rows = boundingGrid.Height + 1;
_pieceGrid.Columns = boundingGrid.Width + 1;
_pieceGrid.Rows = height;
_pieceGrid.Columns = width;
_controlGrid.Clear();
for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
@@ -430,6 +436,7 @@ public sealed class StorageWindow : BaseWindow
}
}
_pieceGridSize = new(width, height);
_toRemove.Clear();
// Remove entities no longer relevant / Update existing ones

View File

@@ -3,10 +3,12 @@ using Content.Client.ContextMenu.UI;
using Content.Shared.Verbs;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client.Verbs.UI
{
@@ -27,7 +29,17 @@ namespace Content.Client.Verbs.UI
public VerbMenuElement(Verb verb) : base(verb.Text)
{
ToolTip = verb.Message;
TooltipSupplier = sender =>
{
var label = new RichTextLabel();
label.SetMessage(FormattedMessage.FromMarkupOrThrow(verb.Message ?? verb.Text));
var tooltip = new Tooltip();
tooltip.GetChild(0).Children.Clear();
tooltip.GetChild(0).Children.Add(label);
return tooltip;
};
Disabled = verb.Disabled;
Verb = verb;

View File

@@ -213,7 +213,7 @@ namespace Content.Client.Verbs
{
// maybe send an informative pop-up message.
if (!string.IsNullOrWhiteSpace(verb.Message))
_popupSystem.PopupEntity(verb.Message, user);
_popupSystem.PopupEntity(FormattedMessage.RemoveMarkupOrThrow(verb.Message), user);
return;
}

View File

@@ -1,4 +1,5 @@
using Content.Shared._CP14.Farming;
using Content.Shared._CP14.Farming.Components;
using Content.Shared.Rounding;
using Robust.Client.GameObjects;
@@ -32,7 +33,7 @@ public sealed class ClientCP14FarmingSystem : CP14SharedFarmingSystem
if (!TryComp<SpriteComponent>(visuals, out var sprite))
return;
if (!TryComp<CP14PlantComponent>(visuals, out var plant))
if (!PlantQuery.TryComp(visuals, out var plant))
return;
var growthState = ContentHelpers.RoundToNearestLevels(plant.GrowthLevel, 1, visuals.Comp.GrowthSteps);

View File

@@ -1,43 +0,0 @@
using Content.Shared._CP14.Knowledge;
using Content.Shared._CP14.Knowledge.Events;
using Content.Shared._CP14.Knowledge.Prototypes;
using Robust.Client.Player;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Knowledge;
public sealed class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSystem
{
[Dependency] private readonly IPlayerManager _players = default!;
public event Action<KnowledgeData>? OnKnowledgeUpdate;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<CP14KnowledgeInfoEvent>(OnCharacterKnowledgeEvent);
}
public void RequestKnowledgeInfo()
{
var entity = _players.LocalEntity;
if (entity is null)
return;
RaiseNetworkEvent(new CP14RequestKnowledgeInfoEvent(GetNetEntity(entity.Value)));
}
private void OnCharacterKnowledgeEvent(CP14KnowledgeInfoEvent msg, EntitySessionEventArgs args)
{
var entity = GetEntity(msg.NetEntity);
var data = new KnowledgeData(entity, msg.AllKnowledge);
OnKnowledgeUpdate?.Invoke(data);
}
public readonly record struct KnowledgeData(
EntityUid Entity,
HashSet<ProtoId<CP14KnowledgePrototype>> AllKnowledge
);
}

View File

@@ -0,0 +1,65 @@
using Content.Shared._CP14.NightVision;
using Robust.Client.Player;
using Robust.Shared.Player;
namespace Content.Client._CP14.NightVision;
public sealed class CP14ClientNightVisionSystem : CP14SharedNightVisionSystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14NightVisionComponent, CP14ToggleNightVisionEvent>(OnToggleNightVision);
SubscribeLocalEvent<CP14NightVisionComponent, PlayerDetachedEvent>(OnPlayerDetached);
}
protected override void OnRemove(Entity<CP14NightVisionComponent> ent, ref ComponentRemove args)
{
base.OnRemove(ent, ref args);
NightVisionOff(ent);
}
private void OnPlayerDetached(Entity<CP14NightVisionComponent> ent, ref PlayerDetachedEvent args)
{
NightVisionOff(ent);
}
private void OnToggleNightVision(Entity<CP14NightVisionComponent> ent, ref CP14ToggleNightVisionEvent args)
{
NightVisionToggle(ent);
}
private void NightVisionOn(Entity<CP14NightVisionComponent> ent)
{
if (_playerManager.LocalSession?.AttachedEntity != ent)
return;
var nightVisionLight = Spawn(ent.Comp.LightPrototype, Transform(ent).Coordinates);
_transform.SetParent(nightVisionLight, ent);
_transform.SetWorldRotation(nightVisionLight, _transform.GetWorldRotation(ent));
ent.Comp.LocalLightEntity = nightVisionLight;
}
private void NightVisionOff(Entity<CP14NightVisionComponent> ent)
{
QueueDel(ent.Comp.LocalLightEntity);
ent.Comp.LocalLightEntity = null;
}
private void NightVisionToggle(Entity<CP14NightVisionComponent> ent)
{
if (ent.Comp.LocalLightEntity == null)
{
NightVisionOn(ent);
}
else
{
NightVisionOff(ent);
}
}
}

View File

@@ -1,5 +1,5 @@
using System.Numerics;
using Content.Shared._CP14.DayCycle.Components;
using Content.Shared._CP14.CloudShadow;
using Robust.Client.Graphics;
using Robust.Shared.Utility;

View File

@@ -0,0 +1,57 @@
using Content.Shared._CP14.Skill;
using Content.Shared._CP14.Skill.Components;
using Content.Shared._CP14.Skill.Prototypes;
using Robust.Client.Player;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Skill;
public sealed partial class CP14ClientSkillSystem : CP14SharedSkillSystem
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public event Action<EntityUid>? OnSkillUpdate;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14SkillStorageComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
}
private void OnAfterAutoHandleState(Entity<CP14SkillStorageComponent> ent, ref AfterAutoHandleStateEvent args)
{
if (ent != _playerManager.LocalEntity)
return;
OnSkillUpdate?.Invoke(ent.Owner);
}
public void RequestSkillData()
{
var localPlayer = _playerManager.LocalEntity;
if (!HasComp<CP14SkillStorageComponent>(localPlayer))
return;
OnSkillUpdate?.Invoke(localPlayer.Value);
}
public void RequestLearnSkill(EntityUid? target, CP14SkillPrototype? skill)
{
if (skill == null || target == null)
return;
var netEv = new CP14TryLearnSkillMessage(GetNetEntity(target.Value), skill.ID);
RaiseNetworkEvent(netEv);
if (_proto.TryIndex(skill.Tree, out var indexedTree))
{
_audio.PlayGlobal(indexedTree.LearnSound, target.Value, AudioParams.Default.WithVolume(6f));
}
}
}

View File

@@ -0,0 +1,24 @@
<Control xmlns="https://spacestation14.io" HorizontalExpand="True">
<BoxContainer Name="MainContainer"
Orientation="Horizontal"
HorizontalExpand="True">
<Button Name="MainButton"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="OpenRight"
Margin="0 0 -1 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Margin="-5 0 0 0">
<Label Name="SkillTreeLabel" />
</BoxContainer>
</BoxContainer>
</Button>
<PanelContainer Name="ColorPanel"
VerticalExpand="True"
SetWidth="7"
Margin="0 1 0 0" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,22 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._CP14.Skill.Ui;
[GenerateTypedNameReferences]
public sealed partial class CP14SkillTreeButtonControl : Control
{
public event Action? OnPressed;
public CP14SkillTreeButtonControl(Color color, string label)
{
RobustXamlLoader.Load(this);
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = color };
SkillTreeLabel.Text = label;
MainButton.OnPressed += args => OnPressed?.Invoke();
}
}

View File

@@ -0,0 +1,7 @@
<ui:CP14SkillTreeGraphControl
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client._CP14.Skill.Ui"
xmlns:ui="clr-namespace:Content.Client._CP14.Skill.Ui"
HorizontalExpand="True"
VerticalExpand="True"
MouseFilter="Stop"/>

View File

@@ -0,0 +1,227 @@
using System.Linq;
using System.Numerics;
using Content.Shared._CP14.Skill;
using Content.Shared._CP14.Skill.Components;
using Content.Shared._CP14.Skill.Prototypes;
using Content.Shared._CP14.Skill.Restrictions;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.Utility;
using Robust.Shared.Input;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Skill.Ui;
[GenerateTypedNameReferences]
public sealed partial class CP14SkillTreeGraphControl : BoxContainer
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
private readonly CP14SharedSkillSystem _skillSystem;
private Entity<CP14SkillStorageComponent>? _player;
private IEnumerable<CP14SkillPrototype> _allSkills;
private CP14SkillPrototype? _hoveredNode;
private CP14SkillPrototype? _selectedNode;
public CP14SkillTreePrototype? Tree;
private bool dragging = false;
private Vector2 _previousMousePosition = Vector2.Zero;
private Vector2 _globalOffset = new (60,60);
private const float GridSize = 25f;
public event Action<CP14SkillPrototype?>? OnNodeSelected;
public event Action<Vector2>? OnOffsetChanged;
public CP14SkillTreeGraphControl()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
_skillSystem = _entManager.System<CP14SharedSkillSystem>();
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
_proto.PrototypesReloaded += _ => _allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>().OrderBy(skill => _skillSystem.GetSkillName(skill)).ToList();
OnOffsetChanged?.Invoke(_globalOffset);
}
public void UpdateState(Entity<CP14SkillStorageComponent>? player)
{
_player = player;
OnOffsetChanged?.Invoke(_globalOffset);
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
if (args.Handled)
return;
if (args.Function == EngineKeyFunctions.UIClick)
{
dragging = true;
if (_hoveredNode == null)
return;
OnNodeSelected?.Invoke(_hoveredNode);
UserInterfaceManager.ClickSound();
_selectedNode = _hoveredNode;
}
if (args.Function == EngineKeyFunctions.UIRightClick)
{
_globalOffset = new Vector2(60, 60); // Reset offset on right click
OnOffsetChanged?.Invoke(_globalOffset);
}
}
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{
base.KeyBindUp(args);
if (args.Handled || args.Function != EngineKeyFunctions.UIClick)
return;
dragging = false;
}
protected override void ExitedTree()
{
base.ExitedTree();
OnNodeSelected?.Invoke(null);
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
_hoveredNode = null;
if (_player == null || Tree == null)
{
return;
}
var cursor = (UserInterfaceManager.MousePositionScaled.Position * UIScale) - GlobalPixelPosition;
if (dragging)
{
var delta = cursor - _previousMousePosition;
_globalOffset += delta;
OnOffsetChanged?.Invoke(_globalOffset);
}
_previousMousePosition = cursor;
var playerSkills = _player.Value.Comp.LearnedSkills;
//Draw connection lines
foreach (var skill in _allSkills)
{
if (skill.Tree != Tree)
continue;
var fromPos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
foreach (var req in skill.Restrictions)
{
switch (req)
{
case NeedPrerequisite prerequisite:
if (!_proto.TryIndex(prerequisite.Prerequisite, out var prerequisiteSkill))
continue;
if (prerequisiteSkill.Tree != Tree)
continue;
var learned = playerSkills.Contains(skill.ID);
var toPos = prerequisiteSkill.SkillUiPosition * GridSize * UIScale + _globalOffset;
var color = learned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f));
handle.DrawLine(fromPos, toPos, color);
break;
}
}
}
//Draw skill icons over lines
foreach (var skill in _allSkills)
{
if (skill.Tree != Tree)
continue;
//TODO: Not optimized, recalculates every frame. Needs to be calculated on state update and cached.
var canBeLearned = _skillSystem.CanLearnSkill(_player.Value, skill, _player.Value.Comp);
var pos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
// Base skill icon
var baseTexture = skill.Icon.Frame0();
var baseSize = new Vector2(baseTexture.Width, baseTexture.Height) * 2;
var baseQuad = new UIBox2(pos - baseSize / 2, pos + baseSize / 2);
var hovered = (cursor - pos).LengthSquared() <= (baseSize.X / 2) * (baseSize.X / 2);
// Frame
var frameTexture = Tree.FrameIcon.Frame0();
var frameSize = new Vector2(frameTexture.Width, frameTexture.Height) * 2;
var frameQuad = new UIBox2(pos - frameSize / 2, pos + frameSize / 2);
handle.DrawTextureRect(frameTexture, frameQuad, canBeLearned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)));
// Selected Skill
if (_selectedNode == skill)
{
var selectedTexture = Tree.SelectedIcon.Frame0();
var selectedSize = new Vector2(selectedTexture.Width, selectedTexture.Height) * 2;
var selectedQuad = new UIBox2(pos - selectedSize / 2, pos + selectedSize / 2);
handle.DrawTextureRect(selectedTexture, selectedQuad, Color.White);
}
// Hovered Skill
if (hovered)
{
_hoveredNode = skill;
var hoveredTexture = Tree.HoveredIcon.Frame0();
var hoveredSize = new Vector2(hoveredTexture.Width, hoveredTexture.Height) * 2;
var hoveredQuad = new UIBox2(pos - hoveredSize / 2, pos + hoveredSize / 2);
handle.DrawTextureRect(hoveredTexture, hoveredQuad, Color.White);
}
var learned = playerSkills.Contains(skill.ID);
var allowedToLearn = _skillSystem.AllowedToLearn(_player.Value, skill, _player.Value.Comp);
// Learned Skill
if (learned)
{
var learnedTexture = Tree.LearnedIcon.Frame0();
var learnedSize = new Vector2(learnedTexture.Width, learnedTexture.Height) * 2;
var learnedQuad = new UIBox2(pos - learnedSize / 2, pos + learnedSize / 2);
handle.DrawTextureRect(learnedTexture, learnedQuad, Color.White);
}
else if (canBeLearned)
{
var availableTexture = Tree.AvailableIcon.Frame0();
var availableSize = new Vector2(availableTexture.Width, availableTexture.Height) * 2;
var availableQuad = new UIBox2(pos - availableSize / 2, pos + availableSize / 2);
handle.DrawTextureRect(availableTexture, availableQuad, Color.White);
}
var iconColor = allowedToLearn switch
{
true when !learned => Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)),
false when !learned => Color.FromSrgb(new Color(0f, 0f, 0f)),
_ => Color.White
};
handle.DrawTextureRect(baseTexture, baseQuad, iconColor);
}
}
}

View File

@@ -1,158 +0,0 @@
using Content.Client._CP14.Knowledge;
using Content.Client._CP14.UserInterface.Systems.Knowledge.Windows;
using Content.Client.Gameplay;
using Content.Client.UserInterface.Controls;
using Content.Shared.Input;
using JetBrains.Annotations;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Character;
[UsedImplicitly]
public sealed class CP14KnowledgeUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>,
IOnSystemChanged<ClientCP14KnowledgeSystem>
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[UISystemDependency] private readonly ClientCP14KnowledgeSystem _knowledge = default!;
private CP14KnowledgeWindow? _window;
private MenuButton? KnowledgeButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.CP14KnowledgeButton;
public void OnStateEntered(GameplayState state)
{
DebugTools.Assert(_window == null);
_window = UIManager.CreateWindow<CP14KnowledgeWindow>();
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
CommandBinds.Builder
.Bind(ContentKeyFunctions.CP14OpenKnowledgeMenu,
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
.Register<CP14KnowledgeUIController>();
}
public void OnStateExited(GameplayState state)
{
if (_window != null)
{
_window.Dispose();
_window = null;
}
CommandBinds.Unregister<CP14KnowledgeUIController>();
}
public void OnSystemLoaded(ClientCP14KnowledgeSystem system)
{
system.OnKnowledgeUpdate += KnowledgeUpdated;
_player.LocalPlayerDetached += CharacterDetached;
}
public void OnSystemUnloaded(ClientCP14KnowledgeSystem system)
{
system.OnKnowledgeUpdate -= KnowledgeUpdated;
_player.LocalPlayerDetached -= CharacterDetached;
}
public void UnloadButton()
{
if (KnowledgeButton is null)
return;
KnowledgeButton.OnPressed -= KnowledgeButtonPressed;
}
public void LoadButton()
{
if (KnowledgeButton is null)
return;
KnowledgeButton.OnPressed += KnowledgeButtonPressed;
if (_window is null)
return;
_window.OnClose += DeactivateButton;
_window.OnOpen += ActivateButton;
}
private void DeactivateButton()
{
KnowledgeButton!.Pressed = false;
}
private void ActivateButton()
{
KnowledgeButton!.Pressed = true;
}
private void KnowledgeUpdated(ClientCP14KnowledgeSystem.KnowledgeData data)
{
if (_window is null)
return;
_window.KnowledgeContent.RemoveAllChildren();
var (entity, allKnowledge) = data;
foreach (var knowledge in allKnowledge)
{
if (!_proto.TryIndex(knowledge, out var indexedKnowledge))
continue;
var knowledgeButton = new Button()
{
Access = AccessLevel.Public,
Text = Loc.GetString(indexedKnowledge.Name),
ToolTip = Loc.GetString(indexedKnowledge.Desc),
TextAlign = Label.AlignMode.Center,
};
_window.KnowledgeContent.AddChild(knowledgeButton);
}
}
private void CharacterDetached(EntityUid uid)
{
CloseWindow();
}
private void KnowledgeButtonPressed(BaseButton.ButtonEventArgs args)
{
ToggleWindow();
}
private void CloseWindow()
{
_window?.Close();
}
private void ToggleWindow()
{
if (_window == null)
return;
if (KnowledgeButton != null)
{
KnowledgeButton.SetClickPressed(!_window.IsOpen);
}
if (_window.IsOpen)
{
CloseWindow();
}
else
{
_knowledge.RequestKnowledgeInfo();
_window.Open();
}
}
}

View File

@@ -1,13 +0,0 @@
<windows:CP14KnowledgeWindow
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:windows="clr-namespace:Content.Client._CP14.UserInterface.Systems.Knowledge.Windows"
Title="{Loc 'cp14-knowledge-info-title'}"
MinWidth="400"
MinHeight="200">
<ScrollContainer>
<BoxContainer Name="KnowledgeContent" Margin="5" Access="Public" Orientation="Vertical">
</BoxContainer>
</ScrollContainer>
</windows:CP14KnowledgeWindow>

View File

@@ -0,0 +1,266 @@
using System.Linq;
using System.Numerics;
using System.Text;
using Content.Client._CP14.Skill;
using Content.Client._CP14.Skill.Ui;
using Content.Client._CP14.UserInterface.Systems.Skill.Window;
using Content.Client.Gameplay;
using Content.Client.UserInterface.Controls;
using Content.Shared._CP14.Skill.Components;
using Content.Shared._CP14.Skill.Prototypes;
using Content.Shared.Input;
using JetBrains.Annotations;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client._CP14.UserInterface.Systems.Skill;
[UsedImplicitly]
public sealed class CP14SkillUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>,
IOnSystemChanged<CP14ClientSkillSystem>
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[UISystemDependency] private readonly CP14ClientSkillSystem _skill = default!;
private CP14SkillWindow? _window;
private CP14SkillPrototype? _selectedSkill;
private MenuButton? SkillButton => UIManager.GetActiveUIWidgetOrNull<Client.UserInterface.Systems.MenuBar.Widgets.GameTopMenuBar>()?.CP14SkillButton;
public void OnStateEntered(GameplayState state)
{
DebugTools.Assert(_window == null);
_window = UIManager.CreateWindow<CP14SkillWindow>();
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
CommandBinds.Builder
.Bind(ContentKeyFunctions.CP14OpenSkillMenu,
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
.Register<CP14SkillUIController>();
_window.LearnButton.OnPressed += _ => _skill.RequestLearnSkill(_player.LocalEntity, _selectedSkill);
_window.GraphControl.OnNodeSelected += SelectNode;
_window.GraphControl.OnOffsetChanged += offset =>
{
_window.ParallaxBackground.Offset = -offset * 0.25f + new Vector2(1000,1000); //hardcoding is bad
};
}
public void OnStateExited(GameplayState state)
{
if (_window != null)
{
_window.GraphControl.OnNodeSelected -= SelectNode;
_window.Dispose();
_window = null;
}
CommandBinds.Unregister<CP14SkillUIController>();
}
public void OnSystemLoaded(CP14ClientSkillSystem system)
{
system.OnSkillUpdate += UpdateState;
_player.LocalPlayerDetached += CharacterDetached;
}
public void OnSystemUnloaded(CP14ClientSkillSystem system)
{
system.OnSkillUpdate -= UpdateState;
_player.LocalPlayerDetached -= CharacterDetached;
}
public void UnloadButton()
{
if (SkillButton is null)
return;
SkillButton.OnPressed -= SkillButtonPressed;
}
public void LoadButton()
{
if (SkillButton is null)
return;
SkillButton.OnPressed += SkillButtonPressed;
if (_window is null)
return;
_window.OnClose += DeactivateButton;
_window.OnOpen += ActivateButton;
}
private void DeactivateButton()
{
SkillButton!.Pressed = false;
}
private void ActivateButton()
{
SkillButton!.Pressed = true;
}
private void SelectNode(CP14SkillPrototype? skill)
{
if (_window is null)
return;
if (_player.LocalEntity == null)
return;
_selectedSkill = skill;
if (skill == null)
{
_window.SkillName.Text = string.Empty;
_window.SkillDescription.Text = string.Empty;
_window.SkillView.Texture = null;
_window.LearnButton.Disabled = true;
}
else
{
_window.SkillName.Text = _skill.GetSkillName(skill);
_window.SkillDescription.SetMessage(GetSkillDescription(skill));
_window.SkillView.Texture = skill.Icon.Frame0();
_window.LearnButton.Disabled = !_skill.CanLearnSkill(_player.LocalEntity.Value, skill);
_window.SkillCost.Text = skill.LearnCost.ToString();
}
}
private FormattedMessage GetSkillDescription(CP14SkillPrototype skill)
{
var msg = new FormattedMessage();
if (_player.LocalEntity == null)
return msg;
var sb = new StringBuilder();
//Description
sb.Append(_skill.GetSkillDescription(skill) + "\n \n");
//Restrictions
foreach (var req in skill.Restrictions)
{
var color = req.Check(_entManager, _player.LocalEntity.Value) ? "green" : "red";
sb.Append($"- [color={color}]{req.GetDescription(_entManager, _proto)}[/color]\n");
}
msg.TryAddMarkup(sb.ToString(), out _);
return msg;
}
private void UpdateState(EntityUid player)
{
if (_window is null)
return;
if (!EntityManager.TryGetComponent<CP14SkillStorageComponent>(player, out var storage))
return;
_window.GraphControl.UpdateState((player, storage));
// Reselect for update state
SelectNode(_selectedSkill);
//If tree not selected, select the first one
if (_window.GraphControl.Tree == null && storage.Progress.Count > 0)
{
var firstTree = storage.Progress.First().Key;
if (_proto.TryIndex(firstTree, out var indexedTree))
{
SelectTree(indexedTree, storage); // Set the first tree from the player's progress
}
}
// Update the experience points for the selected tree
var playerProgress = storage.Progress;
if (_window.GraphControl.Tree is not null && playerProgress.TryGetValue(_window.GraphControl.Tree, out var skillpoint))
{
_window.ExpPointLabel.Text = skillpoint.ToString();
}
_window.LevelLabel.Text = $"{storage.SkillsSumExperience}/{storage.ExperienceMaxCap}";
_window.TreeTabsContainer.RemoveAllChildren();
foreach (var (tree, progress) in storage.Progress)
{
if (!_proto.TryIndex(tree, out var indexedTree))
continue;
var treeButton2 = new CP14SkillTreeButtonControl(indexedTree.Color, Loc.GetString(indexedTree.Name));
treeButton2.ToolTip = Loc.GetString(indexedTree.Desc ?? string.Empty);
treeButton2.OnPressed += () =>
{
SelectTree(indexedTree, storage);
};
_window.TreeTabsContainer.AddChild(treeButton2);
}
}
private void SelectTree(CP14SkillTreePrototype tree, CP14SkillStorageComponent storage)
{
if (_window == null)
return;
_window.GraphControl.Tree = tree;
_window.ParallaxBackground.ParallaxPrototype = tree.Parallax;
_window.TreeName.Text = Loc.GetString(tree.Name);
var playerProgress = storage.Progress;
_window.ExpPointLabel.Text = playerProgress.TryGetValue(tree, out var skillpoint) ? skillpoint.ToString() : "0";
}
private void CharacterDetached(EntityUid uid)
{
CloseWindow();
}
private void SkillButtonPressed(BaseButton.ButtonEventArgs args)
{
ToggleWindow();
}
private void CloseWindow()
{
_window?.Close();
}
private void ToggleWindow()
{
if (_window == null)
return;
if (SkillButton != null)
{
SkillButton.SetClickPressed(!_window.IsOpen);
}
if (_window.IsOpen)
{
CloseWindow();
}
else
{
_skill.RequestSkillData();
_window.Open();
}
}
}

View File

@@ -0,0 +1,89 @@
<window:CP14SkillWindow
xmlns="https://spacestation14.io"
xmlns:window="clr-namespace:Content.Client._CP14.UserInterface.Systems.Skill.Window"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:parallax="clr-namespace:Content.Client.Parallax"
xmlns:ui1="clr-namespace:Content.Client._CP14.Skill.Ui"
Title="{Loc 'cp14-skill-info-title'}"
MinSize="700 350"
SetSize="980 550">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<!-- Selected Skill -->
<BoxContainer Margin="10 10 10 10" MaxWidth="240" SetWidth="240" Orientation="Vertical"
HorizontalExpand="False" VerticalExpand="True">
<!-- Skill View -->
<PanelContainer Name="BackPanel" HorizontalAlignment="Center">
<PanelContainer.PanelOverride>
<graphics:StyleBoxTexture Modulate="#1B1B1E" PatchMarginBottom="10" PatchMarginLeft="10"
PatchMarginRight="10" PatchMarginTop="10" />
</PanelContainer.PanelOverride>
<BoxContainer HorizontalExpand="True" VerticalExpand="True" >
<TextureRect Stretch="Scale" Name="SkillView" SetSize="64 64" HorizontalAlignment="Center" VerticalAlignment="Center" MinSize="64 64"
HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
</BoxContainer>
</PanelContainer>
<customControls:HSeparator StyleClasses="HighDivider" Margin="0 15 0 10" />
<!-- Skill Data -->
<BoxContainer Name="NodeViewContainer" Orientation="Vertical" VerticalExpand="True">
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="False" VerticalExpand="True">
<BoxContainer Name="InfoContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer HorizontalExpand="True">
<Label Name="SkillName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
HorizontalExpand="True" HorizontalAlignment="Center" />
</BoxContainer>
<!-- Skill Cost -->
<BoxContainer HorizontalExpand="True">
<RichTextLabel HorizontalExpand="True" Access="Public" Text="{Loc 'cp14-skill-menu-learncost'}" Margin="0 10 0 10" />
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Left" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
<RichTextLabel Name="SkillCost" Access="Public" Text="0"/>
</BoxContainer>
<!-- Skill Description -->
<BoxContainer HorizontalExpand="True">
<RichTextLabel Name="SkillDescription" HorizontalExpand="True" Access="Public"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</ScrollContainer>
<Control MinHeight="5"/>
<!-- Skill Buttons -->
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Button Name="LearnButton" Text="{Loc 'cp14-skill-menu-learn-button'}" StyleClasses="OpenRight" HorizontalExpand="True" MinHeight="35" Access="Public"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
<customControls:VSeparator StyleClasses="LowDivider" />
<!-- Skills Tree -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer HorizontalExpand="True">
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
HorizontalExpand="True" HorizontalAlignment="Center" />
</BoxContainer>
<PanelContainer Margin="10 10 10 10" HorizontalExpand="True" VerticalExpand="True" RectClipContent="True">
<parallax:ParallaxControl Name="ParallaxBackground" ScaleX="4" ScaleY="4" Access="Public" SpeedX="10" SpeedY="5"/>
<BoxContainer Margin="10 10 10 10" Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<ui1:CP14SkillTreeGraphControl Name="GraphControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Access="Public"/>
</BoxContainer>
<!-- Tree Tabs -->
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Top" HorizontalAlignment="Right" Orientation="Vertical" VerticalExpand="True">
<BoxContainer Name="TreeTabsContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
</BoxContainer>
<!-- Experience Data -->
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Bottom" HorizontalAlignment="Center" Orientation="Horizontal" VerticalExpand="True">
<RichTextLabel VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Loc 'cp14-skill-menu-skillpoints'}" StyleClasses="LabelKeyText"/>
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
<RichTextLabel Margin="0 0 20 0" Name="ExpPointLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
<RichTextLabel VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Loc 'cp14-skill-menu-level'}" StyleClasses="LabelKeyText"/>
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
<RichTextLabel Margin="0 0 0 0" Name="LevelLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
</BoxContainer>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</window:CP14SkillWindow>

View File

@@ -2,12 +2,12 @@ using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._CP14.UserInterface.Systems.Knowledge.Windows;
namespace Content.Client._CP14.UserInterface.Systems.Skill.Window;
[GenerateTypedNameReferences]
public sealed partial class CP14KnowledgeWindow : DefaultWindow
public sealed partial class CP14SkillWindow : DefaultWindow
{
public CP14KnowledgeWindow()
public CP14SkillWindow()
{
RobustXamlLoader.Load(this);
}

View File

@@ -0,0 +1,94 @@
using System.Collections.Generic;
using System.Linq;
using Content.Server.DeviceLinking.Systems;
using Content.Shared.DeviceLinking;
using Content.Shared.Prototypes;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.DeviceLinking;
public sealed class DeviceLinkingTest
{
private const string PortTesterProtoId = "DeviceLinkingSinkPortTester";
[TestPrototypes]
private const string Prototypes = $@"
- type: entity
id: {PortTesterProtoId}
components:
- type: DeviceLinkSource
ports:
- Output
";
/// <summary>
/// Spawns every entity that has a <see cref="DeviceLinkSinkComponent"/>
/// and sends a signal to every port to make sure nothing causes an error.
/// </summary>
[Test]
public async Task AllDeviceLinkSinksWorkTest()
{
await using var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var compFact = server.ResolveDependency<IComponentFactory>();
var mapMan = server.ResolveDependency<IMapManager>();
var mapSys = server.System<SharedMapSystem>();
var deviceLinkSys = server.System<DeviceLinkSystem>();
var prototypes = server.ProtoMan.EnumeratePrototypes<EntityPrototype>();
await server.WaitAssertion(() =>
{
Assert.Multiple(() =>
{
foreach (var proto in prototypes)
{
if (proto.Abstract || pair.IsTestPrototype(proto))
continue;
if (!proto.TryGetComponent<DeviceLinkSinkComponent>(out var protoSinkComp, compFact))
continue;
foreach (var port in protoSinkComp.Ports)
{
// Create a map for each entity/port combo so they can't interfere
mapSys.CreateMap(out var mapId);
var grid = mapMan.CreateGridEntity(mapId);
mapSys.SetTile(grid.Owner, grid.Comp, Vector2i.Zero, new Tile(1));
var coord = new EntityCoordinates(grid.Owner, 0, 0);
// Spawn the sink entity
var sinkEnt = server.EntMan.SpawnEntity(proto.ID, coord);
// Get the actual sink component, since the one we got from the prototype doesn't have its owner set up
Assert.That(server.EntMan.TryGetComponent<DeviceLinkSinkComponent>(sinkEnt, out var sinkComp),
$"{proto.ID} does not have a DeviceLinkSinkComponent!");
// Spawn the tester
var sourceEnt = server.EntMan.SpawnEntity(PortTesterProtoId, coord);
Assert.That(server.EntMan.TryGetComponent<DeviceLinkSourceComponent>(sourceEnt, out var sourceComp),
$"Tester prototype does not have a DeviceLinkSourceComponent!");
// Create a link from the tester's output to the target port on the sink
deviceLinkSys.SaveLinks(null,
sourceEnt,
sinkEnt,
[("Output", port.Id)],
sourceComp,
sinkComp);
// Send a signal to the port
Assert.DoesNotThrow(() => { deviceLinkSys.InvokePort(sourceEnt, "Output", null, sourceComp); },
$"Exception thrown while triggering port {port.Id} of sink device {proto.ID}");
mapSys.DeleteMap(mapId);
}
}
});
});
await pair.CleanReturnAsync();
}
}

View File

@@ -0,0 +1,91 @@
using Content.IntegrationTests.Tests.Interaction;
using Content.Shared.Projectiles;
using Robust.Shared.Network;
namespace Content.IntegrationTests.Tests.Embedding;
public sealed class EmbedTest : InteractionTest
{
/// <summary>
/// Embeddable entity that will be thrown at the target.
/// </summary>
private const string EmbeddableProtoId = "SurvivalKnife";
/// <summary>
/// Target entity that the thrown item will embed into.
/// </summary>
private const string TargetProtoId = "AirlockGlass";
/// <summary>
/// Embeds an entity with a <see cref="EmbeddableProjectileComponent"/> into a target,
/// then disconnects the client. Intended to reveal any clientside issues that might
/// occur due to reparenting during cleanup.
/// </summary>
[Test]
public async Task TestDisconnectWhileEmbedded()
{
// Spawn the target we're going to throw at
await SpawnTarget(TargetProtoId);
// Give the player the embeddable to throw
var projectile = await PlaceInHands(EmbeddableProtoId);
Assert.That(TryComp<EmbeddableProjectileComponent>(projectile, out var embedComp),
$"{EmbeddableProtoId} does not have EmbeddableProjectileComponent");
// Make sure the projectile isn't already embedded into anything
Assert.That(embedComp.EmbeddedIntoUid, Is.Null,
$"Projectile already embedded into {SEntMan.ToPrettyString(embedComp.EmbeddedIntoUid)}");
// Have the player throw the embeddable at the target
await ThrowItem();
// Wait a moment for the item to hit and embed
await RunSeconds(0.5f);
// Make sure the projectile is embedded into the target
Assert.That(embedComp.EmbeddedIntoUid, Is.EqualTo(ToServer(Target)),
"Projectile not embedded into target");
// Disconnect the client
var cNetMgr = Client.ResolveDependency<IClientNetManager>();
await Client.WaitPost(Client.EntMan.FlushEntities);
await Pair.RunTicksSync(1);
}
/// <summary>
/// Embeds an entity with a <see cref="EmbeddableProjectileComponent"/> into a target,
/// then deletes the target and makes sure the embeddable is not deleted.
/// </summary>
[Test]
public async Task TestEmbedDetach()
{
// Spawn the target we're going to throw at
await SpawnTarget(TargetProtoId);
// Give the player the embeddable to throw
var projectile = await PlaceInHands(EmbeddableProtoId);
Assert.That(TryComp<EmbeddableProjectileComponent>(projectile, out var embedComp),
$"{EmbeddableProtoId} does not have EmbeddableProjectileComponent");
// Make sure the projectile isn't already embedded into anything
Assert.That(embedComp.EmbeddedIntoUid, Is.Null,
$"Projectile already embedded into {SEntMan.ToPrettyString(embedComp.EmbeddedIntoUid)}");
// Have the player throw the embeddable at the target
await ThrowItem();
// Wait a moment for the item to hit and embed
await RunSeconds(0.5f);
// Make sure the projectile is embedded into the target
Assert.That(embedComp.EmbeddedIntoUid, Is.EqualTo(ToServer(Target)),
"Projectile not embedded into target");
// Delete the target
await Delete(Target.Value);
await RunTicks(1);
// Make sure the embeddable wasn't deleted with the target
AssertExists(projectile);
await AssertEntityLookup(EmbeddableProtoId);
}
}

View File

@@ -155,7 +155,7 @@ public sealed class NukeOpsTest
// The game rule exists, and all the stations/shuttles/maps are properly initialized
var rule = entMan.AllComponents<NukeopsRuleComponent>().Single();
var ruleComp = rule.Component;
var gridsRule = entMan.AllComponents<RuleGridsComponent>().Single().Component;
var gridsRule = entMan.GetComponent<RuleGridsComponent>(rule.Uid);
foreach (var grid in gridsRule.MapGrids)
{
Assert.That(entMan.EntityExists(grid));

View File

@@ -19,16 +19,19 @@ public sealed class LocalizedDatasetPrototypeTest
var protos = protoMan.EnumeratePrototypes<LocalizedDatasetPrototype>().OrderBy(p => p.ID);
// Check each prototype
foreach (var proto in protos)
Assert.Multiple(() =>
{
// Check each value in the prototype
foreach (var locId in proto.Values)
// Check each prototype
foreach (var proto in protos)
{
// Make sure the localization manager has a string for the LocId
Assert.That(localizationMan.HasString(locId), $"LocalizedDataset {proto.ID} with prefix \"{proto.Values.Prefix}\" specifies {proto.Values.Count} entries, but no localized string was found matching {locId}!");
// Check each value in the prototype
foreach (var locId in proto.Values)
{
// Make sure the localization manager has a string for the LocId
Assert.That(localizationMan.HasString(locId), $"LocalizedDataset {proto.ID} with prefix \"{proto.Values.Prefix}\" specifies {proto.Values.Count} entries, but no localized string was found matching {locId}!");
}
}
}
});
await pair.CleanReturnAsync();
}

View File

@@ -22,6 +22,7 @@ using Robust.Shared.EntitySerialization.Systems;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
using Robust.Shared.Map.Events;
namespace Content.IntegrationTests.Tests
{
@@ -213,9 +214,12 @@ namespace Content.IntegrationTests.Tests
}
var deps = server.ResolveDependency<IEntitySystemManager>().DependencyCollection;
var ev = new BeforeEntityReadEvent();
server.EntMan.EventBus.RaiseEvent(EventSource.Local, ev);
foreach (var map in v7Maps)
{
Assert.That(IsPreInit(map, loader, deps));
Assert.That(IsPreInit(map, loader, deps, ev.RenamedPrototypes, ev.DeletedPrototypes));
}
// Check that the test actually does manage to catch post-init maps and isn't just blindly passing everything.
@@ -228,12 +232,12 @@ namespace Content.IntegrationTests.Tests
// First check that a pre-init version passes
var path = new ResPath($"{nameof(NoSavedPostMapInitTest)}.yml");
Assert.That(loader.TrySaveMap(id, path));
Assert.That(IsPreInit(path, loader, deps));
Assert.That(IsPreInit(path, loader, deps, ev.RenamedPrototypes, ev.DeletedPrototypes));
// and the post-init version fails.
await server.WaitPost(() => mapSys.InitializeMap(id));
Assert.That(loader.TrySaveMap(id, path));
Assert.That(IsPreInit(path, loader, deps), Is.False);
Assert.That(IsPreInit(path, loader, deps, ev.RenamedPrototypes, ev.DeletedPrototypes), Is.False);
await pair.CleanReturnAsync();
}
@@ -266,7 +270,11 @@ namespace Content.IntegrationTests.Tests
});
}
private bool IsPreInit(ResPath map, MapLoaderSystem loader, IDependencyCollection deps)
private bool IsPreInit(ResPath map,
MapLoaderSystem loader,
IDependencyCollection deps,
Dictionary<string, string> renamedPrototypes,
HashSet<string> deletedPrototypes)
{
if (!loader.TryReadFile(map, out var data))
{
@@ -274,7 +282,12 @@ namespace Content.IntegrationTests.Tests
return false;
}
var reader = new EntityDeserializer(deps, data, DeserializationOptions.Default);
var reader = new EntityDeserializer(deps,
data,
DeserializationOptions.Default,
renamedPrototypes,
deletedPrototypes);
if (!reader.TryProcessData())
{
Assert.Fail($"Failed to process {map}");

View File

@@ -35,7 +35,6 @@ public sealed class PrototypeSaveTest
await using var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var mapManager = server.ResolveDependency<IMapManager>();
var entityMan = server.ResolveDependency<IEntityManager>();
var prototypeMan = server.ResolveDependency<IPrototypeManager>();
var seriMan = server.ResolveDependency<ISerializationManager>();

View File

@@ -102,6 +102,12 @@ public sealed class StoreTests
+ $"flag as 'true'. This marks the fact that cost modifier of discount is not applied properly!"
);
// The storeComponent returns discounted items with conditions randomly, so we remove these to sanitize the data.
foreach (var discountedItem in discountedListingItems)
{
discountedItem.Conditions = null;
}
// Refund action requests re-generation of listing items so we will be re-acquiring items from component a lot of times.
var itemIds = discountedListingItems.Select(x => x.ID);
foreach (var itemId in itemIds)
@@ -140,6 +146,9 @@ public sealed class StoreTests
// get refreshed item after refund re-generated items
discountedListingItem = storeComponent.FullListingsCatalog.First(x => x.ID == itemId);
// The storeComponent can give a discounted item a condition at random, so we remove it to sanitize the data.
discountedListingItem.Conditions = null;
var afterRefundBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype];
Assert.That(afterRefundBalance.Value, Is.EqualTo(originalBalance.Value), "Expected refund to return all discounted cost value.");
Assert.That(

View File

@@ -0,0 +1,205 @@
using System.Linq;
using Content.IntegrationTests.Tests.Interaction;
using Content.Server.VendingMachines;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Content.Shared.VendingMachines;
namespace Content.IntegrationTests.Tests.Vending;
public sealed class VendingInteractionTest : InteractionTest
{
private const string VendingMachineProtoId = "InteractionTestVendingMachine";
private const string VendedItemProtoId = "InteractionTestItem";
private const string RestockBoxProtoId = "InteractionTestRestockBox";
private const string RestockBoxOtherProtoId = "InteractionTestRestockBoxOther";
[TestPrototypes]
private const string TestPrototypes = $@"
- type: entity
parent: BaseItem
id: {VendedItemProtoId}
name: {VendedItemProtoId}
- type: vendingMachineInventory
id: InteractionTestVendingInventory
startingInventory:
{VendedItemProtoId}: 5
- type: vendingMachineInventory
id: InteractionTestVendingInventoryOther
startingInventory:
{VendedItemProtoId}: 5
- type: entity
parent: BaseVendingMachineRestock
id: {RestockBoxProtoId}
components:
- type: VendingMachineRestock
canRestock:
- InteractionTestVendingInventory
- type: entity
parent: BaseVendingMachineRestock
id: {RestockBoxOtherProtoId}
components:
- type: VendingMachineRestock
canRestock:
- InteractionTestVendingInventoryOther
- type: entity
id: {VendingMachineProtoId}
parent: VendingMachine
components:
- type: VendingMachine
pack: InteractionTestVendingInventory
ejectDelay: 0 # no delay to speed up tests
- type: Sprite
sprite: error.rsi
";
[Test]
public async Task InteractUITest()
{
await SpawnTarget(VendingMachineProtoId);
// Should start with no BUI open
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI was open unexpectedly.");
// Unpowered vending machine does not open BUI
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI opened without power.");
// Power the vending machine
var apc = await SpawnEntity("APCBasic", SEntMan.GetCoordinates(TargetCoords));
await RunTicks(1);
// Interacting with powered vending machine opens BUI
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "BUI failed to open.");
// Interacting with it again closes the BUI
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI failed to close on interaction.");
// Reopen BUI for the next check
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "BUI failed to reopen.");
// Remove power
await Delete(apc);
await RunTicks(1);
// The BUI should close when power is lost
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI failed to close on power loss.");
}
[Test]
public async Task DispenseItemTest()
{
await SpawnTarget(VendingMachineProtoId);
var vendorEnt = SEntMan.GetEntity(Target.Value);
var vendingSystem = SEntMan.System<VendingMachineSystem>();
var items = vendingSystem.GetAllInventory(vendorEnt);
// Verify initial item count
Assert.That(items, Is.Not.Empty, $"{VendingMachineProtoId} spawned with no items.");
Assert.That(items.First().Amount, Is.EqualTo(5), $"{VendingMachineProtoId} spawned with unexpected item count.");
// Power the vending machine
await SpawnEntity("APCBasic", SEntMan.GetCoordinates(TargetCoords));
await RunTicks(1);
// Open the BUI
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "BUI failed to open.");
// Request an item be dispensed
var ev = new VendingMachineEjectMessage(InventoryType.Regular, VendedItemProtoId);
await SendBui(VendingMachineUiKey.Key, ev);
// Make sure the stock decreased
Assert.That(items.First().Amount, Is.EqualTo(4), "Stocked item count did not decrease.");
// Make sure the dispensed item was spawned in to the world
await AssertEntityLookup(
("APCBasic", 1),
(VendedItemProtoId, 1)
);
}
[Test]
public async Task RestockTest()
{
var vendingSystem = SEntMan.System<VendingMachineSystem>();
await SpawnTarget(VendingMachineProtoId);
var vendorEnt = SEntMan.GetEntity(Target.Value);
var items = vendingSystem.GetAllInventory(vendorEnt);
Assert.That(items, Is.Not.Empty, $"{VendingMachineProtoId} spawned with no items.");
Assert.That(items.First().Amount, Is.EqualTo(5), $"{VendingMachineProtoId} spawned with unexpected item count.");
// Try to restock with the maintenance panel closed (nothing happens)
await InteractUsing(RestockBoxProtoId);
Assert.That(items.First().Amount, Is.EqualTo(5), "Restocked without opening maintenance panel.");
// Open the maintenance panel
await InteractUsing(Screw);
// Try to restock using the wrong restock box (nothing happens)
await InteractUsing(RestockBoxOtherProtoId);
Assert.That(items.First().Amount, Is.EqualTo(5), "Restocked with wrong restock box.");
// Restock the machine
await InteractUsing(RestockBoxProtoId);
Assert.That(items.First().Amount, Is.EqualTo(10), "Restocking resulted in unexpected item count.");
}
[Test]
public async Task RepairTest()
{
await SpawnTarget(VendingMachineProtoId);
// Power the vending machine
await SpawnEntity("APCBasic", SEntMan.GetCoordinates(TargetCoords));
await RunTicks(1);
// Break it
await BreakVendor();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI did not close when vending machine broke.");
// Make sure we can't open the BUI while it's broken
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "Opened BUI of broken vending machine.");
// Repair the vending machine
await InteractUsing(Weld);
// Make sure the BUI can open now that the machine has been repaired
await Activate();
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "Failed to open BUI after repair.");
}
private async Task BreakVendor()
{
var damageableSys = SEntMan.System<DamageableSystem>();
Assert.That(TryComp<DamageableComponent>(out var damageableComp), $"{VendingMachineProtoId} does not have DamageableComponent.");
Assert.That(damageableComp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero), $"{VendingMachineProtoId} started with unexpected damage.");
// Damage the vending machine to the point that it breaks
var damageType = ProtoMan.Index<DamageTypePrototype>("Blunt");
var damage = new DamageSpecifier(damageType, FixedPoint2.New(100));
await Server.WaitPost(() => damageableSys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true));
await RunTicks(5);
Assert.That(damageableComp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero), $"{VendingMachineProtoId} did not take damage.");
}
}

View File

@@ -241,7 +241,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
var addedTags = newAccessList.Except(oldTags).Select(tag => "+" + tag).ToList();
var removedTags = oldTags.Except(newAccessList).Select(tag => "-" + tag).ToList();
_adminLogger.Add(LogType.Action, LogImpact.Medium,
_adminLogger.Add(LogType.Action, LogImpact.High,
$"{ToPrettyString(player):player} has modified {ToPrettyString(accessReaderEnt.Value):entity} with the following allowed access level holders: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
accessReaderEnt.Value.Comp.AccessLists = ConvertAccessListToHashSet(newAccessList);

View File

@@ -168,7 +168,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
/*TODO: ECS SharedIdCardConsoleComponent and then log on card ejection, together with the save.
This current implementation is pretty shit as it logs 27 entries (27 lines) if someone decides to give themselves AA*/
_adminLogger.Add(LogType.Action, LogImpact.Medium,
_adminLogger.Add(LogType.Action, LogImpact.High,
$"{ToPrettyString(player):player} has modified {ToPrettyString(targetId):entity} with the following accesses: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
}

View File

@@ -88,7 +88,7 @@ public sealed class IdCardSystem : SharedIdCardSystem
access.Tags.Add(random.ID);
Dirty(uid, access);
_adminLogger.Add(LogType.Action, LogImpact.Medium,
_adminLogger.Add(LogType.Action, LogImpact.High,
$"{ToPrettyString(args.Microwave)} added {random.ID} access to {ToPrettyString(uid):entity}");
}

View File

@@ -180,7 +180,7 @@ public sealed class ChangeCvarCommand : IConsoleCommand
var oldValue = _configurationManager.GetCVar<object>(cvar);
_configurationManager.SetCVar(cvar, parsed);
_adminLogManager.Add(LogType.AdminCommands,
LogImpact.High,
LogImpact.Extreme,
$"{shell.Player!.Name} ({shell.Player!.UserId}) changed CVAR {cvar} from {oldValue.ToString()} to {parsed.ToString()}"
);

View File

@@ -1,19 +1,19 @@
using Content.Server.Administration.Notes;
using System.Linq;
using Content.Server.Administration.Notes;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Console;
namespace Content.Server.Administration.Commands;
[AdminCommand(AdminFlags.ViewNotes)]
public sealed class OpenAdminNotesCommand : IConsoleCommand
public sealed class OpenAdminNotesCommand : LocalizedCommands
{
public const string CommandName = "adminnotes";
public string Command => CommandName;
public string Description => "Opens the admin notes panel.";
public string Help => $"Usage: {Command} <notedPlayerUserId OR notedPlayerUsername>";
public override string Command => CommandName;
public async void Execute(IConsoleShell shell, string argStr, string[] args)
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (shell.Player is not { } player)
{
@@ -33,17 +33,27 @@ public sealed class OpenAdminNotesCommand : IConsoleCommand
if (dbGuid == null)
{
shell.WriteError($"Unable to find {args[0]} netuserid");
shell.WriteError(Loc.GetString("cmd-adminnotes-wrong-target", ("user", args[0])));
return;
}
notedPlayer = dbGuid.UserId;
break;
default:
shell.WriteError($"Invalid arguments.\n{Help}");
shell.WriteError(Loc.GetString("cmd-adminnotes-args-error"));
return;
}
await IoCManager.Resolve<IAdminNotesManager>().OpenEui(player, notedPlayer);
}
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
if (args.Length != 1)
return CompletionResult.Empty;
var playerMgr = IoCManager.Resolve<IPlayerManager>();
var options = playerMgr.Sessions.Select(c => c.Name).OrderBy(c => c).ToArray();
return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-adminnotes-hint"));
}
}

View File

@@ -48,7 +48,7 @@ namespace Content.Server.Administration.Commands
}
else
{
if (player.Status != SessionStatus.InGame || player.AttachedEntity is not {Valid: true} playerEntity)
if (player.Status != SessionStatus.InGame || player.AttachedEntity is not { Valid: true } playerEntity)
{
shell.WriteLine("You are not in-game!");
return;
@@ -57,14 +57,16 @@ namespace Content.Server.Administration.Commands
var currentMap = _entManager.GetComponent<TransformComponent>(playerEntity).MapID;
var currentGrid = _entManager.GetComponent<TransformComponent>(playerEntity).GridUid;
var xformSystem = _entManager.System<SharedTransformSystem>();
var found = GetWarpPointByName(location)
.OrderBy(p => p.Item1, Comparer<EntityCoordinates>.Create((a, b) =>
{
// Sort so that warp points on the same grid/map are first.
// So if you have two maps loaded with the same warp points,
// it will prefer the warp points on the map you're currently on.
var aGrid = a.GetGridUid(_entManager);
var bGrid = b.GetGridUid(_entManager);
var aGrid = xformSystem.GetGrid(a);
var bGrid = xformSystem.GetGrid(b);
if (aGrid == bGrid)
{
@@ -81,8 +83,8 @@ namespace Content.Server.Administration.Commands
return 1;
}
var mapA = a.GetMapId(_entManager);
var mapB = a.GetMapId(_entManager);
var mapA = xformSystem.GetMapId(a);
var mapB = xformSystem.GetMapId(b);
if (mapA == mapB)
{
@@ -117,10 +119,8 @@ namespace Content.Server.Administration.Commands
return;
}
var xform = _entManager.GetComponent<TransformComponent>(playerEntity);
var xformSystem = _entManager.System<SharedTransformSystem>();
xform.Coordinates = coords;
xformSystem.AttachToGridOrMap(playerEntity, xform);
xformSystem.SetCoordinates(playerEntity, coords);
xformSystem.AttachToGridOrMap(playerEntity);
if (_entManager.TryGetComponent(playerEntity, out PhysicsComponent? physics))
{
_entManager.System<SharedPhysicsSystem>().SetLinearVelocity(playerEntity, Vector2.Zero, body: physics);

View File

@@ -2,14 +2,19 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration.Systems;
using Content.Server.Database;
using Content.Server.GameTicking;
using Content.Shared.Administration.Logs;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Players.PlayTimeTracking;
using Prometheus;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Reflection;
using Robust.Shared.Timing;
@@ -25,6 +30,9 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
[Dependency] private readonly IDynamicTypeFactory _typeFactory = default!;
[Dependency] private readonly IReflectionManager _reflection = default!;
[Dependency] private readonly IDependencyCollection _dependencies = default!;
[Dependency] private readonly ISharedPlayerManager _player = default!;
[Dependency] private readonly ISharedPlaytimeManager _playtime = default!;
[Dependency] private readonly ISharedChatManager _chat = default!;
public const string SawmillId = "admin.logs";
@@ -66,6 +74,7 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
private int _queueMax;
private int _preRoundQueueMax;
private int _dropThreshold;
private int _highImpactLogPlaytime;
// Per update
private TimeSpan _nextUpdateTime;
@@ -100,6 +109,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
value => _preRoundQueueMax = value, true);
_configuration.OnValueChanged(CCVars.AdminLogsDropThreshold,
value => _dropThreshold = value, true);
_configuration.OnValueChanged(CCVars.AdminLogsHighLogPlaytime,
value => _highImpactLogPlaytime = value, true);
if (_metricsEnabled)
{
@@ -300,6 +311,10 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
Players = new List<AdminLogPlayer>(players.Count)
};
var adminLog = false;
var adminSys = _entityManager.SystemOrNull<AdminSystem>();
var logMessage = message;
foreach (var id in players)
{
var player = new AdminLogPlayer
@@ -309,8 +324,39 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
};
log.Players.Add(player);
if (adminSys != null)
{
var cachedInfo = adminSys.GetCachedPlayerInfo(new NetUserId(id));
if (cachedInfo != null && cachedInfo.Antag)
{
logMessage += " [ANTAG: " + cachedInfo.CharacterName + "]";
}
}
if (adminLog)
continue;
if (impact == LogImpact.Extreme) // Always chat-notify Extreme logs
adminLog = true;
if (impact == LogImpact.High) // Only chat-notify High logs if the player is below a threshold playtime
{
if (_highImpactLogPlaytime >= 0 && _player.TryGetSessionById(new NetUserId(id), out var session))
{
var playtimes = _playtime.GetPlayTimes(session);
if (playtimes.TryGetValue(PlayTimeTrackingShared.TrackerOverall, out var overallTime) &&
overallTime <= TimeSpan.FromHours(_highImpactLogPlaytime))
{
adminLog = true;
}
}
}
}
if (adminLog)
_chat.SendAdminAlert(logMessage);
if (preRound)
{
_preRoundLogQueue.Enqueue(log);

View File

@@ -221,6 +221,7 @@ public sealed class AdminSystem : EntitySystem
var name = data.UserName;
var entityName = string.Empty;
var identityName = string.Empty;
var sortWeight = 0;
// Visible (identity) name can be different from real name
if (session?.AttachedEntity != null)
@@ -234,8 +235,10 @@ public sealed class AdminSystem : EntitySystem
// Starting role, antagonist status and role type
RoleTypePrototype roleType = new();
var startingRole = string.Empty;
if (_minds.TryGetMind(session, out var mindId, out var mindComp))
if (_minds.TryGetMind(session, out var mindId, out var mindComp) && mindComp is not null)
{
sortWeight = _role.GetRoleCompByTime(mindComp)?.Comp.SortWeight ?? 0;
if (_proto.TryIndex(mindComp.RoleType, out var role))
roleType = role;
else
@@ -259,8 +262,19 @@ public sealed class AdminSystem : EntitySystem
overallPlaytime = playTime;
}
return new PlayerInfo(name, entityName, identityName, startingRole, antag, roleType, GetNetEntity(session?.AttachedEntity), data.UserId,
connected, _roundActivePlayers.Contains(data.UserId), overallPlaytime);
return new PlayerInfo(
name,
entityName,
identityName,
startingRole,
antag,
roleType,
sortWeight,
GetNetEntity(session?.AttachedEntity),
data.UserId,
connected,
_roundActivePlayers.Contains(data.UserId),
overallPlaytime);
}
private void OnPanicBunkerChanged(bool enabled)

View File

@@ -1,10 +1,12 @@
using Content.Server._CP14.GameTicking.Rules.Components;
using Content.Server.Administration.Commands;
using Content.Server.Antag;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Zombies;
using Content.Shared.Administration;
using Content.Shared.Database;
using Content.Shared.Humanoid;
using Content.Shared.Mind.Components;
using Content.Shared.Roles;
using Content.Shared.Verbs;
@@ -18,6 +20,7 @@ public sealed partial class AdminVerbSystem
{
[Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly ZombieSystem _zombie = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[ValidatePrototypeId<EntityPrototype>]
private const string DefaultTraitorRule = "Traitor";
@@ -37,6 +40,8 @@ public sealed partial class AdminVerbSystem
[ValidatePrototypeId<StartingGearPrototype>]
private const string PirateGearId = "PirateGear";
private readonly EntProtoId _paradoxCloneRuleId = "ParadoxCloneSpawn";
//CP14
[ValidatePrototypeId<EntityPrototype>]
private const string CP14VampireRule = "CP14Vampire";
@@ -179,6 +184,30 @@ public sealed partial class AdminVerbSystem
Message = string.Join(": ", thiefName, Loc.GetString("admin-verb-make-thief")),
};
args.Verbs.Add(thief);
var paradoxCloneName = Loc.GetString("admin-verb-text-make-paradox-clone");
Verb paradox = new()
{
Text = paradoxCloneName,
Category = VerbCategory.Antag,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/job_icons.rsi"), "ParadoxClone"),
Act = () =>
{
var ruleEnt = _gameTicker.AddGameRule(_paradoxCloneRuleId);
if (!TryComp<ParadoxCloneRuleComponent>(ruleEnt, out var paradoxCloneRuleComp))
return;
paradoxCloneRuleComp.OriginalBody = args.Target; // override the target player
_gameTicker.StartGameRule(ruleEnt);
},
Impact = LogImpact.High,
Message = string.Join(": ", paradoxCloneName, Loc.GetString("admin-verb-make-paradox-clone")),
};
if (HasComp<HumanoidAppearanceComponent>(args.Target)) // only humanoids can be cloned
args.Verbs.Add(paradox);
*/
}
}

View File

@@ -136,7 +136,7 @@ public sealed partial class AdminVerbSystem
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
var board = Spawn("ChessBoard", xform.Coordinates);
var session = _tabletopSystem.EnsureSession(Comp<TabletopGameComponent>(board));
xform.Coordinates = _transformSystem.ToCoordinates(session.Position);
_transformSystem.SetMapCoordinates(args.Target, session.Position);
_transformSystem.SetWorldRotationNoLerp((args.Target, xform), Angle.Zero);
},
Impact = LogImpact.Extreme,
@@ -421,7 +421,7 @@ public sealed partial class AdminVerbSystem
{
var xform = Transform(args.Target);
var fixtures = Comp<FixturesComponent>(args.Target);
xform.Anchored = false; // Just in case.
_transformSystem.Unanchor(args.Target); // Just in case.
_physics.SetBodyType(args.Target, BodyType.Dynamic, manager: fixtures, body: physics);
_physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir);
_physics.WakeBody(args.Target, manager: fixtures, body: physics);
@@ -456,7 +456,7 @@ public sealed partial class AdminVerbSystem
{
var xform = Transform(args.Target);
var fixtures = Comp<FixturesComponent>(args.Target);
xform.Anchored = false; // Just in case.
_transformSystem.Unanchor(args.Target); // Just in case.
_physics.SetBodyType(args.Target, BodyType.Dynamic, body: physics);
_physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir);

View File

@@ -637,7 +637,7 @@ public sealed partial class AdminVerbSystem
{
if (_adminManager.HasAdminFlag(player, AdminFlags.Mapping))
{
if (_mapManager.IsMapPaused(map.MapId))
if (_map.IsPaused(map.MapId))
{
Verb unpauseMap = new()
{
@@ -646,7 +646,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
Act = () =>
{
_mapManager.SetMapPaused(map.MapId, false);
_map.SetPaused(map.MapId, false);
},
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-unpause-map-description"),
@@ -663,7 +663,7 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
Act = () =>
{
_mapManager.SetMapPaused(map.MapId, true);
_map.SetPaused(map.MapId, true);
},
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-pause-map-description"),

View File

@@ -53,7 +53,7 @@ namespace Content.Server.Administration.Systems
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly AdminSystem _adminSystem = default!;
[Dependency] private readonly DisposalTubeSystem _disposalTubes = default!;
@@ -153,12 +153,10 @@ namespace Content.Server.Administration.Systems
var profile = _ticker.GetPlayerProfile(targetActor.PlayerSession);
var mobUid = _spawning.SpawnPlayerMob(coords.Value, null, profile, stationUid);
var targetMind = _mindSystem.GetMind(args.Target);
if (targetMind != null)
{
_mindSystem.TransferTo(targetMind.Value, mobUid, true);
}
if (_mindSystem.TryGetMind(args.Target, out var mindId, out var mindComp))
_mindSystem.TransferTo(mindId, mobUid, true, mind: mindComp);
},
ConfirmationPopup = true,
Impact = LogImpact.High,

View File

@@ -14,6 +14,7 @@ internal sealed class ServerAlertsSystem : AlertsSystem
private void OnGetState(Entity<AlertsComponent> alerts, ref ComponentGetState args)
{
args.State = new AlertComponentState(alerts.Comp.Alerts);
// TODO: Use sourcegen when clone-state bug fixed.
args.State = new AlertComponentState(new(alerts.Comp.Alerts));
}
}

View File

@@ -240,7 +240,7 @@ public sealed class AmeControllerSystem : EntitySystem
return;
var humanReadableState = value ? "Inject" : "Not inject";
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to {humanReadableState}");
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to {humanReadableState}");
}
public void ToggleInjecting(EntityUid uid, EntityUid? user = null, AmeControllerComponent? controller = null)
@@ -267,27 +267,15 @@ public sealed class AmeControllerSystem : EntitySystem
return;
var humanReadableState = controller.Injecting ? "Inject" : "Not inject";
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to inject {controller.InjectionAmount} while set to {humanReadableState}");
/* This needs to be information which an admin is very likely to want to be informed about in order to be an admin alert or have a sound notification.
At the time of editing, players regularly "overclock" the AME and those cases require no admin attention.
// Admin alert
var safeLimit = int.MaxValue;
if (TryGetAMENodeGroup(uid, out var group))
safeLimit = group.CoreCount * 4;
if (oldValue <= safeLimit && value > safeLimit)
{
if (_gameTiming.CurTime > controller.EffectCooldown)
{
_chatManager.SendAdminAlert(user.Value, $"increased AME over safe limit to {controller.InjectionAmount}");
_audioSystem.PlayGlobal("/Audio/Misc/adminlarm.ogg",
Filter.Empty().AddPlayers(_adminManager.ActiveAdmins), false, AudioParams.Default.WithVolume(-8f));
controller.EffectCooldown = _gameTiming.CurTime + controller.CooldownDuration;
}
}
*/
var logImpact = (oldValue <= safeLimit && value > safeLimit) ? LogImpact.Extreme : LogImpact.Medium;
_adminLogger.Add(LogType.Action, logImpact, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to inject {controller.InjectionAmount} while set to {humanReadableState}");
}
public void AdjustInjectionAmount(EntityUid uid, int delta, EntityUid? user = null, AmeControllerComponent? controller = null)

View File

@@ -6,7 +6,7 @@ namespace Content.Server.Announcements;
/// <summary>
/// Used for any announcements on the start of a round.
/// </summary>
[Prototype("roundAnnouncement")]
[Prototype]
public sealed partial class RoundAnnouncementPrototype : IPrototype
{
[IdDataField]

View File

@@ -116,7 +116,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
_popup.PopupEntity(message, ent, ent, PopupType.MediumCaution);
_adminLog.Add(LogType.Anomaly,LogImpact.Extreme,$"{ToPrettyString(ent)} became anomaly host.");
_adminLog.Add(LogType.Anomaly,LogImpact.Medium,$"{ToPrettyString(ent)} became anomaly host.");
}
Dirty(ent);
}

View File

@@ -1,4 +1,5 @@
using Content.Server.Antag.Components;
using Content.Shared.GameTicking.Components;
using Content.Server.GameTicking.Rules;
namespace Content.Server.Antag;
@@ -14,9 +15,20 @@ public sealed class AntagRandomSpawnSystem : GameRuleSystem<AntagRandomSpawnComp
SubscribeLocalEvent<AntagRandomSpawnComponent, AntagSelectLocationEvent>(OnSelectLocation);
}
protected override void Added(EntityUid uid, AntagRandomSpawnComponent comp, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, comp, gameRule, args);
// we have to select this here because AntagSelectLocationEvent is raised twice because MakeAntag is called twice
// once when a ghost role spawner is created and once when someone takes the ghost role
if (TryFindRandomTile(out _, out _, out _, out var coords))
comp.Coords = coords;
}
private void OnSelectLocation(Entity<AntagRandomSpawnComponent> ent, ref AntagSelectLocationEvent args)
{
if (TryFindRandomTile(out _, out _, out _, out var coords))
args.Coordinates.Add(_transform.ToMapCoordinates(coords));
if (ent.Comp.Coords != null)
args.Coordinates.Add(_transform.ToMapCoordinates(ent.Comp.Coords.Value));
}
}

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Server.Antag.Components;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Server.GameTicking.Rules;
using Content.Server.Ghost.Roles;
using Content.Server.Ghost.Roles.Components;
@@ -65,6 +66,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
SubscribeLocalEvent<AntagSelectionComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
SubscribeLocalEvent<NoJobsAvailableSpawningEvent>(OnJobNotAssigned);
SubscribeLocalEvent<RulePlayerSpawningEvent>(OnPlayerSpawning);
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnJobsAssigned);
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
@@ -136,6 +138,28 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
}
}
private void OnJobNotAssigned(NoJobsAvailableSpawningEvent args)
{
// If someone fails to spawn in due to there being no jobs, they should be removed from any preselected antags.
// We only care about delayed rules, since if they're active the player should have already been removed via MakeAntag.
var query = QueryDelayedRules();
while (query.MoveNext(out var uid, out _, out var comp, out _))
{
if (comp.SelectionTime != AntagSelectionTime.IntraPlayerSpawn)
continue;
if (!comp.RemoveUponFailedSpawn)
continue;
foreach (var def in comp.Definitions)
{
if (!comp.PreSelectedSessions.TryGetValue(def, out var session))
break;
session.Remove(args.Player);
}
}
}
private void OnSpawnComplete(PlayerSpawnCompleteEvent args)
{
if (!args.LateJoin)
@@ -149,8 +173,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
var rules = new List<(EntityUid, AntagSelectionComponent)>();
while (query.MoveNext(out var uid, out var antag, out _))
{
if (HasComp<ActiveGameRuleComponent>(uid) ||
(HasComp<DelayedStartRuleComponent>(uid) && antag.SelectionTime == AntagSelectionTime.IntraPlayerSpawn)) //IntraPlayerSpawn selects antags before spawning, but doesn't activate until after.
if (HasComp<ActiveGameRuleComponent>(uid))
rules.Add((uid, antag));
}
RobustRandom.Shuffle(rules);
@@ -171,9 +194,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
if (!TryGetNextAvailableDefinition((uid, antag), out var def, players))
continue;
var onlyPreSelect = (antag.SelectionTime == AntagSelectionTime.IntraPlayerSpawn && !antag.AssignmentComplete); // Don't wanna give them antag status if the rule hasn't assigned its existing ones yet
if (TryMakeAntag((uid, antag), args.Player, def.Value, onlyPreSelect: onlyPreSelect))
if (TryMakeAntag((uid, antag), args.Player, def.Value))
break;
}
}
@@ -209,16 +230,12 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
if (component.AssignmentComplete)
return;
if (!component.PreSelectionsComplete)
{
var players = _playerManager.Sessions
.Where(x => GameTicker.PlayerGameStatuses.TryGetValue(x.UserId, out var status) &&
status == PlayerGameStatus.JoinedGame)
.ToList();
ChooseAntags((uid, component), players, midround: true);
}
var players = _playerManager.Sessions
.Where(x => GameTicker.PlayerGameStatuses.TryGetValue(x.UserId, out var status) &&
status == PlayerGameStatus.JoinedGame)
.ToList();
ChooseAntags((uid, component), players, midround: true);
AssignPreSelectedSessions((uid, component));
}
@@ -230,9 +247,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
/// <param name="midround">Disable picking players for pre-spawn antags in the middle of a round</param>
public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, bool midround = false)
{
if (ent.Comp.PreSelectionsComplete)
return;
foreach (var def in ent.Comp.Definitions)
{
ChooseAntags(ent, pool, def, midround: midround);
@@ -254,7 +268,8 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
bool midround = false)
{
var playerPool = GetPlayerPool(ent, pool, def);
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def);
var existingAntagCount = ent.Comp.PreSelectedSessions.TryGetValue(def, out var existingAntags) ? existingAntags.Count : 0;
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def) - existingAntagCount;
// if there is both a spawner and players getting picked, let it fall back to a spawner.
var noSpawner = def.SpawnerPrototype == null;
@@ -327,6 +342,8 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
/// </summary>
public bool TryMakeAntag(Entity<AntagSelectionComponent> ent, ICommonSession? session, AntagSelectionDefinition def, bool ignoreSpawner = false, bool checkPref = true, bool onlyPreSelect = false)
{
_adminLogger.Add(LogType.AntagSelection, $"Start trying to make {session} become the antagonist: {ToPrettyString(ent)}");
if (checkPref && !HasPrimaryAntagPreference(session, def))
return false;
@@ -384,7 +401,8 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
if (antagEnt is not { } player)
{
Log.Error($"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player.");
if (session != null)
_adminLogger.Add(LogType.AntagSelection,$"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player.");
if (session != null && ent.Comp.RemoveUponFailedSpawn)
{
ent.Comp.AssignedSessions.Remove(session);
ent.Comp.PreSelectedSessions[def].Remove(session);
@@ -393,6 +411,11 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
return;
}
// TODO: This is really messy because this part runs twice for midround events.
// Once when the ghostrole spawner is created and once when a player takes it.
// Therefore any component subscribing to this has to make sure both subscriptions return the same value
// or the ghost role raffle location preview will be wrong.
var getPosEv = new AntagSelectLocationEvent(session, ent);
RaiseLocalEvent(ent, ref getPosEv, true);
if (getPosEv.Handled)
@@ -409,6 +432,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
if (!TryComp<GhostRoleAntagSpawnerComponent>(player, out var spawnerComp))
{
Log.Error($"Antag spawner {player} does not have a GhostRoleAntagSpawnerComponent.");
_adminLogger.Add(LogType.AntagSelection,$"Antag spawner {player} in gamerule {ToPrettyString(ent)} failed due to not having GhostRoleAntagSpawnerComponent.");
if (session != null)
{
ent.Comp.AssignedSessions.Remove(session);
@@ -470,6 +494,9 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
if (!IsSessionValid(ent, session, def) || !IsEntityValid(session.AttachedEntity, def))
continue;
if (ent.Comp.PreSelectedSessions.TryGetValue(def, out var preSelected) && preSelected.Contains(session))
continue;
if (HasPrimaryAntagPreference(session, def))
{
preferredList.Add(session);

View File

@@ -1,3 +1,5 @@
using Robust.Shared.Map;
namespace Content.Server.Antag.Components;
/// <summary>
@@ -5,4 +7,11 @@ namespace Content.Server.Antag.Components;
/// Requires <see cref="AntagSelectionComponent"/>.
/// </summary>
[RegisterComponent]
public sealed partial class AntagRandomSpawnComponent : Component;
public sealed partial class AntagRandomSpawnComponent : Component
{
/// <summary>
/// Location that was picked.
/// </summary>
[DataField]
public EntityCoordinates? Coords;
}

View File

@@ -61,6 +61,13 @@ public sealed partial class AntagSelectionComponent : Component
/// </summary>
[DataField]
public LocId? AgentName;
/// <summary>
/// If the player is pre-selected but fails to spawn in (e.g. due to only having antag-immune jobs selected),
/// should they be removed from the pre-selection list?
/// </summary>
[DataField]
public bool RemoveUponFailedSpawn = true;
}
[DataDefinition]

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.Reactions
{
[Prototype("gasReaction")]
[Prototype]
public sealed partial class GasReactionPrototype : IPrototype
{
[ViewVariables]

View File

@@ -65,15 +65,11 @@ public sealed class BodySystem : SharedBodySystem
// TODO: Predict this probably.
base.AddPart(bodyEnt, partEnt, slotId);
if (TryComp<HumanoidAppearanceComponent>(bodyEnt, out var humanoid))
var layer = partEnt.Comp.ToHumanoidLayers();
if (layer != null)
{
var layer = partEnt.Comp.ToHumanoidLayers();
if (layer != null)
{
var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value);
_humanoidSystem.SetLayersVisibility(
bodyEnt, layers, visible: true, permanent: true, humanoid);
}
var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value);
_humanoidSystem.SetLayersVisibility(bodyEnt.Owner, layers, visible: true);
}
}
@@ -93,8 +89,7 @@ public sealed class BodySystem : SharedBodySystem
return;
var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value);
_humanoidSystem.SetLayersVisibility(
bodyEnt, layers, visible: false, permanent: true, humanoid);
_humanoidSystem.SetLayersVisibility((bodyEnt, humanoid), layers, visible: false);
}
public override HashSet<EntityUid> GibBody(

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