Compare commits

...

144 Commits

Author SHA1 Message Date
Ed
a463fe64d1 Update T1_Hypnosis.yml 2025-03-07 19:18:03 +03:00
Ed
9cb1f806de mimimi 2025-03-07 17:07:46 +03:00
github-actions[bot]
d97d7f6fc4 @LinkF2kkk has signed the CLA in crystallpunk-14/crystall-punk-14#987 2025-03-07 13:53:33 +00:00
Nim
228258e575 Dice (#989)
* dice

* wallet

* crate
2025-03-07 15:36:58 +03:00
Ed
6aac9d6447 Update wizard.yml 2025-03-07 14:53:58 +03:00
Ed
0b5712ce97 Vampire antag (#988)
* new blood types

* vampire systems setup

* death under sun

* vampire blood nutrition

* alerts

* autolearn skills

* base bite actions

* suck blood spell

* polish

* Update blood.yml

* unshitcode

* vampire hunger visual

* nerf speed

* hypnosis + map update

* darkness demiplane warning
2025-03-07 14:52:43 +03:00
Nim
cea7d93d12 Fixes (#975)
* fixs

* not
2025-03-06 16:33:10 +03:00
Tornado Tech
4a11cf9c53 Merge pull request #977 from crystallpunk-14/skill-remaster
Knowledge refactor
2025-03-06 22:29:36 +10:00
github-actions[bot]
19e9b3bc40 @SpyDev14 has signed the CLA in crystallpunk-14/crystall-punk-14#976 2025-03-06 10:38:37 +00:00
Tornado Tech
1ad686f42e feature: add to adghost CP14AllKnowing 2025-03-06 19:59:33 +10:00
Tornado Tech
06697abcdb fix: Books\knowledge.yml 2025-03-06 19:57:04 +10:00
Tornado Tech
1265355260 fix: CP14AddKnowledgeSpecial usings 2025-03-06 19:48:20 +10:00
github-actions[bot]
b1e985d0ad @Tornado-Technology has signed the CLA in crystallpunk-14/crystall-punk-14#977 2025-03-06 09:46:28 +00:00
Tornado Tech
ce0ec78e8d fix: CP14AddKnowledgeSpecial namespace 2025-03-06 19:43:04 +10:00
Tornado Tech
e6a28307a4 refactor: server CP14KnowledgeSystem 2025-03-06 19:42:20 +10:00
Ed
c1acf81541 NewTrade (#969)
* trading portal replace traveling storeship

* clean up content

* clean up content 2

* seel and buy realization

* fixes

* Update migration.yml

* Update migration.yml

* Update dev_map.yml

* Update dev_map.yml

* thats work correctly now

* bugfies and visual

* factions

* faction restruct + name reduce

* unnesting sell cargo positions

* unnesting cargo positions

* more cargo content

* Update buy.yml

* improve tradeportal visual

* Update migration.yml

* Bank ad Commandant removal

* merchant objectives

* finish

* clean up content

* Update migration.yml

* fix goal calculation

* Update comoss.yml

* Update dev_map.yml
2025-03-06 12:01:43 +03:00
Tornado Tech
7b5283b35b fix: Knowledge events usings (I hate Rider) 2025-03-06 18:56:06 +10:00
Tornado Tech
45a6919994 fix: KnowledgeRequired 2025-03-06 18:46:51 +10:00
Viator-MV
0d23f79eb6 Обновление скелетов (#971)
* Literally everything

Как будто я не должен был делать всё в 1 коммит

* фиксы

маленькие изменения по запросу Эда

* fix

HideSpawnMenu

* fix2

fix

* final fix

final fix
2025-03-06 11:40:30 +03:00
Tornado Tech
35e6bae5fe refactor: Add AllKnowing comp, separate paper and events 2025-03-06 18:40:17 +10:00
Tornado Tech
44f4c17266 refactor: Orthographic and obsolete in Knowledge 2025-03-06 18:22:01 +10:00
Nim
e54e8a95ee Sheep (#972)
* sheep

* demi mod
2025-03-05 17:30:06 +03:00
creamybag
d9a5869504 Merge pull request #973 from creamybag/GuildmasterHat
Guildmaster hat
2025-03-05 17:28:41 +03:00
Ed
f9ff91d74b Update default.yml 2025-03-04 13:56:12 +03:00
Ed
b7b52e664d Update Dev.toml 2025-03-03 23:59:32 +03:00
Ed
b202897c36 Merge pull request #968 from crystallpunk-14/ed-2025-03-03-upstream-stable-2
Stable upstream sync
2025-03-03 23:40:02 +03:00
Ed
acc9886242 Merge remote-tracking branch 'upstream/stable' into ed-2025-03-03-upstream-stable-2
# Conflicts:
#	Content.Client/Options/UI/OptionsMenu.xaml
#	Content.IntegrationTests/Tests/PostMapInitTest.cs
2025-03-03 23:23:40 +03:00
Nim
2855cc906b Мелкий фикс перевода (#966)
* fix

* a

* ehh

* yep
2025-03-03 23:17:00 +03:00
Ed
81b9cdfff7 Alchemy integration test (#967)
* Update TryAllReactionsTest.cs

* test drive

* fix traveling ship roundremove

* Update CP14RoundRemoveShuttleSystem.cs

* Dev map update
2025-03-03 23:15:40 +03:00
Ed
3fb7cc0cd7 minor balance tweak 2025-03-03 18:43:44 +03:00
Ed
a0b190fd97 Update vials.yml 2025-03-03 16:55:12 +03:00
Ed
719ee50c96 CP14AreaEffectBehavior 2025-03-03 16:07:19 +03:00
Ed
c7c2e7265b Update essence_collector.yml 2025-03-03 14:37:13 +03:00
Ed
bef78c62c0 Alchemical bomb (#965)
* smoke bomb system

* collector fixes

* bomb integration

* fix

* tweak
2025-03-03 14:06:50 +03:00
VideoKompany
bab794e68f Added 'arrow' to the names of the arrowheads (#964)
Co-authored-by: VideoKompany <135313844+VlaDOS1408@users.noreply.github.com>
2025-03-03 10:37:36 +03:00
Errant
3d9ce10f58 Revert "[HOTFIX] - Players with unknown playtimes now are tagged as new players" (#35639)
Revert "[HOTFIX] - Players with unknown playtimes now are tagged as new playe…"

This reverts commit 4dfd3e5740.
2025-03-03 07:49:13 +01:00
Nim
9ea547d8be Перевод на RU (#949)
* translate

* fix

* yee

* qwerty

* fix

* Signal

* Skeleton

* arrow

* fix
2025-03-03 09:38:09 +03:00
beck-thompson
4dfd3e5740 [HOTFIX] - Players with unknown playtimes now are tagged as new players (#35564)
* Players with unknown playtimes now are tagged as new players

* Fix

* I'm silly it was in the same file

* Cavar update
2025-03-02 20:45:54 +01:00
Errant
7bf09bfdb5 add altered silicon to rules (#35455)
* add altered silicon to rules

* skreee

Co-authored-by: crazybrain23 <44417085+crazybrain23@users.noreply.github.com>

---------

Co-authored-by: crazybrain23 <44417085+crazybrain23@users.noreply.github.com>
2025-03-02 20:41:07 +01:00
SlamBamActionman
08cb26dbf0 Hotfix: Fix uplinks allowing buying conditionally restricted items (#35334)
* Initial commit

* I just compressed the code

* Actually address review
2025-03-02 20:40:57 +01:00
creamybag
a16dd2fd3e Shirts in pants #2 (#934)
* New shirt, all fix

* merchant,chainmail
2025-03-02 22:16:34 +03:00
Myra
98cca7b0f8 Change Phalanximine to be more complex, increase Arithrazine damage (#32209) 2025-03-02 13:47:11 +01:00
ActiveMammmoth
cec05d697e Staff of Animation Fixes (#35491)
* staff of animation fixes and system

* requested changes

* size back to normal

* Update AnimateSpellSystem.cs

---------

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
2025-02-27 20:11:57 +01:00
slarticodefast
3c20f63292 fix subwizard gamerule (#35562) 2025-02-27 14:01:20 -05:00
PJBot
439e1c6dc0 Automatic changelog update 2025-02-27 17:58:34 +00:00
SlamBamActionman
41c51e2905 Implanter draw rework (#32136)
* Initial commit

* Clean-up

* Fix ftl, new damage

* ftl fix for real

* Updates based on feedback

* Child implant fix

* Make the UI only open when implanter is in draw mode

* Review fixes

* shunting
2025-02-27 18:57:28 +01:00
PJBot
5fdf702e3c Automatic changelog update 2025-02-27 17:45:02 +00:00
SlamBamActionman
c7b9a76342 Prevent crates, pet carriers and other things from going into disposals (#35557)
* Initial commit

* Solve underlying bug, readd to disposals

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-02-27 18:43:56 +01:00
PJBot
19c23682b0 Automatic changelog update 2025-02-27 17:26:20 +00:00
Aisu9
2db57f11ac Sap-Syrup balance (#32996)
Sap-Pancake balance

Change the conversion rate from 12:1 to 2:1
2025-02-27 09:25:12 -08:00
PJBot
3f014d2b77 Automatic changelog update 2025-02-27 13:48:23 +00:00
deltanedas
7520d8a2c8 add button to print logprobe logs (#32255)
* add EntityName at the bottom of LogProbe

* pass User into CartridgeMessageEvent

* add button to print logprobe logs

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2025-02-27 14:47:16 +01:00
PJBot
4d0e63caeb Automatic changelog update 2025-02-27 12:45:17 +00:00
āda
f80f305d1d Add filters to uniform printer (#34316)
* uniform

* missing category

* lint

* bedsheets

* carpets

* typo

* indent
2025-02-27 13:44:10 +01:00
PJBot
e705d04a12 Automatic changelog update 2025-02-27 12:41:05 +00:00
kosticia
a5aab8b8a1 Fire resist now can be examined. (#35183) 2025-02-27 23:39:55 +11:00
slarticodefast
0c6081fe10 Fix egg cooking and make microwave code a little less bad (#35459) 2025-02-27 23:39:06 +11:00
āda
3127f73c48 Multiple categories for lathe recipes (#34315)
* first

* lint

* changes

* change null comparison

* linq

* indent

* fix indent

---------

Co-authored-by: Milon <milonpl.git@proton.me>
2025-02-27 12:33:39 +01:00
Dora
53dc27cb1e Adding sorting to chem master (#34763)
* Adding sorting to chem master

* Chem Master can now sort based on following categories
 - Alphabetical
 - Quantity
 - Time Added to Machine

* Sorting is disabled by default and persist in the machine for everyone

* Removed some pointless code from Chem Master's UI

* Changed None and Time Added's text to reflect what they do better

* Minor adjustments to the code requested by maintainers
2025-02-27 12:19:52 +01:00
PJBot
c20fb21ac1 Automatic changelog update 2025-02-27 10:47:17 +00:00
qwerltaz
7b0b401312 t-ray reveal for entities and draw depth fix (#33012)
* t-rays show above catwalk

* a

* RevealSubfloorComponent

* revealSubfloorOnScan, add it to catwalk

* TrayScanReveal sys and comp

* Rr

* handle anchoring

* use tile indices for vector2i

* fix IsUnderRevealingEntity reset on pvs pop in reanchor

* fix exception on TrayScanRevealComponent remove

* fix IsUnderRevealingEntity not updating on pvs enter

* update to ent

* make subfloor retain respect for their relative draw depth

* fix carpets not revealing subfloor on plating

* chapel carpet

* ??

* draw depth gap for subfloor entities.

* revert alpha change

* remove abs from draw depth difference

* move TrayScanReveal to client

* delete old refactor

* let's show them above puddles too

* Remove superfluous component classes

---------

Co-authored-by: SlamBamActionman <slambamactionman@gmail.com>
2025-02-27 11:46:09 +01:00
PJBot
9a12bfd4e8 Automatic changelog update 2025-02-27 10:06:37 +00:00
MilenVolf
1c62e335b9 Add breakdown recipes for Insect and Ammonia blood (#33614) 2025-02-27 11:05:29 +01:00
PJBot
7351a9d1bd Automatic changelog update 2025-02-27 08:27:38 +00:00
Brassica Prime
f850b69e89 Wizard Stamp (#35552)
* First go around adds everything necessary to work

* fixes issues with attribution and a whitespace

* Update Resources/Textures/Objects/Misc/bureaucracy.rsi/meta.json

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

* Update Resources/Textures/Objects/Misc/stamps.rsi/meta.json

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

---------

Co-authored-by: Pumkin69 <judeb@DESKTOP-M4B8G5D>
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2025-02-27 11:26:30 +03:00
Emisse
16c377a05b bagel update (#35550) 2025-02-26 20:48:47 -07:00
Emisse
9d62e8c0e7 centcomm update (#35549) 2025-02-26 20:41:51 -07:00
PJBot
3557be1cff Automatic changelog update 2025-02-26 23:38:38 +00:00
DieselMohawk
7bd98b9075 Old Rollie Name Integration (#35544) 2025-02-26 15:37:31 -08:00
PJBot
6c3dbbccfe Automatic changelog update 2025-02-26 22:33:50 +00:00
Errant
c698b163b6 Admin Options tab (#35543)
* admin options tab initial

* make admin tab only visible to admins
2025-02-26 23:32:42 +01:00
Tobias Berger
8f164cffe4 Add libicu to shell.nix (#35540)
Add libicu to Nix shell

I'm not sure if it's just me but without this, the C# debugger in VSCode
simply does not work
2025-02-26 19:54:33 +01:00
ScarKy0
058d9fec09 Wizard robes allow you to wear gas tanks (#35537)
Update misc.yml
2025-02-26 18:41:42 +01:00
ScarKy0
7c6028bc80 Wizard ID (#35530)
* init

* comment

* agentless

* sprite changes
2025-02-26 15:06:18 +01:00
slarticodefast
7283f9b6dc fix delta state in SharedGunSystem (#35510) 2025-02-26 22:11:17 +11:00
SpeltIncorrectyl
e86770f5a0 Mime can no longer write on paper without breaking their vow (#35043)
Co-authored-by: Simon <63975668+Simyon264@users.noreply.github.com>
2025-02-26 10:11:59 +01:00
PJBot
08a274dc28 Automatic changelog update 2025-02-26 05:35:17 +00:00
keronshb
68de58eb66 THE WIZARD (#35406)
* Adds Survivor Antag

* Adds Survivor Role

* Adds Survivor Rule ECS, adds a survivor role event, adds make antagonist to  random global spawn spell

* Moves Survivor Ensurecomp to event handler. Makes Add Survivor Role a broadcast. Adds Survivor Component. Removes redundant briefing.

* Adds Survivor Antagonist role type for admins to keep track of this easier, adds it to Survivor.

* Adds access to survivor game rule system

* Adds Survivor Rule

* Adds end of round survivor text

* Adds end of round reporting logic. Adds logic to start the survivor rule.

* Changes desc from centcomm to shuttle

* survivor (S)

* Checks if they're alive on the shuttle instead of centcomm.

* ftl text selection based on number of survivors.

* Removed Survivor Antagonist, replaced it with Free Agent.

* Adds InvalidForGlobalSpawnSpell tag, checks for it on spawnspell, and adds it to a zombified person.

* Changes logic so we launch the game rule if it hasnt launched yet. Moves rule logic starting to server. Moved survivor rule logic out of event and into Start method.

* Fixes invalid entity issue

* Descs for Survivor Rule and Survivor comps

* Moves Survivor Rule to its own yml

* Checks for dead survivors, changes survivor checks for mind. Adds survivor comp to mind to fix any mindswap issues. Same for invalid survivor tag

* Changes shuttle xform call to just mapid

* Protoid fix

* THE WIZARD

* Wizard spawner

* adds the correct state

* Wizard preset and weight

* Fixes wizard rule

* Weight back to 100%

* Adds Random Metadata

* Wizard locs

* Puts requirements in the right place

* Adds wiz ghost spawner and mob

* wizard spawnpoint fix + shuttle mapping

* wizard loadout + fix wizard spawning + wizard random name

* comment

* Adds Wizard testing

* FIXES SHUTTLE ISSUE BASED REI

* THE WIZARD LOBBY SONG. Special thanks to song creator Chris Remo for allowing us to use this.

* Free Objective ECS + Base Free Objective

* Space Wizard Federation for Wiz Obj issuer.

* Wizard Objectives

* Moves wizard shuttle to base wizard rule. Gives Wizard their objectives. Removes WizardRule

* Renames midround to subgamemodes. Adds wizard sub game mode.

* Adds SubWizard to SubGameModesRule. Adds a SubGameMode with no wizard. Adds No SubGamemodeRule for Wizard preset

* Wizard midround event

* Fixes wizard midround

* Wizard Guidebook

* Removes todo

* Fixes text

* Removes wizard rule ECS, not needed

* Wizard jetpack

---------

Co-authored-by: ScarKy0 <scarky0@onet.eu>
Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
2025-02-25 22:34:07 -07:00
Spessmann
6ea742d4b4 Convex update (#35513) 2025-02-25 20:20:03 -07:00
ToastEnjoyer
11dd26e08e Made forensic scanner classified as contraband. (#35512)
Update forensic_scanner.yml
2025-02-25 18:22:20 -08:00
PJBot
6e269c65d8 Automatic changelog update 2025-02-26 02:19:49 +00:00
Momo
f65ff0bd37 Lizard Plushie Slippers (#35381)
* added the lizard plushie slippers yippeegit status

* fixed attributions so that the links arent broken

* update meta.json links

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

* four spacing in meta.json

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2025-02-25 18:18:42 -08:00
PJBot
d949feeacf Automatic changelog update 2025-02-26 01:22:52 +00:00
Brassica Prime
9615bc64f8 Engineers can now choose to wear no head piece (#35508)
fixes engi loadout

Co-authored-by: Pumkin69 <judeb@DESKTOP-M4B8G5D>
2025-02-25 20:21:45 -05:00
Sparlight
9f4a4b81ac Add species-specific code for ToggleableLightVisuals (#35482) 2025-02-25 09:00:37 -08:00
PJBot
f165223a5e Automatic changelog update 2025-02-25 16:41:46 +00:00
pathetic meowmeow
ab9c78b066 Make escape key work as expected with multiple open inventories (#35040) 2025-02-25 17:40:39 +01:00
PJBot
92006deede Automatic changelog update 2025-02-25 16:01:28 +00:00
noirogen
263f915671 Adds new speech bubble opacity sliders to the accessibility menu. (#35346)
* Adds new accessibility slider for speech bubble text opacity.
Adds new accessibility slider for speech bubble background opacity.
Adds new Cvars to track speech bubble text and background opacity settings.

* Adds a separate option slider for the opacity of the speaker's name on speech bubbles.

* Changes text and speaker default opacity to 100%, as it was before.

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-02-25 17:00:12 +01:00
PJBot
183ea1043b Automatic changelog update 2025-02-25 14:44:09 +00:00
spderman3333
7ddad07118 Unbreakable bar sign fix. (#35490)
* Fixed bar signs being indestructable

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-02-25 15:43:03 +01:00
PJBot
594811a686 Automatic changelog update 2025-02-25 14:26:56 +00:00
ScarKy0
afe83e1231 [ADMIN] Admin IDs now have Agent ID properties (#35345)
init
2025-02-25 15:25:48 +01:00
PJBot
8265fb215b Automatic changelog update 2025-02-25 13:46:27 +00:00
Theodore Lukin
7f67ff4b26 borgs don't scream (#33038)
* borgs don't scream

* revert that
2025-02-25 14:45:19 +01:00
PJBot
e761ab5815 Automatic changelog update 2025-02-25 03:53:14 +00:00
slarticodefast
920df98f76 fix mousetraps (#35486)
fix mousetrap
2025-02-24 19:52:05 -08:00
Winkarst
1e435822c7 Cleanup: Fix formatting in `CCVars.Game` (#35483)
Cleanup
2025-02-25 00:42:15 +01:00
PJBot
309d21bb4c Automatic changelog update 2025-02-24 23:22:39 +00:00
Errant
285decd734 Make the version watermark less annoying (#35484)
* make version watermark less annoying

* skreee
2025-02-25 00:21:33 +01:00
Winkarst
5eeba30211 Cleanup: Make `EyeCursorOffsetSystem` sealed (#35481)
Cleanup
2025-02-24 17:46:04 -05:00
lzk
237df1c9a1 fix ion storm code readability (#35337)
fix ion storm readability
2025-02-25 08:36:56 +11:00
PJBot
02f5015830 Automatic changelog update 2025-02-24 21:36:48 +00:00
Vortebo
52df2dbe15 Custom arrivals shuttle for Relic (#35194)
* Custom arrivals shuttle for Relic.

* Added shuttle APU

* Saved it as a grid the way I now see the mapping guide said I was supposed to do it

* Relic arrivals hallway more historically accurate.

* Removed invalid configurator
2025-02-24 14:35:41 -07:00
PJBot
1a76e4fd52 Automatic changelog update 2025-02-24 21:30:13 +00:00
Schrödinger
2958706e04 [ADMIN minor update] Add Autocompletion for Player Usernames in SetMind Command (#35477)
* add(src): Add getCompletion player for setmind command

* tweak(src): Fulfilling review requirements. used CompletionHelper.SessionNames()

* tweak(loc): Add localization

* fix(srs): smail
2025-02-24 22:29:05 +01:00
Winkarst
004e54af51 Cleanup: Use `SoundCollectionSpecifier instead of string literals in BibleSystem` (#35448)
* Cleanup

* Update
2025-02-25 08:23:50 +11:00
Winkarst
ebc1bff4cb Cleanup: Use `SoundCollectionSpecifier instead of string literals in PowerGridCheckRule` (#35449)
* Cleanup

* Update

* .

* Volume
2025-02-25 08:16:10 +11:00
Winkarst
c899ae7649 Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in SalvageSystem.Magnet` (#35475)
Cleanup
2025-02-24 21:29:12 +01:00
Winkarst
08bc8436a5 Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in StartingGearPrototypeStorageTest` (#35474)
* Cleanup

* Fix
2025-02-24 21:26:40 +01:00
Winkarst
4d72a2d5f3 Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in MindTests` (#35473)
* Cleanup

* Fix
2025-02-24 21:26:04 +01:00
Winkarst
16787a0281 Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in MaterialPrototypeSpawnsStackMaterialTest` (#35472)
* Cleanup

* Fix
2025-02-24 21:12:25 +01:00
Winkarst
e22c3b1eeb Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in MaterialArbitrageTest` (#35471)
Cleanup
2025-02-24 21:11:33 +01:00
Winkarst
5fbe217db3 Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in InteractionTest` (#35470)
Cleanup
2025-02-24 21:10:59 +01:00
Winkarst
059c64a75f Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in HumanInventoryUniformSlotsTest` (#35469)
* Cleanup

* Fix
2025-02-24 21:10:09 +01:00
Winkarst
363eec1465 Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in HandTests` (#35468)
* Cleanup

* Update

* Fix
2025-02-24 21:09:24 +01:00
Winkarst
d1415d9dcb Cleanup: Use `MapSystem.DeleteMap instead of IMapManager.DeleteMap in CargoTest` (#35467)
* Cleanup

* Update

* Fix
2025-02-24 21:04:54 +01:00
Winkarst
7fc8dcb811 Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside SharedChameleonProjectorSystem` (#35465)
* Cleanup

* Yes
2025-02-24 20:45:17 +01:00
Winkarst
670791ac49 Cleanup: Remove redundant checks from `SharedWieldableSystem` (#35466)
Cleanup
2025-02-24 20:22:19 +01:00
ScarKy0
51104a7316 TryGetRandomRecord in StationRecordsSystem (#35452)
* init

* requested changes

* stuff
2025-02-24 19:05:32 +01:00
Winkarst
bb110b376e Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside SharedStackSystem` (#35464)
Cleanup
2025-02-24 18:59:06 +01:00
Winkarst
02f0190c35 Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside SharedMaterialStorageSystem` (#35463)
Cleanup
2025-02-24 18:58:25 +01:00
Winkarst
45e7891706 Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside ImmovableRodRule` (#35462)
Cleanup
2025-02-24 18:57:39 +01:00
Winkarst
22398ea342 Cleanup: Fix field naming rule violation in `GhostComponent` (#35454)
* Fix

* Update Content.Shared/Ghost/GhostComponent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-02-24 18:48:32 +01:00
Winkarst
0148c441e6 Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside EventManagerSystem` (#35460)
Cleanup
2025-02-24 18:45:00 +01:00
Winkarst
615d548021 Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside MaterialStorageSystem` (#35458)
* Cleanup

* Update
2025-02-24 18:38:40 +01:00
Winkarst
969e7bdd39 Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside FlatpackSystem` (#35457)
* Cleanup

* Update
2025-02-24 18:37:50 +01:00
Winkarst
c71e6e67aa Cleanup: Pass in `IComponentFactory in EntityPrototype.TryGetComponent calls inside ChemistryGuideDataSystem` (#35456)
* Cleanup

* Update
2025-02-24 18:36:17 +01:00
ScarKy0
88308356db Move FingerprintComponent and FingerprintMaskComponent to shared (#35451)
* init

* review

* whoopsie
2025-02-24 17:23:11 +01:00
ScarKy0
c3784a3005 GettingUsedAttemptEvent (#35450)
* init

* review

* doc

* Update Content.Shared/Interaction/Events/GettingUsedAttemptEvent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-02-24 17:21:17 +01:00
Winkarst
f4fab85e34 Cleanup: Use `SoundSpecifier instead of string literals in EyeClosingComponent` (#35425)
* Cleanup

* Update

* Update

* Update
2025-02-24 17:10:23 +01:00
PJBot
6fa4767b4c Automatic changelog update 2025-02-24 09:44:51 +00:00
metalgearsloth
ac9c8b8275 Fix arrivals (#35439) 2025-02-24 20:43:43 +11:00
metalgearsloth
5385683b7e Fix admin test arena (#35444)
* Fix admin test arena

* Add to GridsLoadableTest

* QueueDel map, remove nullable

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2025-02-24 17:05:59 +11:00
Pieter-Jan Briers
05de5bd3eb Fix bogus AdminNameOverlay Rider error (#35432) 2025-02-24 15:37:54 +11:00
Tayrtahn
6f925dd610 Fix prototypes so they pass analyzer checks (#35435) 2025-02-24 15:21:59 +11:00
PJBot
0d84d25067 Automatic changelog update 2025-02-23 23:31:07 +00:00
Tiniest Shark
b7c86cae71 Put Neckwear above Backpacks (#35322)
Puts Neck layer on top of Back.
2025-02-24 00:29:59 +01:00
Winkarst
fa73217b52 Cleanup: Use `SoundSpecifier instead of string literals in VomitSystem` (#35426)
* Cleanup

* Update

* Update
2025-02-23 22:53:04 +01:00
Winkarst
91f2c46f56 Fix: Admin-only messages still show "(S)" on Discord (#35431)
Fix
2025-02-23 22:43:14 +01:00
PJBot
1404095f27 Automatic changelog update 2025-02-23 20:04:17 +00:00
No Elka
9fb5517afa Make holoparasite's damage transfer ignore the host's armor (#35418)
Change stuff
2025-02-23 21:03:11 +01:00
SlamBamActionman
fe69de942f Updated values 2024-11-01 12:52:12 +01:00
SlamBamActionman
5794ecd28f Initial commit 2024-09-16 11:05:57 +02:00
601 changed files with 21222 additions and 81891 deletions

View File

@@ -85,7 +85,7 @@ internal sealed class AdminNameOverlay : Overlay
{
args.ScreenHandle.DrawString(_font, screenCoordinates + (lineoffset * 2), _antagLabelClassic, uiScale, _antagColorClassic);
}
else if (!classic && _filter.Contains(playerInfo.RoleProto.ID))
else if (!classic && _filter.Contains(playerInfo.RoleProto))
{
var label = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
var color = playerInfo.RoleProto.Color;

View File

@@ -1,4 +1,5 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.UserInterface;
@@ -13,16 +14,23 @@ public sealed partial class LogProbeUi : UIFragment
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
public override void Setup(BoundUserInterface ui, EntityUid? fragmentOwner)
{
_fragment = new LogProbeUiFragment();
_fragment.OnPrintPressed += () =>
{
var ev = new LogProbePrintMessage();
var message = new CartridgeUiMessage(ev);
ui.SendMessage(message);
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not LogProbeUiState logProbeUiState)
if (state is not LogProbeUiState cast)
return;
_fragment?.UpdateState(logProbeUiState.PulledLogs);
_fragment?.UpdateState(cast.EntityName, cast.PulledLogs);
}
}

View File

@@ -18,4 +18,9 @@
<ScrollContainer VerticalExpand="True" HScrollEnabled="True">
<BoxContainer Orientation="Vertical" Name="ProbedDeviceContainer"/>
</ScrollContainer>
<BoxContainer Orientation="Horizontal" Margin="4 8">
<Button Name="PrintButton" HorizontalAlignment="Left" Text="{Loc 'log-probe-print-button'}" Disabled="True"/>
<BoxContainer HorizontalExpand="True"/>
<Label Name="EntityName" Align="Right"/>
</BoxContainer>
</cartridges:LogProbeUiFragment>

View File

@@ -8,17 +8,24 @@ namespace Content.Client.CartridgeLoader.Cartridges;
[GenerateTypedNameReferences]
public sealed partial class LogProbeUiFragment : BoxContainer
{
/// <summary>
/// Action invoked when the print button gets pressed.
/// </summary>
public Action? OnPrintPressed;
public LogProbeUiFragment()
{
RobustXamlLoader.Load(this);
PrintButton.OnPressed += _ => OnPrintPressed?.Invoke();
}
public void UpdateState(List<PulledAccessLog> logs)
public void UpdateState(string name, List<PulledAccessLog> logs)
{
ProbedDeviceContainer.RemoveAllChildren();
EntityName.Text = name;
PrintButton.Disabled = string.IsNullOrEmpty(name);
//Reverse the list so the oldest entries appear at the bottom
logs.Reverse();
ProbedDeviceContainer.RemoveAllChildren();
var count = 1;
foreach (var log in logs)

View File

@@ -217,7 +217,7 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { label },
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity))
};
return panel;
@@ -247,21 +247,23 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { label },
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity)),
};
return unfanciedPanel;
}
var bubbleHeader = new RichTextLabel
{
Margin = new Thickness(1, 1, 1, 1)
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleSpeakerOpacity)),
Margin = new Thickness(1, 1, 1, 1),
};
var bubbleContent = new RichTextLabel
{
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleTextOpacity)),
MaxWidth = SpeechMaxWidth,
Margin = new Thickness(2, 6, 2, 2),
StyleClasses = { "bubbleContent" }
StyleClasses = { "bubbleContent" },
};
//We'll be honest. *Yes* this is hacky. Doing this in a cleaner way would require a bottom-up refactor of how saycode handles sending chat messages. -Myr
@@ -273,7 +275,7 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { bubbleContent },
ModulateSelfOverride = Color.White.WithAlpha(0.75f),
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity)),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Bottom,
Margin = new Thickness(4, 14, 4, 2)
@@ -283,7 +285,7 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { bubbleHeader },
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.ChatFancyNameBackground) ? 0.75f : 0f),
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.ChatFancyNameBackground) ? ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity) : 0f),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Top
};

View File

@@ -94,7 +94,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
if (entProto.Abstract || usedNames.Contains(entProto.Name))
continue;
if (!entProto.TryGetComponent<ExtractableComponent>(out var extractableComponent))
if (!entProto.TryGetComponent<ExtractableComponent>(out var extractableComponent, EntityManager.ComponentFactory))
continue;
//these bloat the hell out of blood/fat
@@ -121,7 +121,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
if (extractableComponent.GrindableSolution is { } grindableSolutionId &&
entProto.TryGetComponent<SolutionContainerManagerComponent>(out var manager) &&
entProto.TryGetComponent<SolutionContainerManagerComponent>(out var manager, EntityManager.ComponentFactory) &&
_solutionContainer.TryGetSolution(manager, grindableSolutionId, out var grindableSolution))
{
var data = new ReagentEntitySourceData(

View File

@@ -46,6 +46,8 @@ namespace Content.Client.Chemistry.UI
_window.CreateBottleButton.OnPressed += _ => SendMessage(
new ChemMasterOutputToBottleMessage(
(uint) _window.BottleDosage.Value, _window.LabelLine));
_window.BufferSortButton.OnPressed += _ => SendMessage(
new ChemMasterSortingTypeCycleMessage());
for (uint i = 0; i < _window.PillTypeButtons.Length; i++)
{

View File

@@ -34,6 +34,7 @@
<Label Text="{Loc 'chem-master-window-buffer-text'}" />
<Control HorizontalExpand="True" />
<Button MinSize="80 0" Name="BufferTransferButton" Access="Public" Text="{Loc 'chem-master-window-transfer-button'}" ToggleMode="True" StyleClasses="OpenRight" />
<Button MinSize="80 0" Name="BufferSortButton" Access="Public" Text="{Loc 'chem-master-window-sort-type-none'}" StyleClasses="OpenBoth" />
<Button MinSize="80 0" Name="BufferDiscardButton" Access="Public" Text="{Loc 'chem-master-window-discard-button'}" ToggleMode="True" StyleClasses="OpenLeft" />
</BoxContainer>

View File

@@ -140,17 +140,17 @@ namespace Content.Client.Chemistry.UI
// Ensure the Panel Info is updated, including UI elements for Buffer Volume, Output Container and so on
UpdatePanelInfo(castState);
BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
InputEjectButton.Disabled = castState.InputContainerInfo is null;
OutputEjectButton.Disabled = castState.OutputContainerInfo is null;
CreateBottleButton.Disabled = castState.OutputContainerInfo?.Reagents == null;
CreatePillButton.Disabled = castState.OutputContainerInfo?.Entities == null;
UpdateDosageFields(castState);
}
//assign default values for pill and bottle fields.
private void UpdateDosageFields(ChemMasterBoundUserInterfaceState castState)
{
@@ -162,8 +162,9 @@ namespace Content.Client.Chemistry.UI
var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0;
PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit);
PillTypeButtons[castState.SelectedPillType].Pressed = true;
PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax;
PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit;
BottleDosage.IsValid = x => x >= 0 && x <= bottleAmountMax;
@@ -213,6 +214,17 @@ namespace Content.Client.Chemistry.UI
BufferInfo.Children.Clear();
// This has to happen here due to people possibly
// setting sorting before putting any chemicals
BufferSortButton.Text = state.SortingType switch
{
ChemMasterSortingType.Alphabetical => Loc.GetString("chem-master-window-sort-type-alphabetical"),
ChemMasterSortingType.Quantity => Loc.GetString("chem-master-window-sort-type-quantity"),
ChemMasterSortingType.Latest => Loc.GetString("chem-master-window-sort-type-latest"),
_ => Loc.GetString("chem-master-window-sort-type-none")
};
if (!state.BufferReagents.Any())
{
BufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") });
@@ -235,19 +247,48 @@ namespace Content.Client.Chemistry.UI
};
bufferHBox.AddChild(bufferVol);
// initialises rowCount to allow for striped rows
var rowCount = 0;
// This sets up the needed data for sorting later in a list
// Its done this way to not repeat having to use same code twice (once for sorting
// and once for displaying)
var reagentList = new List<(ReagentId reagentId, string name, Color color, FixedPoint2 quantity)>();
foreach (var (reagent, quantity) in state.BufferReagents)
{
var reagentId = reagent;
_prototypeManager.TryIndex(reagentId.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color);
BufferInfo.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagentId, quantity, true, true));
reagentList.Add(new (reagentId, name, reagentColor, quantity));
}
// We sort here since we need sorted list to be filled first.
// You can easily add any new params you need to it.
switch (state.SortingType)
{
case ChemMasterSortingType.Alphabetical:
reagentList = reagentList.OrderBy(x => x.name).ToList();
break;
case ChemMasterSortingType.Quantity:
reagentList = reagentList.OrderByDescending(x => x.quantity).ToList();
break;
case ChemMasterSortingType.Latest:
reagentList = Enumerable.Reverse(reagentList).ToList();
break;
case ChemMasterSortingType.None:
default:
// This case is pointless but it is there for readability
break;
}
// initialises rowCount to allow for striped rows
var rowCount = 0;
foreach (var reagent in reagentList)
{
BufferInfo.Children.Add(BuildReagentRow(reagent.color, rowCount++, reagent.name, reagent.reagentId, reagent.quantity, true, true));
}
}
private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
{
control.Children.Clear();
@@ -295,7 +336,7 @@ namespace Content.Client.Chemistry.UI
_prototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color);
control.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagent.Reagent, reagent.Quantity, false, addReagentButtons));
}
}
@@ -315,7 +356,7 @@ namespace Content.Client.Chemistry.UI
}
//this calls the separated button builder, and stores the return to render after labels
var reagentButtonConstructors = CreateReagentTransferButtons(reagent, isBuffer, addReagentButtons);
// Create the row layout with the color panel
var rowContainer = new BoxContainer
{
@@ -358,7 +399,7 @@ namespace Content.Client.Chemistry.UI
Children = { rowContainer }
};
}
public string LabelLine
{
get => LabelLineEdit.Text;

View File

@@ -27,7 +27,7 @@ public sealed class FlatpackSystem : SharedFlatpackSystem
if (!PrototypeManager.TryIndex<EntityPrototype>(machineBoardId, out var machineBoardPrototype))
return;
if (!machineBoardPrototype.TryGetComponent<SpriteComponent>(out var sprite))
if (!machineBoardPrototype.TryGetComponent<SpriteComponent>(out var sprite, EntityManager.ComponentFactory))
return;
Color? color = null;

View File

@@ -59,13 +59,13 @@ namespace Content.Client.Gameplay
// Version number watermark.
_version = new Label();
_version.FontColorOverride = Color.FromHex("#FFFFFF20");
_version.Text = _changelog.GetClientVersion();
_version.Visible = VersionVisible();
UserInterfaceManager.PopupRoot.AddChild(_version);
_configurationManager.OnValueChanged(CCVars.HudVersionWatermark, (show) => { _version.Visible = VersionVisible(); });
_configurationManager.OnValueChanged(CCVars.ForceClientHudVersionWatermark, (show) => { _version.Visible = VersionVisible(); });
_configurationManager.OnValueChanged(CCVars.HudVersionWatermark, (show) => { _version.Visible = VersionVisible(); }, true);
_configurationManager.OnValueChanged(CCVars.ForceClientHudVersionWatermark, (show) => { _version.Visible = VersionVisible(); }, true);
// TODO make this centered or something
LayoutContainer.SetPosition(_version, new Vector2(800, 0));
LayoutContainer.SetPosition(_version, new Vector2(70, 0));
}
// This allows servers to force the watermark on clients

View File

@@ -155,7 +155,7 @@ namespace Content.Client.Ghost
private void OnGhostState(EntityUid uid, GhostComponent component, ref AfterAutoHandleStateEvent args)
{
if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.LayerSetColor(0, component.color);
sprite.LayerSetColor(0, component.Color);
if (uid != _playerManager.LocalEntity)
return;

View File

@@ -2,11 +2,15 @@
using Content.Client.Items;
using Content.Shared.Implants;
using Content.Shared.Implants.Components;
using Robust.Shared.Prototypes;
namespace Content.Client.Implants;
public sealed class ImplanterSystem : SharedImplanterSystem
{
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public override void Initialize()
{
base.Initialize();
@@ -17,6 +21,18 @@ public sealed class ImplanterSystem : SharedImplanterSystem
private void OnHandleImplanterState(EntityUid uid, ImplanterComponent component, ref AfterAutoHandleStateEvent args)
{
if (_uiSystem.TryGetOpenUi<DeimplantBoundUserInterface>(uid, DeimplantUiKey.Key, out var bui))
{
Dictionary<string, string> implants = new();
foreach (var implant in component.DeimplantWhitelist)
{
if (_proto.TryIndex(implant, out var proto))
implants.Add(proto.ID, proto.Name);
}
bui.UpdateState(implants, component.DeimplantChosen);
}
component.UiUpdateNeeded = true;
}
}

View File

@@ -0,0 +1,35 @@
using Content.Shared.Implants;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Implants.UI;
public sealed class DeimplantBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _protomanager = default!;
[ViewVariables]
private DeimplantChoiceWindow? _window;
public DeimplantBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<DeimplantChoiceWindow>();
_window.OnImplantChange += implant => SendMessage(new DeimplantChangeVerbMessage(implant));
}
public void UpdateState(Dictionary<string, string> implantList, string? implant)
{
if (_window != null)
{
_window.UpdateImplantList(implantList);
_window.UpdateState(implant);
}
}
}

View File

@@ -0,0 +1,12 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'implanter-set-draw-window'}"
MinSize="5 30">
<BoxContainer Orientation="Vertical" Margin="10 5">
<Label Text="{Loc 'implanter-set-draw-info'}" Margin="0 0 0 5"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'implanter-set-draw-type'}" Margin="0 0 5 0"/>
<OptionButton Name="ImplantSelector"/> <!-- Populated in LoadVerbs -->
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,53 @@
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using System.Linq;
namespace Content.Client.Implants.UI;
[GenerateTypedNameReferences]
public sealed partial class DeimplantChoiceWindow : FancyWindow
{
public Action<string?>? OnImplantChange;
private Dictionary<string, string> _implants = new();
private string? _chosenImplant;
public DeimplantChoiceWindow()
{
RobustXamlLoader.Load(this);
ImplantSelector.OnItemSelected += args =>
{
OnImplantChange?.Invoke(_implants.ElementAt(args.Id).Key);
ImplantSelector.SelectId(args.Id);
};
}
public void UpdateImplantList(Dictionary<string, string> implants)
{
_implants = implants;
int i = 0;
ImplantSelector.Clear();
foreach (var implantDict in _implants)
{
ImplantSelector.AddItem(implantDict.Value, i);
i++;
}
}
public void UpdateState(string? implant)
{
_chosenImplant = implant;
for (int id = 0; id < ImplantSelector.ItemCount; id++)
{
if (_implants.ElementAt(id).Key.Equals(_chosenImplant))
{
ImplantSelector.SelectId(id);
break;
}
}
}
}

View File

@@ -4,17 +4,20 @@ using Content.Client.UserInterface.Controls;
using Content.Shared.Implants.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Implants.UI;
public sealed class ImplanterStatusControl : Control
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
private readonly ImplanterComponent _parent;
private readonly RichTextLabel _label;
public ImplanterStatusControl(ImplanterComponent parent)
{
IoCManager.InjectDependencies(this);
_parent = parent;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
_label.MaxWidth = 350;
@@ -43,12 +46,25 @@ public sealed class ImplanterStatusControl : Control
_ => Loc.GetString("injector-invalid-injector-toggle-mode")
};
var implantName = _parent.ImplanterSlot.HasItem
? _parent.ImplantData.Item1
: Loc.GetString("implanter-empty-text");
if (_parent.CurrentMode == ImplanterToggleMode.Draw)
{
string implantName = _parent.DeimplantChosen != null
? (_prototype.TryIndex(_parent.DeimplantChosen.Value, out EntityPrototype? implantProto) ? implantProto.Name : Loc.GetString("implanter-empty-text"))
: Loc.GetString("implanter-empty-text");
_label.SetMarkup(Loc.GetString("implanter-label",
("implantName", implantName),
("modeString", modeStringLocalized)));
_label.SetMarkup(Loc.GetString("implanter-label-draw",
("implantName", implantName),
("modeString", modeStringLocalized)));
}
else
{
var implantName = _parent.ImplanterSlot.HasItem
? _parent.ImplantData.Item1
: Loc.GetString("implanter-empty-text");
_label.SetMarkup(Loc.GetString("implanter-label-inject",
("implantName", implantName),
("modeString", modeStringLocalized)));
}
}
}

View File

@@ -94,8 +94,17 @@ public sealed partial class LatheMenu : DefaultWindow
if (!_prototypeManager.TryIndex(recipe, out var proto))
continue;
if (CurrentCategory != null && proto.Category != CurrentCategory)
continue;
// Category filtering
if (CurrentCategory != null)
{
if (proto.Categories.Count <= 0)
continue;
var validRecipe = proto.Categories.Any(category => category == CurrentCategory);
if (!validRecipe)
continue;
}
if (SearchBar.Text.Trim().Length != 0)
{
@@ -179,18 +188,22 @@ public sealed partial class LatheMenu : DefaultWindow
public void UpdateCategories()
{
// Get categories from recipes
var currentCategories = new List<ProtoId<LatheCategoryPrototype>>();
foreach (var recipeId in Recipes)
{
var recipe = _prototypeManager.Index(recipeId);
if (recipe.Category == null)
if (recipe.Categories.Count <= 0)
continue;
if (currentCategories.Contains(recipe.Category.Value))
continue;
foreach (var category in recipe.Categories)
{
if (currentCategories.Contains(category))
continue;
currentCategories.Add(recipe.Category.Value);
currentCategories.Add(category);
}
}
if (Categories != null && (Categories.Count == currentCategories.Count || !Categories.All(currentCategories.Contains)))

View File

@@ -10,7 +10,7 @@ using Robust.Client.Player;
namespace Content.Client.Movement.Systems;
public partial class EyeCursorOffsetSystem : EntitySystem
public sealed partial class EyeCursorOffsetSystem : EntitySystem
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;

View File

@@ -9,6 +9,7 @@
<tabs:KeyRebindTab Name="KeyRebindTab" />
<tabs:AudioTab Name="AudioTab" />
<tabs:AccessibilityTab Name="AccessibilityTab" />
<tabs:AdminOptionsTab Name="AdminOptionsTab" />
<!-- CP14-options-menu-start -->
<options:CP14OptionsMenuMainTab Name="CP14OptionsMenuTab"/>
<!-- CP14-options-menu-end -->

View File

@@ -1,4 +1,4 @@
using Content.Client.Options.UI.Tabs;
using Content.Client.Administration.Managers;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@@ -8,6 +8,8 @@ namespace Content.Client.Options.UI
[GenerateTypedNameReferences]
public sealed partial class OptionsMenu : DefaultWindow
{
[Dependency] private readonly IClientAdminManager _adminManager = default!;
public OptionsMenu()
{
RobustXamlLoader.Load(this);
@@ -18,6 +20,7 @@ namespace Content.Client.Options.UI
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-controls"));
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-accessibility"));
Tabs.SetTabTitle(5, Loc.GetString("ui-options-tab-admin"));
// CP14-options-menu-start
Tabs.SetTabTitle(5, Loc.GetString("cp14-ui-options-tab-main"));
@@ -28,10 +31,14 @@ namespace Content.Client.Options.UI
public void UpdateTabs()
{
var isAdmin = _adminManager.IsAdmin(true);
Tabs.SetTabVisible(5, isAdmin);
GraphicsTab.Control.ReloadValues();
MiscTab.Control.ReloadValues();
AccessibilityTab.Control.ReloadValues();
AudioTab.Control.ReloadValues();
AdminOptionsTab.Control.ReloadValues();
}
}
}

View File

@@ -7,8 +7,11 @@
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
<ui:OptionSlider Name="ChatWindowOpacitySlider" Title="{Loc 'ui-options-chat-window-opacity'}" />
<ui:OptionSlider Name="ScreenShakeIntensitySlider" Title="{Loc 'ui-options-screen-shake-intensity'}" />
<ui:OptionSlider Name="ChatWindowOpacitySlider" Title="{Loc 'ui-options-chat-window-opacity'}" />
<ui:OptionSlider Name="SpeechBubbleTextOpacitySlider" Title="{Loc 'ui-options-speech-bubble-text-opacity'}" />
<ui:OptionSlider Name="SpeechBubbleSpeakerOpacitySlider" Title="{Loc 'ui-options-speech-bubble-speaker-opacity'}" />
<ui:OptionSlider Name="SpeechBubbleBackgroundOpacitySlider" Title="{Loc 'ui-options-speech-bubble-background-opacity'}" />
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />

View File

@@ -15,8 +15,11 @@ public sealed partial class AccessibilityTab : Control
Control.AddOptionCheckBox(CCVars.ChatEnableColorName, EnableColorNameCheckBox);
Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox);
Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox);
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider);
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleTextOpacity, SpeechBubbleTextOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleSpeakerOpacity, SpeechBubbleSpeakerOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleBackgroundOpacity, SpeechBubbleBackgroundOpacitySlider);
Control.Initialize();
}

View File

@@ -0,0 +1,12 @@
<Control xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:Content.Client.Options.UI">
<BoxContainer Orientation="Vertical">
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
<BoxContainer Orientation="Vertical" Margin="8">
<CheckBox Name="EnableClassicOverlayCheckBox" Text="{Loc 'ui-options-enable-classic-overlay'}" />
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,20 @@
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class AdminOptionsTab : Control
{
public AdminOptionsTab()
{
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CCVars.AdminOverlayClassic, EnableClassicOverlayCheckBox);
Control.Initialize();
}
}

View File

@@ -67,8 +67,11 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
// allows a t-ray to show wires/pipes above carpets/puddles
if (scannerRevealed)
{
component.OriginalDrawDepth ??= args.Sprite.DrawDepth;
args.Sprite.DrawDepth = (int) Shared.DrawDepth.DrawDepth.FloorObjects + 1;
if (component.OriginalDrawDepth is not null)
return;
component.OriginalDrawDepth = args.Sprite.DrawDepth;
var drawDepthDifference = Shared.DrawDepth.DrawDepth.ThickPipe - Shared.DrawDepth.DrawDepth.Puddles;
args.Sprite.DrawDepth -= drawDepthDifference - 1;
}
else if (component.OriginalDrawDepth.HasValue)
{

View File

@@ -0,0 +1,29 @@
using System.Linq;
using Content.Shared.SubFloor;
using Robust.Shared.Map.Components;
namespace Content.Client.SubFloor;
public sealed class TrayScanRevealSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public bool IsUnderRevealingEntity(EntityUid uid)
{
var gridUid = _transform.GetGrid(uid);
if (gridUid is null)
return false;
var gridComp = Comp<MapGridComponent>(gridUid.Value);
var position = _transform.GetGridOrMapTilePosition(uid);
return HasTrayScanReveal(((EntityUid)gridUid, gridComp), position);
}
private bool HasTrayScanReveal(Entity<MapGridComponent> ent, Vector2i position)
{
var anchoredEnum = _map.GetAnchoredEntities(ent, position);
return anchoredEnum.Any(HasComp<TrayScanRevealComponent>);
}
}

View File

@@ -19,6 +19,7 @@ public sealed class TrayScannerSystem : SharedTrayScannerSystem
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TrayScanRevealSystem _trayScanReveal = default!;
private const string TRayAnimationKey = "trays";
private const double AnimationLength = 0.3;
@@ -82,7 +83,7 @@ public sealed class TrayScannerSystem : SharedTrayScannerSystem
foreach (var (uid, comp) in inRange)
{
if (comp.IsUnderCover)
if (comp.IsUnderCover || _trayScanReveal.IsUnderRevealingEntity(uid))
EnsureComp<TrayRevealedComponent>(uid);
}
}

View File

@@ -2,6 +2,7 @@ using Content.Client.Clothing;
using Content.Client.Items.Systems;
using Content.Shared.Clothing;
using Content.Shared.Hands;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Toggleable;
using Robust.Client.GameObjects;
@@ -62,7 +63,16 @@ public sealed class ToggleableLightVisualsSystem : VisualizerSystem<ToggleableLi
|| !enabled)
return;
if (!component.ClothingVisuals.TryGetValue(args.Slot, out var layers))
if (!TryComp(args.Equipee, out InventoryComponent? inventory))
return;
List<PrototypeLayerData>? layers = null;
// attempt to get species specific data
if (inventory.SpeciesId != null)
component.ClothingVisuals.TryGetValue($"{args.Slot}-{inventory.SpeciesId}", out layers);
// No species specific data. Try to default to generic data.
if (layers == null && !component.ClothingVisuals.TryGetValue(args.Slot, out layers))
return;
var modulate = AppearanceSystem.TryGetData<Color>(uid, ToggleableLightVisuals.Color, out var color, appearance);

View File

@@ -74,7 +74,7 @@ public sealed class CloseRecentWindowUIController : UIController
/// internal recentlyInteractedWindows tracking.
/// </summary>
/// <param name="window"></param>
private void SetMostRecentlyInteractedWindow(BaseWindow window)
public void SetMostRecentlyInteractedWindow(BaseWindow window)
{
// Search through the list and see if already added.
// (This search is backwards since it's fairly common that the user is clicking the same
@@ -134,7 +134,6 @@ public sealed class CloseRecentWindowUIController : UIController
if (window.IsOpen)
return true;
recentlyInteractedWindows.RemoveAt(i);
// continue going down the list, hoping to find a still-open window
}

View File

@@ -5,6 +5,7 @@ using Content.Client.Interaction;
using Content.Client.Storage;
using Content.Client.Storage.Systems;
using Content.Client.UserInterface.Systems.Hotbar.Widgets;
using Content.Client.UserInterface.Systems.Info;
using Content.Client.UserInterface.Systems.Storage.Controls;
using Content.Client.Verbs.UI;
using Content.Shared.CCVar;
@@ -37,6 +38,7 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
[Dependency] private readonly IConfigurationManager _configuration = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly CloseRecentWindowUIController _closeRecentWindowUIController = default!;
[UISystemDependency] private readonly StorageSystem _storage = default!;
[UISystemDependency] private readonly UserInterfaceSystem _ui = default!;
@@ -98,6 +100,7 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
if (StaticStorageUIEnabled)
{
UIManager.GetActiveUIWidgetOrNull<HotbarGui>()?.StorageContainer.AddChild(window);
_closeRecentWindowUIController.SetMostRecentlyInteractedWindow(window);
}
else
{

View File

@@ -1,11 +1,12 @@
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 partial class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSystem
public sealed class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSystem
{
[Dependency] private readonly IPlayerManager _players = default!;
@@ -24,7 +25,7 @@ public sealed partial class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSyste
if (entity is null)
return;
RaiseNetworkEvent(new RequestKnowledgeInfoEvent(GetNetEntity(entity.Value)));
RaiseNetworkEvent(new CP14RequestKnowledgeInfoEvent(GetNetEntity(entity.Value)));
}
private void OnCharacterKnowledgeEvent(CP14KnowledgeInfoEvent msg, EntitySessionEventArgs args)
@@ -37,6 +38,6 @@ public sealed partial class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSyste
public readonly record struct KnowledgeData(
EntityUid Entity,
HashSet<ProtoId<CP14KnowledgePrototype>> AllKnowledges
HashSet<ProtoId<CP14KnowledgePrototype>> AllKnowledge
);
}

View File

@@ -1,11 +1,19 @@
<Control xmlns="https://spacestation14.io">
<Button Name="ProductButton" Access="Public">
<BoxContainer Orientation="Horizontal">
<EntityPrototypeView Name="EntityView"
MinSize="48 48"
MaxSize="48 48"
Scale="2,2"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Visible="False"/>
<TextureRect Name="View"
MinSize="48 48"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Stretch="KeepAspectCentered" />
Stretch="KeepAspectCentered"
Visible="False"/>
<BoxContainer Orientation="Vertical">
<RichTextLabel Name="SpecialLabel" Text="{Loc 'cp14-store-ui-tab-special'}" VerticalAlignment="Center" Access="Public" Visible="False" />
<RichTextLabel Name="ProductName" VerticalAlignment="Center" Access="Public" />

View File

@@ -3,7 +3,6 @@ using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client._CP14.TravelingStoreShip;
@@ -26,10 +25,16 @@ public sealed partial class CP14StoreProductControl : Control
ProductName.Text = $"[bold]{entry.Name}[/bold]";
SpecialLabel.Visible = entry.Special;
View.Texture = _sprite.Frame0(entry.Icon);
}
private void UpdateView(SpriteSpecifier spriteSpecifier)
{
if (entry.Icon is not null)
{
View.Visible = true;
View.Texture = _sprite.Frame0(entry.Icon);
}
else if (entry.EntityView is not null)
{
EntityView.Visible = true;
EntityView.SetPrototype(entry.EntityView);
}
}
}

View File

@@ -1,6 +1,7 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'cp14-store-ui-title'}"
Name="Window"
Title=""
MinSize="800 600"
SetSize="800 600">
<BoxContainer Orientation="Horizontal">

View File

@@ -11,9 +11,6 @@ public sealed partial class CP14StoreWindow : DefaultWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
private TimeSpan? _nextTravelTime;
private bool _onStation;
public CP14StoreWindow()
{
RobustXamlLoader.Load(this);
@@ -25,24 +22,8 @@ public sealed partial class CP14StoreWindow : DefaultWindow
public void UpdateUI(CP14StoreUiState state)
{
Window.Title = Loc.GetString("cp14-store-ui-title", ("name", state.ShopName));
UpdateProducts(state);
_nextTravelTime = state.NextTravelTime;
_onStation = state.OnStation;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
//Updating time
if (_nextTravelTime is not null)
{
var time = _nextTravelTime.Value - _timing.CurTime;
TravelTimeLabel.Text =
$"{Loc.GetString(_onStation ? "cp14-store-ui-next-travel-out" : "cp14-store-ui-next-travel-in")} {Math.Max(time.Minutes, 0):00}:{Math.Max(time.Seconds, 0):00}";
}
}
private void UpdateProducts(CP14StoreUiState state)

View File

@@ -0,0 +1,31 @@
using Content.Shared._CP14.Vampire;
using Content.Shared.Humanoid;
using Robust.Client.GameObjects;
namespace Content.Client._CP14.Vampire;
public sealed class CP14ClientVampireVisualsSystem : CP14SharedVampireVisualsSystem
{
protected override void OnVampireVisualsInit(Entity<CP14VampireVisualsComponent> vampire, ref ComponentInit args)
{
base.OnVampireVisualsInit(vampire, ref args);
if (!EntityManager.TryGetComponent(vampire, out SpriteComponent? sprite))
return;
if (sprite.LayerMapTryGet(vampire.Comp.FangsMap, out var fangsLayerIndex))
sprite.LayerSetVisible(fangsLayerIndex, true);
}
protected override void OnVampireVisualsShutdown(Entity<CP14VampireVisualsComponent> vampire, ref ComponentShutdown args)
{
base.OnVampireVisualsShutdown(vampire, ref args);
if (!EntityManager.TryGetComponent(vampire, out SpriteComponent? sprite))
return;
if (sprite.LayerMapTryGet(vampire.Comp.FangsMap, out var fangsLayerIndex))
sprite.LayerSetVisible(fangsLayerIndex, false);
}
}

View File

@@ -6,10 +6,8 @@ using Content.Server.Cargo.Systems;
using Content.Server.Nutrition.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.IdentityManagement;
using Content.Shared.Prototypes;
using Content.Shared.Stacks;
using Content.Shared.Tag;
using Content.Shared.Whitelist;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
@@ -67,7 +65,7 @@ public sealed class CargoTest
var testMap = await pair.CreateTestMap();
var entManager = server.ResolveDependency<IEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var protoManager = server.ResolveDependency<IPrototypeManager>();
var cargo = entManager.System<CargoSystem>();
@@ -93,7 +91,7 @@ public sealed class CargoTest
}
});
mapManager.DeleteMap(mapId);
mapSystem.DeleteMap(mapId);
});
await pair.CleanReturnAsync();
@@ -151,6 +149,7 @@ public sealed class CargoTest
var testMap = await pair.CreateTestMap();
var entManager = server.ResolveDependency<IEntityManager>();
var mapSystem = server.System<SharedMapSystem>();
var mapManager = server.ResolveDependency<IMapManager>();
var protoManager = server.ResolveDependency<IPrototypeManager>();
var componentFactory = server.ResolveDependency<IComponentFactory>();
@@ -207,7 +206,7 @@ public sealed class CargoTest
entManager.DeleteEntity(ent);
}
mapManager.DeleteMap(mapId);
mapSystem.DeleteMap(mapId);
});
await pair.CleanReturnAsync();

View File

@@ -59,6 +59,32 @@ namespace Content.IntegrationTests.Tests.Chemistry
#pragma warning restore NUnit2045
}
//------------CP14 - improve test for alchemy
//Get all possible reactions with the current reagents
var possibleReactions = prototypeManager.EnumeratePrototypes<ReactionPrototype>()
.Where(x => x.Reactants.All(id => solution.Contents.Any(s => s.Reagent.Prototype == id.Key)))
.ToList();
//Check if the reaction is the first to occur when heated
foreach (var possibleReaction in possibleReactions.OrderBy(r => r.MinimumTemperature))
{
if (possibleReaction.MinimumTemperature < reactionPrototype.MinimumTemperature && possibleReaction.MixingCategories == reactionPrototype.MixingCategories)
{
Assert.Fail($"The {possibleReaction.ID} reaction may occur before {reactionPrototype.ID} when heated.");
}
}
//Check if the reaction is the first to occur when freezing
foreach (var possibleReaction in possibleReactions.OrderBy(r => r.MaximumTemperature))
{
if (possibleReaction.MaximumTemperature > reactionPrototype.MaximumTemperature && possibleReaction.MixingCategories == reactionPrototype.MixingCategories)
{
Assert.Fail($"The {possibleReaction.ID} reaction may occur before {reactionPrototype.ID} when freezing.");
}
}
//Now safe set the temperature and mix the reagents
//----------CP14 - improve test for alchemy end
solutionContainerSystem.SetTemperature(solutionEnt.Value, reactionPrototype.MinimumTemperature);
if (reactionPrototype.MixingCategories != null)

View File

@@ -6,7 +6,6 @@ using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests.Hands;
@@ -38,7 +37,7 @@ public sealed class HandTests
var entMan = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mapMan = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var sys = entMan.System<SharedHandsSystem>();
var tSys = entMan.System<TransformSystem>();
@@ -69,7 +68,7 @@ public sealed class HandTests
await pair.RunTicksSync(5);
Assert.That(hands.ActiveHandEntity, Is.Null);
await server.WaitPost(() => mapMan.DeleteMap(data.MapId));
await server.WaitPost(() => mapSystem.DeleteMap(data.MapId));
await pair.CleanReturnAsync();
}
@@ -87,7 +86,7 @@ public sealed class HandTests
var entMan = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mapMan = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var sys = entMan.System<SharedHandsSystem>();
var tSys = entMan.System<TransformSystem>();
var containerSystem = server.System<SharedContainerSystem>();
@@ -134,7 +133,7 @@ public sealed class HandTests
Assert.That(hands.ActiveHandEntity, Is.Not.EqualTo(item));
Assert.That(containerSystem.IsInSameOrNoContainer((player, xform), (item, itemXform)));
await server.WaitPost(() => mapMan.DeleteMap(map.MapId));
await server.WaitPost(() => mapSystem.DeleteMap(map.MapId));
await pair.CleanReturnAsync();
}
}

View File

@@ -1,6 +1,5 @@
using Content.Shared.Inventory;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests
{
@@ -67,7 +66,7 @@ namespace Content.IntegrationTests.Tests
EntityUid pocketItem = default;
InventorySystem invSystem = default!;
var mapMan = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var entityMan = server.ResolveDependency<IEntityManager>();
await server.WaitAssertion(() =>
@@ -129,7 +128,7 @@ namespace Content.IntegrationTests.Tests
Assert.That(!invSystem.TryGetSlotEntity(human, "pocket1", out _));
});
mapMan.DeleteMap(testMap.MapId);
mapSystem.DeleteMap(testMap.MapId);
});
await pair.CleanReturnAsync();

View File

@@ -260,7 +260,7 @@ public abstract partial class InteractionTest
[TearDown]
public async Task TearDownInternal()
{
await Server.WaitPost(() => MapMan.DeleteMap(MapId));
await Server.WaitPost(() => MapSystem.DeleteMap(MapId));
await Pair.CleanReturnAsync();
await TearDown();
}

View File

@@ -346,7 +346,7 @@ public sealed class MaterialArbitrageTest
}
});
await server.WaitPost(() => mapManager.DeleteMap(testMap.MapId));
await server.WaitPost(() => mapSystem.DeleteMap(testMap.MapId));
await pair.CleanReturnAsync();
async Task<double> GetSpawnedPrice(Dictionary<string, int> ents)

View File

@@ -3,7 +3,6 @@ using Content.Server.Stack;
using Content.Shared.Stacks;
using Content.Shared.Materials;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.Materials
@@ -24,7 +23,7 @@ namespace Content.IntegrationTests.Tests.Materials
var server = pair.Server;
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
var entityManager = server.ResolveDependency<IEntityManager>();
@@ -59,7 +58,7 @@ namespace Content.IntegrationTests.Tests.Materials
}
});
mapManager.DeleteMap(testMap.MapId);
mapSystem.DeleteMap(testMap.MapId);
});
await pair.CleanReturnAsync();

View File

@@ -81,7 +81,7 @@ public sealed partial class MindTests
var testMap2 = await pair.CreateTestMap();
var entMan = server.ResolveDependency<IServerEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var player = playerMan.Sessions.Single();
@@ -101,7 +101,7 @@ public sealed partial class MindTests
});
await pair.RunTicksSync(5);
await server.WaitAssertion(() => mapManager.DeleteMap(testMap.MapId));
await server.WaitAssertion(() => mapSystem.DeleteMap(testMap.MapId));
await pair.RunTicksSync(5);
await server.WaitAssertion(() =>

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Content.Server.Administration.Systems;
using Content.Server.GameTicking;
using Content.Server.Maps;
using Content.Server.Shuttles.Components;
@@ -42,6 +43,7 @@ namespace Content.IntegrationTests.Tests
//CrystallEdge Map replacement
//CrystallEdge Map replacement end
AdminTestArenaSystem.ArenaMapPath
};
private static readonly string[] DoNotMapWhitelist =

View File

@@ -2,7 +2,6 @@ using System.Linq;
using Content.Shared.Roles;
using Content.Server.Storage.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Collections;
namespace Content.IntegrationTests.Tests.Roles;
@@ -19,7 +18,7 @@ public sealed class StartingGearPrototypeStorageTest
var settings = new PoolSettings { Connected = true, Dirty = true };
await using var pair = await PoolManager.GetServerClient(settings);
var server = pair.Server;
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var storageSystem = server.System<StorageSystem>();
var protos = server.ProtoMan
@@ -64,7 +63,7 @@ public sealed class StartingGearPrototypeStorageTest
}
}
mapManager.DeleteMap(testMap.MapId);
mapSystem.DeleteMap(testMap.MapId);
});
await pair.CleanReturnAsync();

View File

@@ -55,5 +55,16 @@ namespace Content.Server.Abilities.Mime
[DataField]
public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken";
/// <summary>
/// Does this component prevent the mime from writing on paper while their vow is active?
/// </summary>
[DataField]
public bool PreventWriting = false;
/// <summary>
/// What message is displayed when the mime fails to write?
/// </summary>
[DataField]
public LocId FailWriteMessage = "paper-component-illiterate-mime";
}
}

View File

@@ -5,6 +5,7 @@ using Content.Shared.Actions.Events;
using Content.Shared.Alert;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Maps;
using Content.Shared.Paper;
using Content.Shared.Physics;
using Robust.Shared.Containers;
using Robust.Shared.Map;
@@ -55,6 +56,13 @@ namespace Content.Server.Abilities.Mime
private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args)
{
EnsureComp<MutedComponent>(uid);
if (component.PreventWriting)
{
EnsureComp<BlockWritingComponent>(uid, out var illiterateComponent);
illiterateComponent.FailWriteMessage = component.FailWriteMessage;
Dirty(uid, illiterateComponent);
}
_alertsSystem.ShowAlert(uid, component.VowAlert);
_actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid);
}
@@ -123,6 +131,8 @@ namespace Content.Server.Abilities.Mime
mimePowers.VowBroken = true;
mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown;
RemComp<MutedComponent>(uid);
if (mimePowers.PreventWriting)
RemComp<BlockWritingComponent>(uid);
_alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
_actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity);
@@ -146,6 +156,13 @@ namespace Content.Server.Abilities.Mime
mimePowers.ReadyToRepent = false;
mimePowers.VowBroken = false;
AddComp<MutedComponent>(uid);
if (mimePowers.PreventWriting)
{
EnsureComp<BlockWritingComponent>(uid, out var illiterateComponent);
illiterateComponent.FailWriteMessage = mimePowers.FailWriteMessage;
Dirty(uid, illiterateComponent);
}
_alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowAlert);
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);

View File

@@ -74,5 +74,15 @@ namespace Content.Server.Administration.Commands
mindSystem.TransferTo(mind, eUid, ghostOverride);
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
if (args.Length == 2)
{
return CompletionResult.FromHintOptions(CompletionHelper.SessionNames(), Loc.GetString("cmd-mind-command-hint"));
}
return CompletionResult.Empty;
}
}
}

View File

@@ -12,6 +12,7 @@ public sealed class AdminTestArenaSystem : EntitySystem
{
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly MetaDataSystem _metaDataSystem = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
public const string ArenaMapPath = "/Maps/Test/admin_test_arena.yml";
@@ -33,17 +34,20 @@ public sealed class AdminTestArenaSystem : EntitySystem
}
var path = new ResPath(ArenaMapPath);
if (!_loader.TryLoadMap(path, out var map, out var grids))
var mapUid = _maps.CreateMap(out var mapId);
if (!_loader.TryLoadGrid(mapId, path, out var grid))
{
QueueDel(mapUid);
throw new Exception($"Failed to load admin arena");
}
ArenaMap[admin.UserId] = map.Value.Owner;
_metaDataSystem.SetEntityName(map.Value.Owner, $"ATAM-{admin.Name}");
ArenaMap[admin.UserId] = mapUid;
_metaDataSystem.SetEntityName(mapUid, $"ATAM-{admin.Name}");
var grid = grids.FirstOrNull();
ArenaGrid[admin.UserId] = grid?.Owner;
if (grid != null)
_metaDataSystem.SetEntityName(grid.Value.Owner, $"ATAG-{admin.Name}");
ArenaGrid[admin.UserId] = grid.Value.Owner;
_metaDataSystem.SetEntityName(grid.Value.Owner, $"ATAG-{admin.Name}");
return (map.Value.Owner, grid?.Owner);
return (mapUid, grid.Value.Owner);
}
}

View File

@@ -1,3 +1,4 @@
using Content.Server._CP14.GameTicking.Rules.Components;
using Content.Server.Administration.Commands;
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
@@ -36,6 +37,11 @@ public sealed partial class AdminVerbSystem
[ValidatePrototypeId<StartingGearPrototype>]
private const string PirateGearId = "PirateGear";
//CP14
[ValidatePrototypeId<EntityPrototype>]
private const string CP14VampireRule = "CP14Vampire";
//CP14 end
// All antag verbs have names so invokeverb works.
private void AddAntagVerbs(GetVerbsEvent<Verb> args)
{
@@ -52,6 +58,21 @@ public sealed partial class AdminVerbSystem
var targetPlayer = targetActor.PlayerSession;
Verb vampire = new()
{
Text = Loc.GetString("cp14-admin-verb-text-make-vampire"),
Category = VerbCategory.Antag,
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Actions/Spells/vampire.rsi"),
"bite"),
Act = () =>
{
_antag.ForceMakeAntag<CP14VampireRuleComponent>(targetPlayer, CP14VampireRule);
},
Impact = LogImpact.High,
Message = Loc.GetString("cp14-admin-verb-make-vampire"),
};
args.Verbs.Add(vampire);
/* CP14 disable default antags
Verb traitor = new()
{

View File

@@ -759,6 +759,7 @@ namespace Content.Server.Administration.Systems
_gameTicker.RoundDuration().ToString("hh\\:mm\\:ss"),
_gameTicker.RunLevel,
playedSound: playSound,
adminOnly: message.AdminOnly,
noReceivers: nonAfkAdmins.Count == 0
);
_messageQueues[msg.UserId].Enqueue(GenerateAHelpMessage(messageParams));
@@ -790,7 +791,7 @@ namespace Content.Server.Administration.Systems
.ToList();
}
private static DiscordRelayedData GenerateAHelpMessage(AHelpMessageParams parameters)
private DiscordRelayedData GenerateAHelpMessage(AHelpMessageParams parameters)
{
var stringbuilder = new StringBuilder();
@@ -806,7 +807,7 @@ namespace Content.Server.Administration.Systems
if (parameters.RoundTime != string.Empty && parameters.RoundState == GameRunLevel.InRound)
stringbuilder.Append($" **{parameters.RoundTime}**");
if (!parameters.PlayedSound)
stringbuilder.Append(" **(S)**");
stringbuilder.Append($" **{(parameters.AdminOnly ? Loc.GetString("bwoink-message-admin-only") : Loc.GetString("bwoink-message-silent"))}**");
if (parameters.Icon == null)
stringbuilder.Append($" **{parameters.Username}:** ");
else
@@ -869,6 +870,7 @@ namespace Content.Server.Administration.Systems
public string RoundTime { get; set; }
public GameRunLevel RoundState { get; set; }
public bool PlayedSound { get; set; }
public readonly bool AdminOnly;
public bool NoReceivers { get; set; }
public string? Icon { get; set; }
@@ -879,6 +881,7 @@ namespace Content.Server.Administration.Systems
string roundTime,
GameRunLevel roundState,
bool playedSound,
bool adminOnly = false,
bool noReceivers = false,
string? icon = null)
{
@@ -888,6 +891,7 @@ namespace Content.Server.Administration.Systems
RoundTime = roundTime;
RoundState = roundState;
PlayedSound = playedSound;
AdminOnly = adminOnly;
NoReceivers = noReceivers;
Icon = icon;
}

View File

@@ -6,7 +6,7 @@ namespace Content.Server.AlertLevel;
[Prototype("alertLevels")]
public sealed partial class AlertLevelPrototype : IPrototype
{
[IdDataField] public string ID { get; } = default!;
[IdDataField] public string ID { get; private set; } = default!;
/// <summary>
/// Dictionary of alert levels. Keyed by string - the string key is the most important

View File

@@ -28,7 +28,7 @@ public sealed partial class AntagRandomObjectivesComponent : Component
/// Difficulty is checked over all sets, but each set has its own probability and pick count.
/// </summary>
[DataRecord]
public record struct AntagObjectiveSet()
public partial record struct AntagObjectiveSet()
{
/// <summary>
/// The grouping used by the objective system to pick random objectives.

View File

@@ -84,7 +84,7 @@ namespace Content.Server.Bible
}
summonableComp.AlreadySummoned = false;
_popupSystem.PopupEntity(Loc.GetString("bible-summon-respawn-ready", ("book", uid)), uid, PopupType.Medium);
_audio.PlayPvs("/Audio/Effects/radpulse9.ogg", uid, AudioParams.Default.WithVolume(-4f));
_audio.PlayPvs(summonableComp.SummonSound, uid);
// Clean up the accumulator and respawn tracking component
summonableComp.Accumulator = 0;
_remQueue.Enqueue(uid);
@@ -126,7 +126,7 @@ namespace Content.Server.Bible
var selfFailMessage = Loc.GetString(component.LocPrefix + "-heal-fail-self", ("target", Identity.Entity(args.Target.Value, EntityManager)), ("bible", uid));
_popupSystem.PopupEntity(selfFailMessage, args.User, args.User, PopupType.MediumCaution);
_audio.PlayPvs("/Audio/Effects/hit_kick.ogg", args.User);
_audio.PlayPvs(component.BibleHitSound, args.User);
_damageableSystem.TryChangeDamage(args.Target.Value, component.DamageOnFail, true, origin: uid);
_delay.TryResetDelay((uid, useDelay));
return;

View File

@@ -1,11 +1,23 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.Bible.Components
{
[RegisterComponent]
public sealed partial class BibleComponent : Component
{
/// <summary>
/// Default sound when bible hits somebody.
/// </summary>
private static readonly ProtoId<SoundCollectionPrototype> DefaultBibleHit = new("BibleHit");
/// <summary>
/// Sound to play when bible hits somebody.
/// </summary>
[DataField]
public SoundSpecifier BibleHitSound = new SoundCollectionSpecifier(DefaultBibleHit, AudioParams.Default.WithVolume(-4f));
/// <summary>
/// Damage that will be healed on a success
/// </summary>

View File

@@ -1,3 +1,4 @@
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -9,6 +10,17 @@ namespace Content.Server.Bible.Components
[RegisterComponent]
public sealed partial class SummonableComponent : Component
{
/// <summary>
/// Default sound to play when entity is summoned.
/// </summary>
private static readonly ProtoId<SoundCollectionPrototype> DefaultSummonSound = new("Summon");
/// <summary>
/// Sound to play when entity is summoned.
/// </summary>
[DataField]
public SoundSpecifier SummonSound = new SoundCollectionSpecifier(DefaultSummonSound, AudioParams.Default.WithVolume(-4f));
/// <summary>
/// Used for a special item only the Chaplain can summon. Usually a mob, but supports regular items too.
/// </summary>

View File

@@ -14,7 +14,7 @@ namespace Content.Server.Botany;
[Prototype("seed")]
public sealed partial class SeedPrototype : SeedData, IPrototype
{
[IdDataField] public string ID { get; private init; } = default!;
[IdDataField] public string ID { get; private set; } = default!;
}
public enum HarvestType : byte

View File

@@ -427,6 +427,7 @@ public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem
private void OnUiMessage(EntityUid uid, CartridgeLoaderComponent component, CartridgeUiMessage args)
{
var cartridgeEvent = args.MessageEvent;
cartridgeEvent.User = args.Actor;
cartridgeEvent.LoaderUid = GetNetEntity(uid);
cartridgeEvent.Actor = args.Actor;

View File

@@ -1,12 +1,21 @@
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.Paper;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.CartridgeLoader.Cartridges;
[RegisterComponent]
[Access(typeof(LogProbeCartridgeSystem))]
[RegisterComponent, Access(typeof(LogProbeCartridgeSystem))]
[AutoGenerateComponentPause]
public sealed partial class LogProbeCartridgeComponent : Component
{
/// <summary>
/// The name of the scanned entity, sent to clients when they open the UI.
/// </summary>
[DataField]
public string EntityName = string.Empty;
/// <summary>
/// The list of pulled access logs
/// </summary>
@@ -18,4 +27,25 @@ public sealed partial class LogProbeCartridgeComponent : Component
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier SoundScan = new SoundPathSpecifier("/Audio/Machines/scan_finish.ogg");
/// <summary>
/// Paper to spawn when printing logs.
/// </summary>
[DataField]
public EntProtoId<PaperComponent> PaperPrototype = "PaperAccessLogs";
[DataField]
public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/diagnoser_printing.ogg");
/// <summary>
/// How long you have to wait before printing logs again.
/// </summary>
[DataField]
public TimeSpan PrintCooldown = TimeSpan.FromSeconds(5);
/// <summary>
/// When anyone is allowed to spawn another printout.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan NextPrintAllowed = TimeSpan.Zero;
}

View File

@@ -1,25 +1,40 @@
using Content.Shared.Access.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Audio;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.Database;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Labels.EntitySystems;
using Content.Shared.Paper;
using Content.Shared.Popups;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using System.Text;
namespace Content.Server.CartridgeLoader.Cartridges;
public sealed class LogProbeCartridgeSystem : EntitySystem
{
[Dependency] private readonly CartridgeLoaderSystem _cartridge = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly CartridgeLoaderSystem? _cartridgeLoaderSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly SharedLabelSystem _label = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly PaperSystem _paper = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LogProbeCartridgeComponent, CartridgeUiReadyEvent>(OnUiReady);
SubscribeLocalEvent<LogProbeCartridgeComponent, CartridgeAfterInteractEvent>(AfterInteract);
SubscribeLocalEvent<LogProbeCartridgeComponent, CartridgeMessageEvent>(OnMessage);
}
/// <summary>
@@ -37,9 +52,10 @@ public sealed class LogProbeCartridgeSystem : EntitySystem
return;
//Play scanning sound with slightly randomized pitch
_audioSystem.PlayEntity(ent.Comp.SoundScan, args.InteractEvent.User, target, AudioHelpers.WithVariation(0.25f, _random));
_popupSystem.PopupCursor(Loc.GetString("log-probe-scan", ("device", target)), args.InteractEvent.User);
_audio.PlayEntity(ent.Comp.SoundScan, args.InteractEvent.User, target, AudioHelpers.WithVariation(0.25f, _random));
_popup.PopupCursor(Loc.GetString("log-probe-scan", ("device", target)), args.InteractEvent.User);
ent.Comp.EntityName = Name(target);
ent.Comp.PulledAccessLogs.Clear();
foreach (var accessRecord in accessReaderComponent.AccessLog)
@@ -52,6 +68,9 @@ public sealed class LogProbeCartridgeSystem : EntitySystem
ent.Comp.PulledAccessLogs.Add(log);
}
// Reverse the list so the oldest is at the bottom
ent.Comp.PulledAccessLogs.Reverse();
UpdateUiState(ent, args.Loader);
}
@@ -63,9 +82,49 @@ public sealed class LogProbeCartridgeSystem : EntitySystem
UpdateUiState(ent, args.Loader);
}
private void OnMessage(Entity<LogProbeCartridgeComponent> ent, ref CartridgeMessageEvent args)
{
if (args is LogProbePrintMessage cast)
PrintLogs(ent, cast.User);
}
private void PrintLogs(Entity<LogProbeCartridgeComponent> ent, EntityUid user)
{
if (string.IsNullOrEmpty(ent.Comp.EntityName))
return;
if (_timing.CurTime < ent.Comp.NextPrintAllowed)
return;
ent.Comp.NextPrintAllowed = _timing.CurTime + ent.Comp.PrintCooldown;
var paper = Spawn(ent.Comp.PaperPrototype, _transform.GetMapCoordinates(user));
_label.Label(paper, ent.Comp.EntityName); // label it for easy identification
_audio.PlayEntity(ent.Comp.PrintSound, user, paper);
_hands.PickupOrDrop(user, paper, checkActionBlocker: false);
// generate the actual printout text
var builder = new StringBuilder();
builder.AppendLine(Loc.GetString("log-probe-printout-device", ("name", ent.Comp.EntityName)));
builder.AppendLine(Loc.GetString("log-probe-printout-header"));
var number = 1;
foreach (var log in ent.Comp.PulledAccessLogs)
{
var time = TimeSpan.FromSeconds(Math.Truncate(log.Time.TotalSeconds)).ToString();
builder.AppendLine(Loc.GetString("log-probe-printout-entry", ("number", number), ("time", time), ("accessor", log.Accessor)));
number++;
}
var paperComp = Comp<PaperComponent>(paper);
_paper.SetContent((paper, paperComp), builder.ToString());
_adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(user):user} printed out LogProbe logs ({paper}) of {ent.Comp.EntityName}");
}
private void UpdateUiState(Entity<LogProbeCartridgeComponent> ent, EntityUid loaderUid)
{
var state = new LogProbeUiState(ent.Comp.PulledAccessLogs);
_cartridgeLoaderSystem?.UpdateCartridgeUiState(loaderUid, state);
var state = new LogProbeUiState(ent.Comp.EntityName, ent.Comp.PulledAccessLogs);
_cartridge.UpdateCartridgeUiState(loaderUid, state);
}
}

View File

@@ -18,6 +18,9 @@ namespace Content.Server.Chemistry.Components
[DataField("mode"), ViewVariables(VVAccess.ReadWrite)]
public ChemMasterMode Mode = ChemMasterMode.Transfer;
[DataField]
public ChemMasterSortingType SortingType = ChemMasterSortingType.None;
[DataField("pillDosageLimit", required: true), ViewVariables(VVAccess.ReadWrite)]
public uint PillDosageLimit;

View File

@@ -53,6 +53,7 @@ namespace Content.Server.Chemistry.EntitySystems
SubscribeLocalEvent<ChemMasterComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetModeMessage>(OnSetModeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSortingTypeCycleMessage>(OnCycleSortingTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetPillTypeMessage>(OnSetPillTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterReagentAmountButtonMessage>(OnReagentButtonMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterCreatePillsMessage>(OnCreatePillsMessage);
@@ -76,7 +77,7 @@ namespace Content.Server.Chemistry.EntitySystems
var bufferCurrentVolume = bufferSolution.Volume;
var state = new ChemMasterBoundUserInterfaceState(
chemMaster.Mode, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer),
chemMaster.Mode, chemMaster.SortingType, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer),
bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel);
_userInterfaceSystem.SetUiState(owner, ChemMasterUiKey.Key, state);
@@ -93,6 +94,15 @@ namespace Content.Server.Chemistry.EntitySystems
ClickSound(chemMaster);
}
private void OnCycleSortingTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSortingTypeCycleMessage message)
{
chemMaster.Comp.SortingType++;
if (chemMaster.Comp.SortingType > ChemMasterSortingType.Latest)
chemMaster.Comp.SortingType = ChemMasterSortingType.None;
UpdateUiState(chemMaster);
ClickSound(chemMaster);
}
private void OnSetPillTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSetPillTypeMessage message)
{
// Ensure valid pill type. There are 20 pills selectable, 0-19.

View File

@@ -18,25 +18,25 @@ namespace Content.Server.Connection.Whitelist;
/// If the condition doesn't match, the next condition is checked.
/// </summary>
[Prototype("playerConnectionWhitelist")]
public sealed class PlayerConnectionWhitelistPrototype : IPrototype
public sealed partial class PlayerConnectionWhitelistPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = default!;
public string ID { get; private set; } = default!;
/// <summary>
/// Minimum number of players required for this whitelist to be active.
/// If there are less players than this, the whitelist will be ignored and the next one in the list will be used.
/// </summary>
[DataField]
public int MinimumPlayers { get; } = 0;
public int MinimumPlayers = 0;
/// <summary>
/// Maximum number of players allowed for this whitelist to be active.
/// If there are more players than this, the whitelist will be ignored and the next one in the list will be used.
/// </summary>
[DataField]
public int MaximumPlayers { get; } = int.MaxValue;
public int MaximumPlayers = int.MaxValue;
[DataField]
public WhitelistCondition[] Conditions { get; } = default!;
public WhitelistCondition[] Conditions = default!;
}

View File

@@ -30,6 +30,12 @@ public sealed class ThrowInsertContainerSystem : EntitySystem
if (!_containerSystem.CanInsert(args.Thrown, container))
return;
var beforeThrowArgs = new BeforeThrowInsertEvent(args.Thrown);
RaiseLocalEvent(ent, ref beforeThrowArgs);
if (beforeThrowArgs.Cancelled)
return;
if (_random.Prob(ent.Comp.Probability))
{
_audio.PlayPvs(ent.Comp.MissSound, ent);
@@ -46,3 +52,10 @@ public sealed class ThrowInsertContainerSystem : EntitySystem
_adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.Component.Thrower.Value):player} landed in {ToPrettyString(ent)}");
}
}
/// <summary>
/// Sent before the insertion is made.
/// Allows preventing the insertion if any system on the entity should need to.
/// </summary>
[ByRefEvent]
public record struct BeforeThrowInsertEvent(EntityUid ThrownEntity, bool Cancelled = false);

View File

@@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Containers;
using Content.Server.Disposal.Tube;
using Content.Server.Disposal.Tube.Components;
using Content.Server.Disposal.Unit.Components;
@@ -85,6 +86,8 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
SubscribeLocalEvent<DisposalUnitComponent, DisposalDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<DisposalUnitComponent, BeforeThrowInsertEvent>(OnThrowInsert);
SubscribeLocalEvent<DisposalUnitComponent, SharedDisposalUnitComponent.UiButtonPressedMessage>(OnUiButtonPressed);
}
@@ -195,6 +198,12 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
args.Handled = true;
}
private void OnThrowInsert(Entity<DisposalUnitComponent> ent, ref BeforeThrowInsertEvent args)
{
if (!CanInsert(ent, ent, args.ThrownEntity))
args.Cancelled = true;
}
public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null)
{
if (!ResolveDisposals(uid, ref disposal))

View File

@@ -1,12 +0,0 @@
namespace Content.Server.Forensics
{
/// <summary>
/// This component is for mobs that leave fingerprints.
/// </summary>
[RegisterComponent]
public sealed partial class FingerprintComponent : Component
{
[DataField("fingerprint"), ViewVariables(VVAccess.ReadWrite)]
public string? Fingerprint;
}
}

View File

@@ -1,10 +0,0 @@
namespace Content.Server.Forensics
{
/// <summary>
/// This component stops the entity from leaving finger prints,
/// usually so fibres can be left instead.
/// </summary>
[RegisterComponent]
public sealed partial class FingerprintMaskComponent : Component
{}
}

View File

@@ -3,6 +3,7 @@ using Content.Server.Popups;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Forensics;
using Content.Shared.Forensics.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Inventory;

View File

@@ -63,9 +63,10 @@ namespace Content.Server.Forensics
ApplyEvidence(uid, args.Other);
}
private void OnFingerprintInit(EntityUid uid, FingerprintComponent component, MapInitEvent args)
private void OnFingerprintInit(Entity<FingerprintComponent> ent, ref MapInitEvent args)
{
component.Fingerprint = GenerateFingerprint();
ent.Comp.Fingerprint = GenerateFingerprint();
Dirty(ent);
}
private void OnDNAInit(EntityUid uid, DnaComponent component, MapInitEvent args)

View File

@@ -1,4 +1,4 @@
using Content.Server.Antag;
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.Roles;

View File

@@ -6,7 +6,7 @@ namespace Content.Server.Ghost.Roles.Raffles;
/// Allows getting a <see cref="IGhostRoleRaffleDecider"/> as prototype.
/// </summary>
[Prototype("ghostRoleRaffleDecider")]
public sealed class GhostRoleRaffleDeciderPrototype : IPrototype
public sealed partial class GhostRoleRaffleDeciderPrototype : IPrototype
{
/// <inheritdoc />
[IdDataField]

View File

@@ -269,6 +269,7 @@ namespace Content.Server.Guardian
component.Host,
args.DamageDelta * component.DamageShare,
origin: args.Origin,
ignoreResistances: true,
interruptsDoAfters: false);
_popupSystem.PopupEntity(Loc.GetString("guardian-entity-taking-damage"), component.Host.Value, component.Host.Value);

View File

@@ -68,8 +68,6 @@ public sealed partial class ImplanterSystem : SharedImplanterSystem
args.Handled = true;
}
/// <summary>
/// Attempt to implant someone else.
/// </summary>

View File

@@ -1,5 +1,3 @@
using Content.Shared.Kitchen;
namespace Content.Server.Kitchen.Components;
/// <summary>
@@ -8,4 +6,9 @@ namespace Content.Server.Kitchen.Components;
[RegisterComponent]
public sealed partial class ActivelyMicrowavedComponent : Component
{
/// <summary>
/// The microwave this entity is actively being microwaved by.
/// </summary>
[DataField]
public EntityUid? Microwave;
}

View File

@@ -14,6 +14,7 @@ using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Database;
using Content.Shared.Destructible;
@@ -101,6 +102,7 @@ namespace Content.Server.Kitchen.EntitySystems
SubscribeLocalEvent<ActiveMicrowaveComponent, EntRemovedFromContainerMessage>(OnActiveMicrowaveRemove);
SubscribeLocalEvent<ActivelyMicrowavedComponent, OnConstructionTemperatureEvent>(OnConstructionTemp);
SubscribeLocalEvent<ActivelyMicrowavedComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
SubscribeLocalEvent<FoodRecipeProviderComponent, GetSecretRecipesEvent>(OnGetSecretRecipes);
}
@@ -126,7 +128,8 @@ namespace Content.Server.Kitchen.EntitySystems
private void OnActiveMicrowaveInsert(Entity<ActiveMicrowaveComponent> ent, ref EntInsertedIntoContainerMessage args)
{
AddComp<ActivelyMicrowavedComponent>(args.Entity);
var microwavedComp = AddComp<ActivelyMicrowavedComponent>(args.Entity);
microwavedComp.Microwave = ent.Owner;
}
private void OnActiveMicrowaveRemove(Entity<ActiveMicrowaveComponent> ent, ref EntRemovedFromContainerMessage args)
@@ -134,10 +137,33 @@ namespace Content.Server.Kitchen.EntitySystems
EntityManager.RemoveComponentDeferred<ActivelyMicrowavedComponent>(args.Entity);
}
// Stop items from transforming through constructiongraphs while being microwaved.
// They might be reserved for a microwave recipe.
private void OnConstructionTemp(Entity<ActivelyMicrowavedComponent> ent, ref OnConstructionTemperatureEvent args)
{
args.Result = HandleResult.False;
return;
}
// Stop reagents from reacting if they are currently reserved for a microwave recipe.
// For example Egg would cook into EggCooked, causing it to not being removed once we are done microwaving.
private void OnReactionAttempt(Entity<ActivelyMicrowavedComponent> ent, ref SolutionRelayEvent<ReactionAttemptEvent> args)
{
if (!TryComp<ActiveMicrowaveComponent>(ent.Comp.Microwave, out var activeMicrowaveComp))
return;
if (activeMicrowaveComp.PortionedRecipe.Item1 == null) // no recipe selected
return;
var recipeReagents = activeMicrowaveComp.PortionedRecipe.Item1.IngredientsReagents.Keys;
foreach (var reagent in recipeReagents)
{
if (args.Event.Reaction.Reactants.ContainsKey(reagent))
{
args.Event.Cancelled = true;
return;
}
}
}
/// <summary>
@@ -176,33 +202,29 @@ namespace Content.Server.Kitchen.EntitySystems
// this is spaghetti ngl
foreach (var item in component.Storage.ContainedEntities)
{
if (!TryComp<SolutionContainerManagerComponent>(item, out var solMan))
// use the same reagents as when we selected the recipe
if (!_solutionContainer.TryGetDrainableSolution(item, out var solutionEntity, out var solution))
continue;
// go over every solution
foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan)))
foreach (var (reagent, _) in recipe.IngredientsReagents)
{
var solution = soln.Comp.Solution;
foreach (var (reagent, _) in recipe.IngredientsReagents)
// removed everything
if (!totalReagentsToRemove.ContainsKey(reagent))
continue;
var quant = solution.GetTotalPrototypeQuantity(reagent);
if (quant >= totalReagentsToRemove[reagent])
{
// removed everything
if (!totalReagentsToRemove.ContainsKey(reagent))
continue;
var quant = solution.GetTotalPrototypeQuantity(reagent);
if (quant >= totalReagentsToRemove[reagent])
{
quant = totalReagentsToRemove[reagent];
totalReagentsToRemove.Remove(reagent);
}
else
{
totalReagentsToRemove[reagent] -= quant;
}
_solutionContainer.RemoveReagent(soln, reagent, quant);
quant = totalReagentsToRemove[reagent];
totalReagentsToRemove.Remove(reagent);
}
else
{
totalReagentsToRemove[reagent] -= quant;
}
_solutionContainer.RemoveReagent(solutionEntity.Value, reagent, quant);
}
}
@@ -541,7 +563,8 @@ namespace Content.Server.Kitchen.EntitySystems
continue;
}
AddComp<ActivelyMicrowavedComponent>(item);
var microwavedComp = AddComp<ActivelyMicrowavedComponent>(item);
microwavedComp.Microwave = uid;
string? solidID = null;
int amountToAdd = 1;
@@ -560,33 +583,20 @@ namespace Content.Server.Kitchen.EntitySystems
}
if (solidID is null)
{
continue;
}
if (solidsDict.ContainsKey(solidID))
{
if (!solidsDict.TryAdd(solidID, amountToAdd))
solidsDict[solidID] += amountToAdd;
}
else
{
solidsDict.Add(solidID, amountToAdd);
}
if (!TryComp<SolutionContainerManagerComponent>(item, out var solMan))
// only use reagents we have access to
// you have to break the eggs before we can use them!
if (!_solutionContainer.TryGetDrainableSolution(item, out var _, out var solution))
continue;
foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan)))
foreach (var (reagent, quantity) in solution.Contents)
{
var solution = soln.Comp.Solution;
foreach (var (reagent, quantity) in solution.Contents)
{
if (reagentDict.ContainsKey(reagent.Prototype))
reagentDict[reagent.Prototype] += quantity;
else
reagentDict.Add(reagent.Prototype, quantity);
}
if (!reagentDict.TryAdd(reagent.Prototype, quantity))
reagentDict[reagent.Prototype] += quantity;
}
}

View File

@@ -69,7 +69,7 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
if (material.StackEntity != null)
{
if (!_prototypeManager.Index<EntityPrototype>(material.StackEntity).TryGetComponent<PhysicalCompositionComponent>(out var composition))
if (!_prototypeManager.Index<EntityPrototype>(material.StackEntity).TryGetComponent<PhysicalCompositionComponent>(out var composition, EntityManager.ComponentFactory))
return;
var volumePerSheet = composition.MaterialComposition.FirstOrDefault(kvp => kvp.Key == msg.Material).Value;
@@ -169,7 +169,7 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
return new List<EntityUid>();
var entProto = _prototypeManager.Index<EntityPrototype>(materialProto.StackEntity);
if (!entProto.TryGetComponent<PhysicalCompositionComponent>(out var composition))
if (!entProto.TryGetComponent<PhysicalCompositionComponent>(out var composition, EntityManager.ComponentFactory))
return new List<EntityUid>();
var materialPerStack = composition.MaterialComposition[materialProto.ID];

View File

@@ -31,6 +31,12 @@ namespace Content.Server.Medical
[Dependency] private readonly ForensicsSystem _forensics = default!;
[Dependency] private readonly BloodstreamSystem _bloodstream = default!;
[ValidatePrototypeId<SoundCollectionPrototype>]
private const string VomitCollection = "Vomit";
private readonly SoundSpecifier _vomitSound = new SoundCollectionSpecifier(VomitCollection,
AudioParams.Default.WithVariation(0.2f).WithVolume(-4f));
/// <summary>
/// Make an entity vomit, if they have a stomach.
/// </summary>
@@ -94,7 +100,7 @@ namespace Content.Server.Medical
}
// Force sound to play as spill doesn't work if solution is empty.
_audio.PlayPvs("/Audio/Effects/Fluids/splat.ogg", uid, AudioParams.Default.WithVariation(0.2f).WithVolume(-4f));
_audio.PlayPvs(_vomitSound, uid);
_popup.PopupEntity(Loc.GetString("disease-vomit", ("person", Identity.Entity(uid, EntityManager))), uid);
}
}

View File

@@ -8,7 +8,7 @@ namespace Content.Server.NPC.HTN;
[Prototype("htnCompound")]
public sealed partial class HTNCompoundPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[IdDataField] public string ID { get; private set; } = string.Empty;
[DataField("branches", required: true)]
public List<HTNBranch> Branches = new();

View File

@@ -5,7 +5,7 @@ namespace Content.Server.NPC.Queries.Curves;
[Prototype("utilityCurvePreset")]
public sealed partial class UtilityCurvePresetPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[IdDataField] public string ID { get; private set; } = string.Empty;
[DataField("curve", required: true)] public IUtilityCurve Curve = default!;
}

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Objectives.Components;
/// <summary>
/// A free greentext, that's it.
/// </summary>
[RegisterComponent]
public sealed partial class FreeObjectiveComponent : Component;

View File

@@ -0,0 +1,20 @@
using Content.Server.Objectives.Components;
using Content.Shared.Objectives.Components;
namespace Content.Server.Objectives.Systems;
public sealed class FreeObjectiveSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FreeObjectiveComponent, ObjectiveGetProgressEvent>(OnGetProgress);
}
// You automatically greentext, there's not much else to it
private void OnGetProgress(Entity<FreeObjectiveComponent> ent, ref ObjectiveGetProgressEvent args)
{
args.Progress = 1f;
}
}

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Roles;
/// <summary>
/// Mind role to tag entities that they're a Wizard
/// </summary>
[RegisterComponent]
public sealed partial class WizardRoleComponent : Component;

View File

@@ -354,7 +354,7 @@ public sealed partial class SalvageSystem
if (!TryGetSalvagePlacementLocation(magnet, mapId, attachedBounds, bounds!.Value, worldAngle, out var spawnLocation, out var spawnAngle))
{
Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-spawn-no-debris-available");
_mapManager.DeleteMap(salvMapXform.MapID);
_mapSystem.DeleteMap(salvMapXform.MapID);
return;
}
@@ -391,7 +391,7 @@ public sealed partial class SalvageSystem
}
Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-arrived", ("timeLeft", data.Comp.ActiveTime.TotalSeconds));
_mapManager.DeleteMap(salvMapXform.MapID);
_mapSystem.DeleteMap(salvMapXform.MapID);
data.Comp.Announced = false;

View File

@@ -62,7 +62,7 @@ public interface IGridSpawnGroup
}
[DataRecord]
public sealed class DungeonSpawnGroup : IGridSpawnGroup
public sealed partial class DungeonSpawnGroup : IGridSpawnGroup
{
/// <summary>
/// Prototypes we can choose from to spawn.
@@ -97,7 +97,7 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
}
[DataRecord]
public sealed class GridSpawnGroup : IGridSpawnGroup
public sealed partial class GridSpawnGroup : IGridSpawnGroup
{
public List<ResPath> Paths = new();

View File

@@ -30,8 +30,10 @@ using Robust.Server.GameObjects;
using Robust.Shared.Collections;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.EntitySerialization;
using Robust.Shared.EntitySerialization.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
@@ -46,23 +48,23 @@ namespace Content.Server.Shuttles.Systems;
/// </summary>
public sealed class ArrivalsSystem : EntitySystem
{
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly ActorSystem _actor = default!;
[Dependency] private readonly BiomeSystem _biomes = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ShuttleSystem _shuttles = default!;
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly ActorSystem _actor = default!;
private EntityQuery<PendingClockInComponent> _pendingQuery;
private EntityQuery<ArrivalsBlacklistComponent> _blacklistQuery;
@@ -515,31 +517,31 @@ public sealed class ArrivalsSystem : EntitySystem
private void SetupArrivalsStation()
{
var path = new ResPath(_cfgManager.GetCVar(CCVars.ArrivalsMap));
if (!_loader.TryLoadMap(path, out var map, out var grids))
_mapSystem.CreateMap(out var mapId, runMapInit: false);
var mapUid = _mapSystem.GetMap(mapId);
if (!_loader.TryLoadGrid(mapId, path, out var grid))
return;
_metaData.SetEntityName(map.Value, Loc.GetString("map-name-terminal"));
_metaData.SetEntityName(mapUid, Loc.GetString("map-name-terminal"));
foreach (var id in grids)
{
EnsureComp<ArrivalsSourceComponent>(id);
EnsureComp<ProtectedGridComponent>(id);
EnsureComp<PreventPilotComponent>(id);
}
EnsureComp<ArrivalsSourceComponent>(grid.Value);
EnsureComp<ProtectedGridComponent>(grid.Value);
EnsureComp<PreventPilotComponent>(grid.Value);
// Setup planet arrivals if relevant
if (_cfgManager.GetCVar(CCVars.ArrivalsPlanet))
{
var template = _random.Pick(_arrivalsBiomeOptions);
_biomes.EnsurePlanet(map.Value, _protoManager.Index(template));
_biomes.EnsurePlanet(mapUid, _protoManager.Index(template));
var restricted = new RestrictedRangeComponent
{
Range = 32f
};
AddComp(map.Value, restricted);
AddComp(mapUid, restricted);
}
_mapSystem.InitializeMap(map.Value.Comp.MapId);
_mapSystem.InitializeMap(mapId);
// Handle roundstart stations.
var query = AllEntityQuery<StationArrivalsComponent>();

View File

@@ -200,11 +200,11 @@ public sealed class IonStormSystem : EntitySystem
// i dont think theres a way to do this in fluent
var (who, plural) = _robustRandom.Next(0, 5) switch
{
0 => (Loc.GetString("ion-storm-you"), false),
1 => (Loc.GetString("ion-storm-the-station"), true),
2 => (Loc.GetString("ion-storm-the-crew"), true),
3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), false),
_ => (area, true) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS
0 => (Loc.GetString("ion-storm-you"), true),
1 => (Loc.GetString("ion-storm-the-station"), false),
2 => (Loc.GetString("ion-storm-the-crew"), false),
3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), true),
_ => (area, false) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS
};
var jobChange = _robustRandom.Next(0, 3) switch
{

View File

@@ -1,11 +1,24 @@
using System.Threading;
using Content.Server.StationEvents.Events;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents.Components;
[RegisterComponent, Access(typeof(PowerGridCheckRule))]
public sealed partial class PowerGridCheckRuleComponent : Component
{
/// <summary>
/// Default sound of the announcement when power is back on.
/// </summary>
private static readonly ProtoId<SoundCollectionPrototype> DefaultPowerOn = new("PowerOn");
/// <summary>
/// Sound of the announcement to play when power is back on.
/// </summary>
[DataField]
public SoundSpecifier PowerOnSound = new SoundCollectionSpecifier(DefaultPowerOn, AudioParams.Default.WithVolume(-4f));
public CancellationTokenSource? AnnounceCancelToken;
public EntityUid AffectedStation;

View File

@@ -210,7 +210,7 @@ public sealed class EventManagerSystem : EntitySystem
if (prototype.Abstract)
continue;
if (!prototype.TryGetComponent<StationEventComponent>(out var stationEvent))
if (!prototype.TryGetComponent<StationEventComponent>(out var stationEvent, EntityManager.ComponentFactory))
continue;
allEvents.Add(prototype, stationEvent);

View File

@@ -26,7 +26,8 @@ public sealed class ImmovableRodRule : StationEventSystem<ImmovableRodRuleCompon
var proto = _prototypeManager.Index<EntityPrototype>(protoName);
if (proto.TryGetComponent<ImmovableRodComponent>(out var rod) && proto.TryGetComponent<TimedDespawnComponent>(out var despawn))
if (proto.TryGetComponent<ImmovableRodComponent>(out var rod, EntityManager.ComponentFactory) &&
proto.TryGetComponent<TimedDespawnComponent>(out var despawn, EntityManager.ComponentFactory))
{
if (!TryFindRandomTile(out _, out _, out _, out var targetCoords))
return;

View File

@@ -59,7 +59,7 @@ namespace Content.Server.StationEvents.Events
component.AnnounceCancelToken = new CancellationTokenSource();
Timer.Spawn(3000, () =>
{
Audio.PlayGlobal("/Audio/Announcements/power_on.ogg", Filter.Broadcast(), true, AudioParams.Default.WithVolume(-4f));
Audio.PlayGlobal(component.PowerOnSound, Filter.Broadcast(), true);
}, component.AnnounceCancelToken.Token);
component.Unpowered.Clear();
}

View File

@@ -11,6 +11,7 @@ using Content.Shared.Roles;
using Content.Shared.StationRecords;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.StationRecords.Systems;
@@ -39,6 +40,7 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
[Dependency] private readonly StationRecordKeyStorageSystem _keyStorage = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IdCardSystem _idCard = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
@@ -232,6 +234,28 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
return records.Records.TryGetRecordEntry(key.Id, out entry);
}
/// <summary>
/// Gets a random record from the station's record entries.
/// </summary>
/// <param name="ent">The EntityId of the station from which you want to get the record.</param>
/// <param name="entry">The resulting entry.</param>
/// <typeparam name="T">Type to get from the record set.</typeparam>
/// <returns>True if a record was obtained. False otherwise.</returns>
public bool TryGetRandomRecord<T>(Entity<StationRecordsComponent?> ent, [NotNullWhen(true)] out T? entry)
{
entry = default;
if (!Resolve(ent.Owner, ref ent.Comp))
return false;
if (ent.Comp.Records.Keys.Count == 0)
return false;
var key = _random.Pick(ent.Comp.Records.Keys);
return ent.Comp.Records.TryGetRecordEntry(key, out entry);
}
/// <summary>
/// Returns an id if a record with the same name exists.
/// </summary>

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Mind;
using Content.Shared.Store;
using Content.Shared.Store.Components;
using Robust.Shared.Prototypes;
@@ -117,7 +118,7 @@ public sealed partial class StoreSystem
if (listing.Conditions != null)
{
var args = new ListingConditionArgs(buyer, storeEntity, listing, EntityManager);
var args = new ListingConditionArgs(GetBuyerMind(buyer), storeEntity, listing, EntityManager);
var conditionsMet = true;
foreach (var condition in listing.Conditions)
@@ -137,6 +138,19 @@ public sealed partial class StoreSystem
}
}
/// <summary>
/// Returns the entity's mind entity, if it has one, to be used for listing conditions.
/// If it doesn't have one, or is a mind entity already, it returns itself.
/// </summary>
/// <param name="buyer">The buying entity.</param>
public EntityUid GetBuyerMind(EntityUid buyer)
{
if (!HasComp<MindComponent>(buyer) && _mind.TryGetMind(buyer, out var buyerMind, out var _))
return buyerMind;
return buyer;
}
/// <summary>
/// Checks if a listing appears in a list of given categories
/// </summary>

View File

@@ -146,7 +146,7 @@ public sealed partial class StoreSystem
//condition checking because why not
if (listing.Conditions != null)
{
var args = new ListingConditionArgs(component.AccountOwner ?? buyer, uid, listing, EntityManager);
var args = new ListingConditionArgs(component.AccountOwner ?? GetBuyerMind(buyer), uid, listing, EntityManager);
var conditionsMet = listing.Conditions.All(condition => condition.Condition(args));
if (!conditionsMet)

View File

@@ -20,7 +20,7 @@ public sealed partial class WireLayoutPrototype : IPrototype, IInheritingPrototy
public string[]? Parents { get; private set; }
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <summary>
/// How many wires in this layout will do

View File

@@ -14,12 +14,12 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
{
/// <inheritdoc />
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<EntityPrototype>))]
public string[]? Parents { get; }
public string[]? Parents { get; private set; }
/// <inheritdoc />
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <inheritdoc />
[IdDataField]
@@ -42,7 +42,7 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
/// </summary>
[DataField("chunkComponents")]
[AlwaysPushInheritance]
public ComponentRegistry ChunkComponents { get; } = new();
public ComponentRegistry ChunkComponents = new();
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
/// <summary>

View File

@@ -84,12 +84,12 @@ public sealed partial class NoiseChannelPrototype : NoiseChannelConfig, IPrototy
{
/// <inheritdoc />
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<EntityPrototype>))]
public string[]? Parents { get; }
public string[]? Parents { get; private set; }
/// <inheritdoc />
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <inheritdoc />
[IdDataField]

View File

@@ -0,0 +1,55 @@
using Content.Server.Storage.Components;
using Content.Shared._CP14.Cargo;
using Content.Shared.Storage.Components;
namespace Content.Server._CP14.Cargo;
public sealed partial class CP14CargoSystem
{
private void InitializePortals()
{
SubscribeLocalEvent<CP14TradingPortalComponent, MapInitEvent>(OnTradePortalMapInit);
SubscribeLocalEvent<CP14TradingPortalComponent, StorageAfterCloseEvent>(OnTradePortalClose);
SubscribeLocalEvent<CP14TradingPortalComponent, StorageAfterOpenEvent>(OnTradePortalOpen);
}
private void UpdatePortals(float frameTime)
{
var query = EntityQueryEnumerator<CP14TradingPortalComponent, EntityStorageComponent>();
while (query.MoveNext(out var ent, out var portal, out var storage))
{
if (portal.ProcessFinishTime == TimeSpan.Zero || portal.ProcessFinishTime >= _timing.CurTime)
continue;
portal.ProcessFinishTime = TimeSpan.Zero;
SellingThings((ent, portal), storage);
TopUpBalance((ent, portal), storage);
BuyThings((ent, portal), storage);
CashOut((ent, portal), storage);
ThrowAllItems((ent, portal), storage);
}
}
private void OnTradePortalMapInit(Entity<CP14TradingPortalComponent> ent, ref MapInitEvent args)
{
AddRoundstartTradingPositions(ent);
UpdateStaticPositions(ent);
ent.Comp.CurrentSpecialBuyPositions.Clear();
ent.Comp.CurrentSpecialSellPositions.Clear();
AddRandomBuySpecialPosition(ent, ent.Comp.SpecialBuyPositionCount);
AddRandomSellSpecialPosition(ent, ent.Comp.SpecialSellPositionCount);
}
private void OnTradePortalClose(Entity<CP14TradingPortalComponent> ent, ref StorageAfterCloseEvent args)
{
ent.Comp.ProcessFinishTime = _timing.CurTime + ent.Comp.Delay;
}
private void OnTradePortalOpen(Entity<CP14TradingPortalComponent> ent, ref StorageAfterOpenEvent args)
{
ent.Comp.ProcessFinishTime = TimeSpan.Zero;
}
}

View File

@@ -1,118 +0,0 @@
using System.Numerics;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Shared._CP14.Cargo;
using Content.Shared.Gravity;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server._CP14.Cargo;
public sealed partial class CP14CargoSystem
{
private void InitializeShuttle()
{
SubscribeLocalEvent<CP14TravelingStoreShipComponent, FTLCompletedEvent>(OnFTLCompleted);
SubscribeLocalEvent<CP14TravelingStoreShipComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(Entity<CP14TravelingStoreShipComponent> ent, ref MapInitEvent args)
{
//TODO: This is shitcode! Because shouldnt related to traveling ship
EnsureComp<GravityComponent>(ent, out var gravity);
gravity.Enabled = true;
gravity.Inherent = true;
}
private void UpdateShuttle()
{
var query = EntityQueryEnumerator<CP14StationTravelingStoreShipTargetComponent>();
while (query.MoveNext(out var uid, out var ship))
{
if (_timing.CurTime < ship.NextTravelTime || ship.NextTravelTime == TimeSpan.Zero)
continue;
if (ship.Shuttle is null || ship.TradePostMap is null)
continue;
if (Transform(ship.Shuttle.Value).MapUid == Transform(ship.TradePostMap.Value).MapUid)
{
// if landed on trade post
ship.NextTravelTime = _timing.CurTime + ship.StationWaitTime;
SendShuttleToStation(ship.Shuttle.Value);
}
else
{
// if landed on station
ship.NextTravelTime = _timing.CurTime + ship.TradePostWaitTime;
SendShuttleToTradepost(ship.Shuttle.Value, ship.TradePostMap.Value);
}
}
}
private void SendShuttleToStation(EntityUid shuttle, float startupTime = 0f)
{
var targetPoints = new List<EntityUid>();
var targetEnumerator =
EntityQueryEnumerator<CP14TravelingStoreShipFTLTargetComponent,
TransformComponent>(); //TODO - different method position location
while (targetEnumerator.MoveNext(out var uid, out _, out _))
{
targetPoints.Add(uid);
}
if (targetPoints.Count == 0)
return;
var target = _random.Pick(targetPoints);
var targetXform = Transform(target);
var shuttleComp = Comp<ShuttleComponent>(shuttle);
_shuttles.FTLToCoordinates(shuttle,
shuttleComp,
targetXform.Coordinates,
targetXform.LocalRotation,
hyperspaceTime: 20f,
startupTime: startupTime);
}
private void SendShuttleToTradepost(EntityUid shuttle, EntityUid tradePostMap)
{
var shuttleComp = Comp<ShuttleComponent>(shuttle);
_shuttles.FTLToCoordinates(shuttle,
shuttleComp,
new EntityCoordinates(tradePostMap, Vector2.Zero),
Angle.Zero,
startupTime: 10f,
hyperspaceTime: 20f);
}
private void OnFTLCompleted(Entity<CP14TravelingStoreShipComponent> ent, ref FTLCompletedEvent args)
{
if (!TryComp<CP14StationTravelingStoreShipTargetComponent>(ent.Comp.Station, out var station))
return;
if (station.TradePostMap is not null &&
Transform(ent).MapUid == Transform(station.TradePostMap.Value).MapUid) //Landed on tradepost
{
station.OnStation = false;
SellingThings((ent.Comp.Station, station)); // +balance
TopUpBalance((ent.Comp.Station, station)); //+balance
BuyToQueue((ent.Comp.Station, station)); //-balance +buyQueue
TrySpawnBuyedThings((ent.Comp.Station, station));
UpdateStorePositions((ent.Comp.Station, station));
}
else //Landed on station
{
station.OnStation = true;
CashOut((ent.Comp.Station, station));
station.Balance = 0;
}
UpdateAllStores();
}
}

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