Compare commits

...

371 Commits

Author SHA1 Message Date
Ed
237716b353 icons base 2024-10-18 17:21:19 +03:00
Ed
f14177bf86 Alchemist update (#497)
* rebalance alchemy resource

* lockers alternative

* map update
2024-10-18 14:56:01 +03:00
Ed
9a8d30022a Wallpaper update + paper folder (#495)
* paper folders

* Update CP14WorkbenchSystem.cs

* wallpaper update

* Update walls.yml

* remove cable sprites

* Update migration.yml
2024-10-17 13:08:36 +03:00
Ed
ebca84d28f Minor fixes (#494)
* minor loadout tweaks

* wooden counter

* fix parry predicting

* tables crafting simplify
2024-10-16 17:32:41 +03:00
Ed
5b4a7f6edc Ed 15 10 2024 entity hided (#493)
* test

* hide ss14 ents

* Update basic_cloak.yml
2024-10-15 16:53:54 +03:00
Ed
a83d6f0d87 locale (#491)
* locale

* delete ss14 items generated locales
2024-10-15 16:21:07 +03:00
Ed
5d89812abc Merge pull request #490 from crystallpunk-14/ed-15-10-2024-upstream
Ed 15 10 2024 upstream
2024-10-15 15:41:02 +03:00
Ed
31d39b36ae Update CP14ExpeditionSystem.cs 2024-10-15 15:28:16 +03:00
Ed
dc47bb2283 Merge remote-tracking branch 'upstream/stable' into ed-15-10-2024-upstream
# Conflicts:
#	Content.Server/Station/Systems/StationSpawningSystem.cs
2024-10-15 15:25:44 +03:00
Ed
d259191d3d Cargo system (#487)
* simple storeship arriving

* pupu

* ship cycling

* buy positions prototypes

* i hate UI

* PriceControl

* second tab ui

* baloon! pallets!

* update shop in town

* setup billboard timer

* split to sell and buy categories

* renaming gaming

* actually selling

* fix infinity selling

* improve timer

* move description too rigt part UI

* bar selling

* iron cabinet

* purge currency categories

* remove town balance, add money box

* special proposal, FTLImmune anchor

* fix UI

* remove tests buying

* Update CP14StoreWindow.xaml.cs

* currency converter

* currency clean up

* Update CP14CargoSystem.cs

* clean up part 2

* rider petpet

* coins audio

* coin improvment

* Update coins.yml

* translate

* more coins roundstart

* Update wallet.yml

* Update wallet.yml

* generate coin problem fix

* refactor proto reading

* fixes

* huh

* shuttle logshit fix, add to tavern map

* Update CP14StationTravelingStoreShipTargetComponent.cs
2024-10-15 15:22:06 +03:00
Errant
519a6b2474 HOTFIX: Fix tech anomaly nexttimer (#32805) (#32807)
Fix tech anomaly nexttimer (#32805)

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-10-14 11:41:31 +02:00
Ed
4425b77c90 Return RU lang 2024-10-14 11:39:12 +03:00
Pieter-Jan Briers
796764d755 Fix some rounds failing to end due to mind roles (#32792) (#32793)
* Fix some rounds failing to end due to mind roles

Fixes #32791

This is caused by ShowRoundEndScoreboard running into a bug trying to display antags: some player is showing up as antag with MindIsAntagonist(), but has no antag roles listed in MindGetAllRoleInfo().

This was caused by one of the roles of the player having the Antag boolean set, but having no AntagPrototype set.

The responsible mind role appeared to be MindRoleSubvertedSilicon which is missing a set for the SubvertedSilicon antag prototype.

I also added resilience to the round-end code to make it so that an exception showing the scoreboard (and sending the Discord message) would not cause the round end logic to completely abort from an exception.

I am planning to add an integration test to cover this bug (no prototype in mind roles), but I'll leave that for not-the-immediate-hotfix.

* At least one maintainer approved this tiny PR without reading it, not naming names.
2024-10-13 23:00:40 +02:00
Errant
e5ad32fe93 Fix random test fail in DeleteAllThenGhost (#32753)
It's simple. We kill the heisentest
2024-10-13 17:31:38 +02:00
Ed
648505dc15 Switch to ENG language 2024-10-13 15:02:57 +03:00
Jezithyr
af72f2e17c Applying Fix from #32764 to staging 2024-10-12 22:21:44 -07:00
Nim
40959cf422 fix resp (#488) 2024-10-13 02:09:41 +03:00
Nim
a6fc5e6ace Rabbit (#486)
* rabbit

* meat

* гладить

* тоже гладить
2024-10-12 20:01:13 +03:00
scrivoy
e98af125dc Fixed capitalization in Interface description (#32739) 2024-10-10 21:40:41 +02:00
PJBot
bc64676747 Automatic changelog update 2024-10-10 14:36:43 +00:00
nikthechampiongr
e7b7e2270d Fix bounties(and potentially other things) running out of ids (#32700)
* Make NameIdentifier Ids get refreshed after round restarts

Before this commit the existing values would just get shuffled.
This means that eventually the server would run out of ids to give to
new entities for different groups. As a result everything would get id 0

* Comply with what seemingly is the convention for sawmills

* Make it impossible to insert a bounty with a duplicate id

* Reduce duplication

* Remove unused sawmill

* Fix rustbrain and skill issue

* Aaaa

* Apply suggestions from code review

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2024-10-10 16:35:35 +02:00
PJBot
740288eb96 Automatic changelog update 2024-10-10 08:50:05 +00:00
Errant
93c7bdc134 Mind Role Entities (#31318)
* Mind Role Entities wip

* headrev count fix

* silicon stuff, cleanup

* exclusive antag config, cleanup

* jobroleadd overwerite

* logging stuff

* MindHasRole cleanup, admin log stuff

* last second cleanup

* ocd

* minor cleanup

* remove createdTime datafield

* now actually using the event replacement I made for role time tracking

* weh
2024-10-10 10:48:56 +02:00
Pieter-Jan Briers
3e078ab3e0 Fix error log when recycling something with small material counts. (#32723)
* Fix error log when recycling something with small material counts.

MaterialStorageSystem.SpawnMultipleFromMaterial now doesn't call StackSystem.SpawnMultiple if it tries to spawn zero. This happens because the recycler calls SpawnMultipleFromMaterial for everything recycled, even if the amount it has stored is < the amount for one sheet.

* Update Content.Server/Materials/MaterialStorageSystem.cs

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

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-10-10 03:29:26 +02:00
PJBot
ac16a05fef Automatic changelog update 2024-10-09 18:02:38 +00:00
beck-thompson
327466a6e2 Plushies can now have pAIs stuffed into them (v2)! (#30805)
* First commit

* I forgot silly me

* Actually added comments

* spellin

* fixes

* more blacklists

* Minor fixes

* Speech Verb also changes now

* Simple name stuff

* Other fixes

* remove one line of whitespace

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-10-09 20:01:32 +02:00
chavonadelal
6d99597349 Job title localization (#32338)
* Job title localization

* Correcting fields
2024-10-09 17:05:36 +02:00
Ed
844b4d4616 underworld (#485) 2024-10-09 16:19:38 +03:00
PJBot
fc1c709d44 Automatic changelog update 2024-10-09 12:45:45 +00:00
beck-thompson
5a41cc81b3 Decrease price of radio jammer from 4 tc -> 3 tc (#32472)
* First commit

* increase price by one tc
2024-10-09 14:44:38 +02:00
lzk
d450b613d6 fix typo (#32712) 2024-10-09 14:41:07 +02:00
PJBot
b657aba2e1 Automatic changelog update 2024-10-09 11:56:57 +00:00
SlamBamActionman
ddaa0e83c6 Add admin log for codewords (#32531)
* initial commit

* Delta review
2024-10-09 13:55:48 +02:00
Pieter-Jan Briers
1dbbf315c7 Update submodule to v236.1.0 (#32704) 2024-10-09 13:41:03 +02:00
Ed
b9df2a495a some blacksmith bandage (#483)
* anvil

* iron and copper ore walls + procedural cave update

* vladimirs rocks

* furnace

* Revert "furnace"

This reverts commit f378e4fb85.

* Revert "vladimirs rocks"

This reverts commit b2c6a193fc.

* Revert "iron and copper ore walls + procedural cave update"

This reverts commit dc6d70b10e.

* Revert "anvil"

This reverts commit 3ab1649992.

* Reapply "anvil"

This reverts commit 91c226d18d.

* huh

* fuck anvil

* Revert "fuck anvil"

This reverts commit 3c3a87c25e.

* Revert "huh"

This reverts commit 7fb44b4908.

* fix comment

* Reapply "iron and copper ore walls + procedural cave update"

This reverts commit 891c3ba0aa.

* Reapply "vladimirs rocks"

This reverts commit 4f2eaef6c1.

* Reapply "furnace"

This reverts commit 9d7e042ddf.

* Update anvil.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* Update workbenchs.yml

* EVIL anvil

* Update workbenchs.yml
2024-10-09 13:40:06 +03:00
PJBot
357e998cbb Automatic changelog update 2024-10-08 23:30:49 +00:00
beck-thompson
384ff7e8f6 Add pumpkin pie! (#32623)
* first commit

* Licence fix

* rosysyntax licence change (permission granted!)

* simplify

* Better wording
2024-10-09 10:29:41 +11:00
Nim
1ca7456363 AI Factions (#481)
* factions

* CP14

* Update ai_factions.yml

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-10-08 22:52:46 +03:00
PJBot
dc2899c274 Automatic changelog update 2024-10-08 18:30:44 +00:00
K-Dynamic
6f9b4f4226 CHIMP and APE particle speed increase (#32690)
* swap omega and delta particle colours

* remove upgrade doafter

* explicit syndicate chip description

* Syndicate CHIMP stealth

* fast projectile speed

* 10 to 12 shots

* buff heat dmg

* upgrade chip mentions omega particle

* Revert "remove upgrade doafter"

This reverts commit 8a321980b7a384daca06215656494e0c116e7333.

* Revert "explicit syndicate chip description"

This reverts commit c803c773739a61fc5b3a6cb90810622a6d5846c9.

* Revert "Syndicate CHIMP stealth"

This reverts commit 698a108580892addabf8d51494a72e1ee651b8e6.

* Revert "10 to 12 shots"

This reverts commit 858ac0392be0549eb0a288648413d1020cabae1a.

* Revert "swap omega and delta particle colours"

This reverts commit 4c000b2f110a5d35f317cb61cb5b03ea32841ad5.

* Revert "buff heat dmg"

This reverts commit 02a8690dafbd41631b098e51ef9afba5b6ee6ac4.
2024-10-08 20:29:37 +02:00
PJBot
28f576dae8 Automatic changelog update 2024-10-08 09:54:56 +00:00
Plykiya
1366f6b405 Replace the Librarian's round-start D10 with a D20 (#32648)
Replace D10 with a D20
2024-10-08 11:53:50 +02:00
averystarbit
0e0887bd49 Added proper capitalisation for supervisors when entering the game (#32683)
changed punctuation for jobs, added proper capitalization and comma usa
2024-10-08 11:52:46 +02:00
PJBot
1f04117edf Automatic changelog update 2024-10-08 09:52:31 +00:00
shamp
922dd0bce6 Fix cloth dupe (#32685)
Update curtains.yml
2024-10-08 11:51:23 +02:00
lzk
33042b00d0 Fix cryo locale again (#32654)
* Fix cryo locale again

* yeep
2024-10-08 11:50:54 +02:00
Ubaser
38fd54a1bf Update Core (#32665)
* add

* remove invalids

* fix

* yes
2024-10-07 19:59:06 -06:00
PJBot
34df781668 Automatic changelog update 2024-10-07 22:43:51 +00:00
Saphire Lattice
f22f9e39c5 Change minibomb to be explosion resistant and start timer on damage (#32429)
* Make minibomb explosion resistant and trigger timer on damage

* Tune damage behaviour and threshold for minibomb
2024-10-08 00:42:42 +02:00
Pieter-Jan Briers
eecbfb63a0 Move client dumpentities command to "DEBUG" (#32687) 2024-10-07 19:19:42 +02:00
Scribbles0
6b10e00da4 oasis update (#32679)
sec apcs and ai core wiring
2024-10-06 19:24:44 -06:00
Ed
d2c5aa74b4 Ritualizm (#474)
* ritual cucumber setup

* entities requirements

* try graph???

* Revert "try graph???"

This reverts commit c90c6353cb.

* pipyau

* fixes

* yay, it works

* spawn effect

* regex lower message restrictions

* unique speakers support

* apply entity effect ritual

* ritual chalk

* Update SpawnEntity.cs

* ritual stability

* stability event

* add guidebook description to all ritual actions

* Readability added

* Update RequiredResource.cs

* finish describer

* clean up describer

* Update triggers.ftl

* cave ambient loop

* parry sound update

* rituals end start

* magic ambience add

* global sharedization

* Update phases.yml

* daytime requirement

* Update phases.yml

* start ritual

* fixes

* more ambient work

* rritual visualizer

* end ritual

* magic orbs!

* required orbs

* orbs design

* consume orbs

* setup neutral cluster triggers and edges

* listener proxy

* restucture graph

* fix time triggers

* healing cluster

* fixes

* Create CP14RitualTest.cs

* test errors for check test

* YEEEE

* Fuck triggers, its broken now, YAY

* triggers redo

* fix

* fix test

* Update CP14RitualTest.cs

* Update neutral_cluster.yml

* Update CP14RitualSystem.Triggers.cs

* clean up, documentation

* redo triggers again

* and another one

* species sacrifice trigger

* whitelist trigger

* fix

* describer refactor

* fix memory leaking  + hyperlinks

* dd
2024-10-06 18:04:18 +03:00
Nim
a6532a2801 fix (#480) 2024-10-06 17:12:31 +03:00
PJBot
a6c468b697 Automatic changelog update 2024-10-06 13:34:08 +00:00
Golinth
46a2eb545e Fully Revert Clown Waddling (#32652)
Fully revert Clown Waddling (revival of #29161)

A sad day, see #29156 for discussion
2024-10-06 15:33:02 +02:00
PJBot
35fc1b4037 Automatic changelog update 2024-10-06 12:49:56 +00:00
Арт
867efe8b5b Add flowers to loadout (#32097)
* Add_Poppy&Lily

* Add_FlowerWreath

* Add_Headflowers

Sprites, meta, prototype

* Id_Changes

* Changes

* Update_Sprite

* Desc_Change

* Scale_Change

* Sprite_Scaling
2024-10-06 14:48:49 +02:00
Spessmann
126c1786de Cog update fix (#32657)
* fixes for cog

* ok fixed that
2024-10-05 20:30:10 -06:00
PJBot
386e59b462 Automatic changelog update 2024-10-05 18:45:55 +00:00
slarticodefast
eb4e422cb0 fix light bulbs not fitting into the trash bag (#32452)
fix trash
2024-10-05 12:44:47 -06:00
Spessmann
2287df13bd Cog engineering DIY update (#32651)
engineers forced to do work, sobbing
2024-10-05 12:08:39 -06:00
TakoDragon
db64ad9c4d Marathon Removed double walls and a wrong cable (#32603)
removed double walls and cable fucks
2024-10-04 17:18:46 -06:00
NotSoDamn
644d7ab682 BaseAdvancedPen migration (#32638)
* Update migration.yml

* Update Resources/migration.yml

Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com>

---------

Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com>
2024-10-04 23:13:30 +03:00
Nim
98c921aa94 Zombie and old lamp (#467)
* zombie

* fix

* spawner fix

* license

* woman parts

* male parts

* 122

* 123

* 124

* HideSpawnMenu

* damn

* requested

* fixxxx

* gooo
2024-10-04 21:24:17 +03:00
Nim
21ea4290a5 Paintings (#479)
* oppa

* fix

* Update Resources/Textures/_CP14/Structures/Wallmount/wallmount_painting.rsi/meta.json

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-10-04 21:18:01 +03:00
Ed
c55241355e Update wild.yml 2024-10-04 19:48:18 +03:00
Ed
35baaacbce Blue amanita flower, mana potions! (#478)
* merge bloodgrass and red flowers

* delete sprites

* add blue amanita sprites

* restruct alchemy reactions folders

* mana heal and damage reagent

* add gatherable to worldgen

* fixes

* Update sewing_table.yml

* Update Alchemy.xml

* Update Alchemy.xml

* Update migration.yml
2024-10-04 19:19:13 +03:00
PJBot
ec4acdebbf Automatic changelog update 2024-10-04 09:35:55 +00:00
Saphire Lattice
94c8018ff3 Change the syndicate charge to start a timer on signal (#32423)
* Change the syndicate charge to start a timer on signal

* Actually add the component in question

* Add default link for TimerStart signal
2024-10-04 11:34:48 +02:00
PJBot
fbb6f17add Automatic changelog update 2024-10-04 08:44:51 +00:00
Saphire Lattice
88f060d51a Make the explosions throw the container/item they originated from (#32428)
Extra fun if it's something that can trigger multiple times
2024-10-04 10:43:45 +02:00
PJBot
8b65186bfa Automatic changelog update 2024-10-04 05:40:57 +00:00
SoulFN
9e054c1f9d Give dragon pull ability (#32568) 2024-10-04 15:39:50 +10:00
PJBot
423d394af1 Automatic changelog update 2024-10-04 02:56:43 +00:00
Plykiya
295e63193c Two additional checks to prevent FTLing stations (#32558)
Add two additional checks to prevent FTLing
2024-10-04 12:55:36 +10:00
Jezithyr
570c166517 Disable Auto-Publish (#32627)
disable auto publish
2024-10-04 03:16:32 +02:00
PJBot
7edd1c6d52 Automatic changelog update 2024-10-04 01:14:09 +00:00
Southbridge
c0d67429ab Box Station - Connected Recycler, rerouted power for Singlo Substation, added law boards to AI upload room (#32608)
* Fixed #32443 and #30375

* Fixed duplicate ID issue, and added lawboards to resolve #32581

* Removed Overlord board and added Crewsimov

* Removed invalid UserInterface component
2024-10-03 19:12:59 -06:00
Ed
41cf2b22ff Merge pull request #477 from crystallpunk-14/ed-03-10-2024-upstream
Ed 03 10 2024 upstream
2024-10-03 17:47:23 +03:00
Ed
ab1e071fdf Merge remote-tracking branch 'upstream/master' into ed-03-10-2024-upstream
# Conflicts:
#	Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml
2024-10-03 17:34:08 +03:00
PJBot
1c41d3381f Automatic changelog update 2024-10-03 14:02:07 +00:00
eoineoineoin
a8982b88af Allow users to drag-reorder action bar (#32552)
* Avoid rebuilding all buttons on action state change

Allows for drag events to continue when actions change

* Remove excess action buttons

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-10-03 16:01:01 +02:00
PJBot
568fb235fa Automatic changelog update 2024-10-03 10:33:16 +00:00
Vasilis
bc76cd876f Remove sentience from clean and medi bot (#32383)
There is no point in these silicon being sentient, they have basically zero role play potential and are not meant to be controlled by players. The janibot can be played somewhat but at that point we have janitor borgs which are way better at this. You can only clean floors and even then it does a terrible job at doing that and only that. A player playing as a janibot will get bored quickly. No amount of RP will save you.

A player taking over a mediborg just makes it useless as you cant inject anymore. And again, medical borg. There's no point in adding the feature. It's too much work then its worth when we have borgs.

They don't have ghost role info for a reason. They are not meant to be played.
2024-10-03 03:32:10 -07:00
PJBot
3e85d28e9d Automatic changelog update 2024-10-03 10:03:05 +00:00
ArtisticRoomba
c68e5a667c Various item contraband fixes (#32614)
* fixes current contraband issues: xray cannon, hos's trench coats, stinger grenades

* yet another contraband addition
2024-10-03 12:01:58 +02:00
SpaceCat
b603233480 change sound (#476) 2024-10-03 09:28:50 +03:00
PJBot
052d7c4d2e Automatic changelog update 2024-10-03 00:13:04 +00:00
Pieter-Jan Briers
2d644095e3 Fix borg hands showing up in stripping menu (#32606)
* Fix borg hands showing up in stripping menu

Borgs can't drop their items anyways, and the amount of hands borgs have causes the UI to just bug out.

* Add more checks
2024-10-03 02:11:56 +02:00
PJBot
440742f8f7 Automatic changelog update 2024-10-02 13:53:20 +00:00
Pieter-Jan Briers
719f78956b Disable bioluminescence plant mutations because it breaks the engine (#32561)
No fun allowed

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-10-02 15:52:14 +02:00
Flareguy
4ad4fd42b1 Steel tile variantization fix (#32596)
steel tile variantization fix
2024-10-02 14:14:44 +02:00
PJBot
58c8a07d2c Automatic changelog update 2024-10-02 12:01:37 +00:00
FluffMe
8961dd35a5 Fix accidental erase of paper contents by spamming save action (#32598)
Fix spammable paper save issue
2024-10-02 14:00:31 +02:00
PJBot
9b4df5b452 Automatic changelog update 2024-10-02 11:45:17 +00:00
deltanedas
8b14e2534d fix instigator not existing (#32597)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-10-02 13:44:11 +02:00
lzk
c55e311c7e Cleanup pins.yml (#32593)
* Cleanup pins.yml

* oh my

* forgor
2024-10-02 13:23:32 +02:00
PJBot
612732fb84 Automatic changelog update 2024-10-02 10:54:25 +00:00
lzk
edc83b2fab cleanup and fix dinky star (#32594)
* cleanup dinky star

* fix

* oh
2024-10-02 12:53:19 +02:00
PJBot
7b39d146d3 Automatic changelog update 2024-10-02 09:38:55 +00:00
Toly65
ea3b14faac Bandaid fix to entityeffects on plant trays (#32576)
prevented the bioluminescent and slippery effects from being applied to the plant (and thus the plant tray)
2024-10-02 11:37:49 +02:00
PJBot
5a229e7a2b Automatic changelog update 2024-10-02 06:19:03 +00:00
ArchRBX
dd12ac1f8a MedTek Cartridge (#32450)
* initial commit

* adds cartridge to cmo's locker

* tidies up yml, adds default scanner sound, makes it so the silent property silences the scanner sound too

* fixes ert medic pda not having it preinstalled

* adds attribution

* removes redundant dependencies

* fix agent pda

---------

Co-authored-by: archrbx <punk.gear5260@fastmail.com>
2024-10-01 23:17:57 -07:00
PJBot
c4c786f08d Automatic changelog update 2024-10-02 05:36:54 +00:00
TakoDragon
542817807d Red circuit floor (#32557)
* red circuit added

* index colour begone
2024-10-01 23:35:48 -06:00
PJBot
b364894228 Automatic changelog update 2024-10-02 05:34:42 +00:00
TakoDragon
936917cd05 Hydroponics doors (#32575)
* spriting done

* yml hydro updates

* Named wrong thing and forgot it inherets
2024-10-01 23:33:35 -06:00
Preston Smith
2df61e4e71 Added LV cables to Marathon SMES room (#32574)
Added LV cables to SMES room, powering light and computers.
2024-10-01 23:30:58 -06:00
PJBot
95f20f13dc Automatic changelog update 2024-10-02 05:28:07 +00:00
Plykiya
2a07e4666a Fix quick-swap stacks of items (#32560)
* remove picking up stack on quick swap

* better
2024-10-02 15:27:01 +10:00
PJBot
cfc723e3f8 Automatic changelog update 2024-10-02 05:01:54 +00:00
metalgearsloth
4ca2a2bb8f Fix sensors blocking doors (#32591) 2024-10-01 23:00:48 -06:00
PJBot
b050e8332e Automatic changelog update 2024-10-02 03:23:15 +00:00
slarticodefast
360585276d fix voice mask chameleon menu (#32546) 2024-10-01 21:22:09 -06:00
PJBot
c0d8d58629 Automatic changelog update 2024-10-02 02:57:55 +00:00
Zylofan
42a1e02261 Seismic charge now craftable (#32459)
* when tryInsertBlueprint is called it now also calls UpdateMaterialWhitelist on the ent so that it can accept new materials if needed.

* Changed the previous commit to now just have sharedMaterialStorageSystem subscribe to TechnologyDatabaseModifiedEvent which will call  UpdateMaterialWhitelist.

* Empty-Commit
2024-10-01 20:56:49 -06:00
Scribbles0
20aa14e4f7 Cog update (#32585)
* ai core upgrades

* fix distro color
2024-10-01 19:45:54 -06:00
github-actions[bot]
8833cf624a Update Credits (#32516)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2024-10-02 01:29:00 +02:00
Zylofan
ec8b7b238a fixed it so blue bandana head and mask sprite is not reversed on vox (#32569) 2024-10-01 23:55:56 +02:00
PJBot
24f2d4c317 Automatic changelog update 2024-10-01 21:45:55 +00:00
TakoDragon
f3fe5af240 Reinforced walls sprite see throu top (#32578)
fixed a gap
2024-10-01 23:44:47 +02:00
PJBot
bfb2f60090 Automatic changelog update 2024-10-01 21:08:56 +00:00
TakoDragon
23f4bc1d7a Gay Boykissers (#32584) 2024-10-01 23:07:48 +02:00
PJBot
d82c666e80 Automatic changelog update 2024-10-01 15:15:06 +00:00
BramvanZijp
f79de12509 Prevent borgs from being able to be briefly toggled off. (#32485)
* Prevent borgs from being able to be briefly toggled off.

* Use the pre-existing component instead of making an unneccesary duplicate.
2024-10-02 01:13:59 +10:00
Jaraten
6c08ca60f3 frame & table (#464)
* frame & table

* rem superfluous sprite

* merge conflict

* duplicate_ID

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-10-01 16:32:14 +03:00
PJBot
6a1815aeaf Automatic changelog update 2024-10-01 04:04:43 +00:00
ScarKy0
ba68fb2ddb Update binary key to use AI icon (#32327)
* Init

* uplink icon
2024-10-01 14:03:37 +10:00
PJBot
a73780bc57 Automatic changelog update 2024-10-01 03:14:22 +00:00
Golinth
3b682d4d68 Added Firebots - Real (#32482)
* Add Firebots

Had to add OnActivateInWorld to the spray system to get the bot to work. Checks for the flammable component and if the onFire boolean is true.

* Make SpraySystem actually use useDelay

got rid of that TODO

* Added firebot speech

Fire detected!
2024-09-30 20:13:16 -07:00
PJBot
edc110907e Automatic changelog update 2024-09-30 22:41:38 +00:00
kosticia
5681db31a9 Changing the thief's objective to stealing ID cards. (#32411)
* Changed thief ID objection

* Update Resources/Prototypes/Objectives/thief.yml

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-10-01 00:40:31 +02:00
PJBot
64e637905a Automatic changelog update 2024-09-30 22:25:44 +00:00
pofitlo
bad7359aeb Add camera bug (#30250)
* Add camera bug

* Update camera_bug.png

* fix

* change

* Update Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/camera_bug.yml

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

* Update Resources/Prototypes/Catalog/uplink_catalog.yml

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-10-01 00:24:36 +02:00
pofitlo
2f286afd95 Syndicate business card (#32162)
* add card

* Update Resources/Locale/en-US/paper/syndicate-business-card.ftl

Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com>

* fix

* Update Resources/Prototypes/Entities/Objects/Misc/business card.yml

Co-authored-by: Эдуард <36124833+Ertanic@users.noreply.github.com>

* add logo

* swap the "funny 'c'"

* improve logo (a little) and also fight with the funny 'c'

* fix

* oh... i think... mabe i done with this?...

* add

* smaller cards

* fix

* Update synicate_card.png

* fix typo

* fix

* fix

* Update Resources/Prototypes/Entities/Objects/Misc/business_card.yml

---------

Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com>
Co-authored-by: Эдуард <36124833+Ertanic@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-30 22:44:44 +02:00
Charlie
55ae02f320 fix index stepping to avoid pushing front layers into back layers (#32553)
Co-authored-by: charlie <charlie.sc.wong@veiwsonic.com>
2024-09-30 22:27:33 +03:00
PJBot
db198d2813 Automatic changelog update 2024-09-30 17:39:29 +00:00
BramvanZijp
38f59d2038 Swap the advanced tool borg modules omnitool for jaws and a power drill (#32487) 2024-09-30 19:38:22 +02:00
PJBot
717f82f9da Automatic changelog update 2024-09-30 09:57:11 +00:00
qwerltaz
bc059f0b6d AI can use fire alarm (#32467)
* ai can use fire alarm

* ai wire
2024-09-30 11:56:05 +02:00
PJBot
c419e58300 Automatic changelog update 2024-09-30 05:15:13 +00:00
drakewill-CRL
7cf04dcb20 Use archived gas mixture in gas exchange comparison (#32088)
The comparison for doing gas exchange used current and not archived
moles. This could lead to update order-dependent gas spreading effects.

To fix this, convert TileAtmosphere's MolesArchived and
TemperatureArchived to a AirArchived, and use that in the comparison
method.

---------

Co-authored-by: PraxisMapper <praxismapper@gmail.com>
Co-authored-by: Kevin Zheng <kevinz5000@gmail.com>
2024-09-29 22:14:07 -07:00
PJBot
dd15a6862c Automatic changelog update 2024-09-29 22:37:53 +00:00
Celene
5c0b127456 Execution System uses the identity of an entity; added "the" to execution message (#32536)
* Exec.System now uses IdentityManagement; added the where necessary

* Included attacker in check for Identity

---------

Co-authored-by: Celene <maurice_riepert94@web.de>
2024-09-30 00:36:47 +02:00
slarticodefast
16325007d5 Fix mutation system debug assert (#32530) 2024-09-29 13:37:31 -08:00
PJBot
f6ceaa7d10 Automatic changelog update 2024-09-29 15:19:15 +00:00
Ilya246
4aed728207 make conveyor belt assemblies cheaper (#32444)
cheapening
2024-09-29 17:18:09 +02:00
Ed
3f94c73bdb Magic update (#473)
* magic system update

* fix
2024-09-29 16:44:17 +03:00
SlamBamActionman
d0c4d5a93a Add webhook for votekicks (#32513)
* Initial commit

* Localization
2024-09-29 15:23:53 +02:00
PJBot
cc9202bbb2 Automatic changelog update 2024-09-29 12:24:03 +00:00
ArtisticRoomba
1dc9541aed Fixes HoS's energy shotgun not being marked as restricted contraband (#32521)
* the 12^21th contraband marking fix

one step closer to release

* sometimes you just make mistakes
2024-09-29 14:22:57 +02:00
PJBot
6bc383c0ef Automatic changelog update 2024-09-29 12:20:08 +00:00
Leon Friedrich
f1f1fc1dc3 Add interaction rate limits (#32527)
* Move PlayerRateLimitManager to shared

* Add interaction rate limits

* uncap tests
2024-09-29 22:19:00 +10:00
PJBot
6b49a510d1 Automatic changelog update 2024-09-29 12:14:30 +00:00
Leon Friedrich
d806db264a Fix currency duplication bug (#32524) 2024-09-29 22:13:22 +10:00
Ed
4cd9e41469 Mist + Lampposts (#472)
* lamppost

* mist weather

* maps update

* Update weather.yml

* Update meta.json
2024-09-29 13:07:30 +03:00
Ed
4d9e657f6f Split decal cleaner into Broom + Max Gab papers and hair (#470)
* add broom

* water fix

* new hair

* paper added

* feather pen

* some unfinished inkwell

* inkstorage

* Update meta.json

* fixes
2024-09-29 11:02:39 +03:00
nikthechampiongr
a5840b925b Fix RA0032 (#32514) 2024-09-29 02:25:21 +02:00
MilenVolf
1b9d77a760 Replace obsolete Tile Access methods (#32508)
* Replace obsolete SetTile

* Remove obsolete GetTileRef & GetAllTiles

* Forgor

* Apply suggested `GetMapOrInvalid`
2024-09-29 01:27:47 +02:00
Ed
9f93931057 Revert "Added personal signature system (#382)" (#471)
This reverts commit 0cd3a3c2d9.
2024-09-29 00:36:08 +03:00
Ed
0dc7982109 Footprints + Mop + Force undersky liquid evaporation (#469)
* all evaporation under sky

* footprints system

* puddle footprints

* split to holder and trailer

* mop added

* mop finish
2024-09-28 18:09:30 +03:00
metalgearsloth
0a7b23cd4d Update submodule to 236.0.0 (#32500) 2024-09-28 19:31:27 +10:00
PJBot
8b692d118d Automatic changelog update 2024-09-28 09:03:49 +00:00
metalgearsloth
bed968465c Fix multiple door issues (#32483)
* Fix multiple door issues

- Doors should no longer cycle open-and-closed anymore (at least nowhere near as easily).
- Door sprites shouldn't flicker as much (needs my engine PRs to remove all but one of them).

* woops conversion
2024-09-28 19:02:43 +10:00
PJBot
9f5b6af82d Automatic changelog update 2024-09-28 06:08:57 +00:00
Futuristic-OK
a371de16d3 Some new hairstyles! (#31010)
* Add files via upload

png of hairs

* Update meta.json

hairs meta

* Update human_hair.yml

hairs yml

* Update human-hair.ftl

hairs named

* second try

* fix meta

* Add files via upload

* Add files via upload

fix again

* Add files via upload

again again

* Add files via upload

again again fix again

* Add files via upload

i hate yourself

* Add files via upload

fixxxxx!

* Add files via upload

aaagaaaaiiin

* dd

dddddd

* Add files via upload

fix again

* Add files via upload

ddsdssddssddsdsds

* Update human-hair.ftl

* Update human-hair.ftl

screw this im just going to update it myself
webops time

* Update human_hair.yml

* Update meta.json

* Rename capsdaughter.png to longbow.png

* Rename artist.png to shaped.png

---------

Co-authored-by: Ubaser <134914314+UbaserB@users.noreply.github.com>
2024-09-28 16:07:51 +10:00
metalgearsloth
dd376e4e84 Optimise drains (#32230)
* Optimise drains

If it's still a problem then we do what I did for rmc14 and just dump all the active drains onto a job to getentitiesinrange in parallel.

* Fixes
2024-09-28 15:16:54 +10:00
PJBot
caac678fa6 Automatic changelog update 2024-09-28 04:41:31 +00:00
beck-thompson
7485411ab2 Predict appraisal tool verb! (#32496)
* First commit

* Network :(
2024-09-28 14:40:24 +10:00
Ed
dca61c009d 2 new Lobby image, some bugfix (#468)
* +2 lobby screens

* Update goblin.yml

* workbench recipes remove nesting

* tips update

* Update sewing_table.yml
2024-09-28 01:29:02 +03:00
PJBot
b5a7326160 Automatic changelog update 2024-09-27 19:05:30 +00:00
deltanedas
7d4ea967e0 remove thief figurine objective (#32413)
* make figurine objective just 1

* remove the objective entirely

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-09-27 21:04:22 +02:00
PJBot
4e860952d7 Automatic changelog update 2024-09-27 10:05:01 +00:00
LittleNorthStar
bbf84d0346 Feature/grey trenchcoat for detective loadout (#32380)
* Detective grey coat available in loadout

* Revert "Detective grey coat available in loadout"

This reverts commit 3697e15518b300cbc110872dc92d7905b7ef2605.

* Reapply "Detective grey coat available in loadout"

This reverts commit 8e5f43a035d70a7076ba26d43ed683b135af1d99.

* Hoping I got this right?

* Fixing a oversight

* Update Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml

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

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-27 12:03:54 +02:00
Ed
560c7acc52 Merge pull request #465 from crystallpunk-14/ed-27-09-2024-upstream
Ed 27 09 2024 upstream
2024-09-27 11:27:09 +03:00
Ed
34adcd5e2a Update cp14-ignoredPrototypes.yml 2024-09-27 10:48:56 +03:00
Ed
558b38e51d Update ContentAudioSystem.CP14AmbientLoop.cs 2024-09-27 10:46:15 +03:00
Ed
b9e90f50ca nospawn 2024-09-27 10:35:21 +03:00
PJBot
88ccc191b9 Automatic changelog update 2024-09-27 07:23:24 +00:00
Fildrance
4bcf3c3c0e Station AI ability to electricute doors (#32012)
* Boom! Emergency access!

* Emergency access sound

* locale

* Updated sounds

* bleh

* Door electrify base

* feat: popups on attempt to activate AI action when wires cut

* refactor: use SharedApcPowerReceiverComponent to check if AI can interact with door

* refactor: added icon and sound for door overcharge

* meta.json should use tabs not spaces

* refactor: extracted sounds for airlock overcharge to static field in system

* refactor: cleanup, ScarKy0 mentions for resources

* refactor: removed unused textures

* feat: now notification is displayed when AI attempting to interact with door which have wire cut

* StationAiWhitelistComponent is properly gating  BUI OnMessageAttempt, SharedPowerReceiverSystem.IsPowered is now used to check if device powered

* refactor: use PlayLocal to play electrify sound only for AI player

* refactor: SetBoltsDown now uses TrySetBoltDown, checks for power.

* bolts now check for power using SharedPowerReceiverSystem

* electrify localization and louder electrify sounds

* extracted ShowDeviceNotRespondingPopup, reverted airlocks not opening/closing when ai wire was cut

* refactor: cleanup

* New sprites and fixes

* Copyright

* even more sprite changes

* refactore: cleanup, rename overcharge => electrify

---------

Co-authored-by: ScarKy0 <scarky0@onet.eu>
Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-09-27 17:22:17 +10:00
Ed
1df3ed177b Merge remote-tracking branch 'upstream/master' into ed-27-09-2024-upstream
# Conflicts:
#	Content.Server/Explosion/EntitySystems/TriggerSystem.cs
2024-09-27 10:22:05 +03:00
PJBot
0d26bb0320 Automatic changelog update 2024-09-27 07:13:17 +00:00
metalgearsloth
bc461b91a5 Predict stripping (#32478)
* Predict stripping

Stops mob verbs from getting moved around again.

* Bola

* Fix ftl
2024-09-27 17:12:10 +10:00
PJBot
2e03787b6c Automatic changelog update 2024-09-27 07:10:24 +00:00
metalgearsloth
f46f5e2835 Fix storage area pickup sound playing multiple times (#32397) 2024-09-27 17:09:17 +10:00
PJBot
bee66eddef Automatic changelog update 2024-09-27 06:11:33 +00:00
metalgearsloth
b1e69ee84d Fix airlock autoclose mispredict (#32477)
* Fix airlock autoclose mispredict

It was hard to see this ingame due to animations masking it. The only way you'd notice currently is the light mispredicting.

* cudin
2024-09-27 16:10:27 +10:00
PJBot
b8d7733640 Automatic changelog update 2024-09-27 05:50:28 +00:00
august-sun
b9b0c10361 Fixed collision for gas and volumetric pumps (#32471)
Removed BaseMachinePowered from Gas and Volumetric pumps

Co-authored-by: august-sun <45527070+august.sun@users.noreply.github.com>
2024-09-27 15:49:20 +10:00
Spessmann
af3ea5253a Cog update (power fix/grav) (#32475)
* became real

* fixed 32456
2024-09-26 23:20:47 -06:00
Ed
c2704165d3 Loadout update (#461)
* some full species sprite

* floral wreath

* alchemist cloak, loadout restruct

* giant head clothing refactor

* Update entities.ftl

* backpacks loadout! yay

* trinkets

* Update general.yml

* oopsie

* Update general.yml

* fixes

* Delete test-ship.yml
2024-09-27 00:36:09 +03:00
PJBot
bf80f3abb8 Automatic changelog update 2024-09-26 16:57:07 +00:00
beck-thompson
fe2145d3b9 Voice Mask refactor (#30798)
* First commit

* Added base.Initialize()

* Voice wire fix (Electricty name)

* Various minor cleanups

* Localized default voice mask name

* Added VoiceOverride stuff

* Removed unused stuff

* Typo

* Better localized stuff

* Typo / spelling stuff / comments

* Blessed
2024-09-26 18:55:59 +02:00
PJBot
c2bc821e55 Automatic changelog update 2024-09-26 16:33:21 +00:00
SlamBamActionman
eeadc75b0a Add Votekick functionality (#32005) 2024-09-26 18:32:13 +02:00
Ed
038201bfde Ed 26 09 2024 server fix 2 (#460)
* fix server rules

* update tavern map, add arena

* Update exp_tavern.yml

* Update arenas.yml
2024-09-26 19:14:47 +03:00
Ed
622f1a23f3 fix Game map, set only Sandbox Gamemode, add game rules (#459)
* fix map and gamemod, add rule file

* move
2024-09-26 17:35:21 +03:00
Ed
d8263f0298 Shield Parry (#456)
* simple parry disarm

* idk, need testing

* parry fix
2024-09-26 16:59:22 +03:00
PJBot
4491550a5e Automatic changelog update 2024-09-26 12:47:24 +00:00
Ilya246
fd1f4a3929 lower frezon/n2o sale prices, make frezon take more trit (#32407)
* lower gas prices

* set trit ratio from 1:50 to 1:8
2024-09-26 14:46:17 +02:00
Ed
a92c623672 Fences update (#458)
* small fences update

* Update wooden_fence.yml

* reparent all fences, fix high fence

* iron grille fix

* migration

* Update migration.yml

* construction recipes

* Update migration.yml

* fix dev map

* Update migration.yml

* Update migration.yml

* Update migration.yml
2024-09-26 14:57:24 +03:00
Velcroboy
0f729bca0d Makes BaseAdvancedPen abstract (#32454)
Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
2024-09-26 12:58:18 +02:00
PJBot
9c2fe85d47 Automatic changelog update 2024-09-25 17:40:55 +00:00
BramvanZijp
548973bc1f Fix Doctors Delight metabolism Rate (#32297)
* Fix Doctors Delight metabolism Rate

* Combine Drink and Medicine instead of halving their motabolism rate.

* Removed unintentional newline.

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

* Remove metabolismRate since it is setting it to the default.

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

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-25 19:39:49 +02:00
PJBot
5a585f70e5 Automatic changelog update 2024-09-25 17:28:36 +00:00
august-sun
b2dad9ff90 Makes the rolling pin craftable (#32285)
* Makes the rolling pin craftable

* Update Resources/Prototypes/Recipes/Crafting/Graphs/improvised/rolling_pin.yml

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

---------

Co-authored-by: august-sun <45527070+august.sun@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-25 19:27:30 +02:00
PJBot
92c5c873d4 Automatic changelog update 2024-09-25 16:50:51 +00:00
Vasilis
6459f7156b Remove binary channel access to silicons without laws. (#32385)
Mostly feature proofing but these should not have binary access. ESPECIALLY pais

Say we had malf ai and it was talking with other borgs about its plans. The owner of the pai (or any of these silicons) can just listen into this. Someone can just wake up a pai and ask it to monitor the binary channel. There's a reason the binary radio chip is a syndicate item.

Some of these also have no reason to be able to talk on binary, are you gonna ask the ai to bother someone to refill your vend stock? Are you gonna clown with the AI and other borgs as a clown borg and annoy them?
2024-09-25 18:49:43 +02:00
PJBot
d2ed93ed62 Automatic changelog update 2024-09-25 15:42:42 +00:00
themias
e0a3d3d91a Fix agent ID card unlimited range (#32445)
* Fix agent ID card unlimited range

* update order to be more optimized
2024-09-25 17:41:34 +02:00
keronshb
7168959929 Adds real-time charge & disabled action information to Actions (#31821) 2024-09-25 10:27:28 -04:00
Zylofan
0dedc9d91a Skull Helm Hand Sprite now turns (#32442)
Fixed a typo for the bone helmet that made it not rotate when held in the right hand.
2024-09-25 20:50:15 +10:00
Jaraten
693ba93e44 Content pack jr (#457)
* 24.09.24

* wallpapers

* backpack parenting setup

* goblin backpack

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-09-25 12:31:31 +03:00
PJBot
31c45d6169 Automatic changelog update 2024-09-25 05:22:30 +00:00
goet
d1812c11fd Fix contraband never getting added to vend inventory (#32431)
* fix contraband never getting added to vend inventory

* Revert "fix contraband never getting added to vend inventory"

This reverts commit e7fb3a60c3cb6fcbf41d7f015f13dbc7b1c1901d.

* readd setter method to system

* fix again without reparenting
2024-09-25 15:21:24 +10:00
PJBot
52e85fe726 Automatic changelog update 2024-09-24 21:59:53 +00:00
Moomoobeef
55366dc594 Most papers are no longer trash (#32343)
most papers are not trash anymore
2024-09-24 23:58:46 +02:00
Brandon Hu
95a159f950 fix(BatterySelfRecharger): Fully charge BatterySelfRechargers (#30627) 2024-09-24 23:37:45 +02:00
Ed
6b6a96e8d6 Create CP14Publish.yml 2024-09-25 00:08:42 +03:00
PJBot
89dbef7461 Automatic changelog update 2024-09-24 20:44:08 +00:00
Pieter-Jan Briers
e36d735064 Fix cartesian explosion in pref loading (#32434)
Lol .AsSingleQuery().

Some people's preferences wouldn't load on Lizard. Turns out the entire preferences set is loaded with a morbillion joins in a single query and one person had 240,000 (!!!) rows returned for their preferences query. Yeah.
2024-09-24 22:43:02 +02:00
Ed
75bc6d4eac Doors update (#455)
* sprites

* mirrored + windowed wooden doors

* cooking table sprite

* craftable doors
2024-09-24 21:19:52 +03:00
PJBot
4bca634ff6 Automatic changelog update 2024-09-24 17:03:58 +00:00
ArchRBX
241be37185 AstroNav GPS Cartridge (#32194)
* initial commit

* adds astronav cartridge to QM locker

* changes requested in review

* fix merge conflicts

* fixes the statuscontrol disappearing if you eject the cartridge but still have it installed

* fix notificationsenabled on salv pda proto

* fixes lingering statuscontrol on eject while held

---------

Co-authored-by: archrbx <punk.gear5260@fastmail.com>
2024-09-24 19:02:51 +02:00
PJBot
f3e185c063 Automatic changelog update 2024-09-24 15:49:38 +00:00
Milon
042f0d3f47 fix paper staying on fire forever (#32412)
okay who did that
2024-09-24 17:48:32 +02:00
PJBot
057de0cb10 Automatic changelog update 2024-09-24 15:20:46 +00:00
lzk
87932bce57 craftable freezers (#32277)
* Craftable freezers

* oh i forgot that
2024-09-24 17:19:40 +02:00
PJBot
b883f79660 Automatic changelog update 2024-09-24 15:08:06 +00:00
LordEclipse
efd989435e Antimov in both Traitor & Nukie Uplinks (#31916)
Adds Antimov AI Lawboard to Uplinks Automatic changelog update

Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2024-09-24 17:06:58 +02:00
PJBot
49d4e4c465 Automatic changelog update 2024-09-24 14:24:56 +00:00
Dvir
50395e25cf Allow AreaInsert pickups for one item (#32153)
Update SharedStorageSystem.cs
2024-09-24 16:23:48 +02:00
Ed
07637bd691 Prototypes cleaning: destructable, flammable (#453)
* damage rethinking, bush fix

* flammable rethink

* trying to fix fire

* airtight false default

* autoignite

* Update fire.yml

* Update fire.yml

* Update fire.yml
2024-09-24 13:46:26 +03:00
Tornado Tech
f3e9209af5 Added CP14 options menu (#454) 2024-09-24 13:30:19 +03:00
spanky-spanky
9d75a228c0 Add missing LV cables in Omega atmos (#32417)
Adds missing LV wire in atmos burn chambers.
2024-09-23 22:48:14 -06:00
PJBot
dc4d638ce9 Automatic changelog update 2024-09-24 00:32:14 +00:00
Myra
f1bd0be772 Remove all command age requirements (#32340)
From what I can tell this was merged with this on accident.

Maintainers see the maint review thread on this.

The original pr also claimed this was as an example.

In my opinion wizden should not have an age requirement for command.
2024-09-24 02:31:08 +02:00
Pieter-Jan Briers
1450d76337 Fix OOC not re-enabling if restartroundnow is used (#32401)
The ChatSystem code for re-enabling OOC only ran during PostRound, which gets skipped over when doing restartroundnow. Now it does this on PreRoundLobby too.
2024-09-24 09:38:09 +10:00
eoineoineoin
594aad0fa9 Paper QOL improvements (#32418)
* Don't add newlines (fixes #32357)

* Improve UI around max paper length (Fixes #32344)

* Display a "fill progress" indicator so users know how close they are to filling it
* Don't allow users to save a paper which went over the limit, to avoid them losing data they want to keep.

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-09-24 09:36:05 +10:00
PJBot
d0bb408678 Automatic changelog update 2024-09-23 21:50:41 +00:00
lzk
95104de117 Fix cadet pda (#32399) 2024-09-23 23:49:34 +02:00
Brandon Hu
20bb9ede11 fix(contraband): Make contraband work with chameleon items (#30986)
* formatting

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-23 22:19:15 +02:00
spanky-spanky
5e9a0c9d9d Omega Minor Sec Update (#32410)
* Updated Omega armory and Warden office.

* Adjusted walls, a decal, and an air sensor.
2024-09-23 10:17:45 -06:00
Ed
468e3c9f69 Some issues (#452)
* possible UI theming fix

* gob blood

* filter guidebooks by Culture settings

* deleted lobby track
2024-09-23 18:34:04 +03:00
Ed
ecdb02650b Update README.md 2024-09-23 17:30:49 +03:00
PJBot
31db37e826 Automatic changelog update 2024-09-23 13:09:17 +00:00
Jophire
24140d8c8a VIM have Passenger Access. (#32302)
* Revert "Update mechs.yml"

This reverts commit 4a44065b11c427581462a9bfa46fc66ff8878cf4.

* Reapply "Update mechs.yml"

This reverts commit fb5db29f4ae58106180ac836d01f953b816e7a61.

* Revert "Reapply "Update mechs.yml""

This reverts commit c845b6bb3d3e6e80ce7a8aa290b10e2f71bca726.

* Reapply "Reapply "Update mechs.yml""

This reverts commit 41b8934fd100337c31b26fc5e269f65e1f459970.

* VIM Door Stuck Fix

Vim No longer gets stuck in doors.

* VIM has Passenger Access

Debug Tested on the wrong map. Much easier solution. Just give the mech Access tags.

* Moved tags to proper VIM.

Moved access tag to the non-admin VIM.
2024-09-23 15:08:10 +02:00
comasqw
8e27ef22ed Local helper update (#420)
* local helper update

* Delete entities.ftl

* Helper Refactor

* Revert "Helper Refactor"

This reverts commit 4aca315593.

* Helper Refactor

* Жееесть, я не знал про setdefault у словарей

* Update localization_helper.py

* Ревёрт "Жееесть, я не знал про setdefault у словарей"

Лучше бы я продолжал не знать о них

* чтооооо

* Update yml_parser.py

* Update entities.ftl

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-09-23 15:43:02 +03:00
Ed
0456d40bef Content pack (#444)
* cable sprite

* steel plates

* iron wall

* vladimirs resprite

* resprite cables

* cable item

* lv cable finish

* round table

* curtains! (need resprite)

* plates + cucumbers

* more procedural cooking

* some tweaks

* fix test

* пипяу

* finish

* ah

* l

* pip

* some cool

* hide station ai

* revert localization

* Update crates.yml

* Update crates.yml

* red and blue curtains

* Update crates.yml

* Update crates.yml

* fix cupboard

* Update exp_tavern.yml

* fix sliceable recursion
2024-09-23 14:53:03 +03:00
PJBot
16c46af6c5 Automatic changelog update 2024-09-23 11:13:29 +00:00
lzk
aab423667e Fix guidebook books don't have damage (#32403) 2024-09-23 13:12:23 +02:00
PJBot
0a3273a436 Automatic changelog update 2024-09-23 10:52:54 +00:00
Errant
a7e29f2878 Computer wirepanel (#32273)
* Computer wirehacking

* Power wire now shocks

* deconstruction fix

* updated tests

* Better parenting

* maintenance panel sprite

* new sprite for maintenance panel open
2024-09-23 12:51:48 +02:00
PJBot
b6845defa0 Automatic changelog update 2024-09-23 07:29:48 +00:00
Leon Friedrich
caf34be616 Entity menu lookup changes (#32395) 2024-09-23 17:28:42 +10:00
PJBot
c4b8260f23 Automatic changelog update 2024-09-23 06:50:05 +00:00
Cojoke
3d2aadde1f L6 Fits in the Suit Storage Slot (#30525)
* L6 Fits in the Suit Storage Slot

* 5x4 item
2024-09-23 16:48:58 +10:00
PJBot
ad6c5a1ce9 Automatic changelog update 2024-09-23 04:56:38 +00:00
metalgearsloth
b2cb813f54 Include container ents in examine (#32267)
Mainly for closets but if it's like a mouse in a bag they can see what's in the bag type deal.
2024-09-23 14:55:30 +10:00
metalgearsloth
dd7884ed40 Predict vending machine BUI (#32376) 2024-09-23 12:10:22 +10:00
IProduceWidgets
5e162e776d Add the Syndicate Instigator Shuttle (#32083)
* Instigator

* sustenance
2024-09-22 17:27:48 -07:00
Killerqu00
8a2c69d18d reach update :3 (#32387) 2024-09-22 14:08:56 -06:00
PJBot
ee393a1cd8 Automatic changelog update 2024-09-22 20:01:02 +00:00
PotentiallyTom
d3ff4d5401 Makes it possible to disable the vent pressure lockout temporarily with a screwdriver (#31050)
* builds

* doesn't crash

* seems to work

* distance cap was dumb

* Requested changes

* can't find any issues from making the changes

* Check for anchor and minor optimisation

* Removed unnecessary usings

* Code less verbose and cleanup
2024-09-22 21:59:56 +02:00
PJBot
f8514e7815 Automatic changelog update 2024-09-22 15:16:18 +00:00
saga3152
1e466579fa Lemons, limes, and oranges can now be mutated into each other (#32306) 2024-09-22 17:15:12 +02:00
Soydium
932af69c31 added the ability for pigs to feed themselves (#32358)
* pigs can eat

* disable carcinisation
2024-09-22 14:26:55 +02:00
PJBot
b78156ac08 Automatic changelog update 2024-09-22 10:34:14 +00:00
ravage
1aea1ae76f Adding a holy watermelon helmet (#32272)
* lolkekhatholy

alalalla

* animationcreate

blelebleblbeleb
2024-09-22 12:33:08 +02:00
PJBot
8ed779bc02 Automatic changelog update 2024-09-22 08:22:48 +00:00
metalgearsloth
8f06155028 Make buckle mint (#32370)
- Fix the unbuckle mispredicts.
- Fix unbuckle offset existing.
- Fix interaction range not aligning with interactionoutline system.
2024-09-22 18:21:40 +10:00
AsnDen
72acce5200 AI now "can" use media console (#32334) 2024-09-22 18:20:49 +10:00
github-actions[bot]
4f5255bdcb Update Credits (#32362)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2024-09-22 13:19:38 +10:00
PJBot
49f177299e Automatic changelog update 2024-09-21 23:23:00 +00:00
Plykiya
1b81ce4b53 Rat kings can butcher things (#32232)
* rat kings can butcher things

* minor organization

* fix

* important comma
2024-09-22 01:21:52 +02:00
Ilya246
cd761eae69 fix cargo order scams, fix internals crate desc (#32350)
fix description, fix scams
2024-09-21 22:51:20 +02:00
PJBot
6a11dd04d4 Automatic changelog update 2024-09-21 19:56:02 +00:00
Ed
2ea54b1913 Flora anomaly seeds (#31987)
* content

* Update meta.json

* Update mobspawn.yml

* Update mobspawn.yml

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

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

* Update Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml

* Update Resources/Prototypes/Entities/Effects/mobspawn.yml

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-21 21:54:56 +02:00
voidnull000
3cc7fd405b Fix a spelling mistake in the DonutVend's advertisments (#32348)
change that one line so i never think about this again
2024-09-21 14:56:00 +02:00
lzk
5f5bed8fa7 Add skirt of life in contraband medidrobe (#32214) 2024-09-21 11:33:28 +02:00
PJBot
3501d49029 Automatic changelog update 2024-09-21 07:34:28 +00:00
TGRCDev
d32c42f754 Added a directory to station maps (#31156)
* Added directory to station maps

* Add null checks to map directory sorting/filtering

* Reworked station map directory to be more readable and responsive
2024-09-21 09:33:22 +02:00
PJBot
29e56becb8 Automatic changelog update 2024-09-21 05:55:56 +00:00
goet
24ed1f71f6 Fix medical PDA/health analyzer long range intel bug (#31879)
* hide spriteview from health analyzer while inactive

* add out of range indicator if analyzer becomes inactive

* hide out of range icon if there is no patient data
2024-09-21 15:54:48 +10:00
PJBot
c5d62ce751 Automatic changelog update 2024-09-20 22:28:49 +00:00
saga3152
3e92eb1910 Soda water and Vodka recipes (#32252)
* SodaWater and Vodka recipes

* Changed crystals recipe in fun.yml

* plasma is now a catalyst to create crystals

* Revert "plasma is now a catalyst to create crystals"

This reverts commit 1002d9927a3597f7a02611071ef3f706cd056a41.

* Revert "Changed crystals recipe in fun.yml"

This reverts commit 30b6b602228ec1b11a46e390c6a5868494e2b61f.

* Stir to make Vodka

* Shake to make soda water

* fix
2024-09-21 00:27:41 +02:00
Golden Can
2955dd5009 Security Clown Mask is now security restricted. (#32335)
made security clown masks security contraband.
2024-09-20 20:24:06 +02:00
PJBot
c4d12df04c Automatic changelog update 2024-09-20 14:44:03 +00:00
cohanna
e964e9c98e Psychologist's Stamp (#31881)
* added sprite and began implementation

* fixed sprite name, fixed meta files

* silly whitespace

* added paper-stamp file

* figured out where to add the componet, added 'credits'

* spelling is hard

* hmm

* GAHHHHH

* how did i do this again
2024-09-20 16:42:57 +02:00
eoineoineoin
6d5ac1e9b6 Fix disposal units flushing too soon after power-on (#32314)
* Don't flush disposals immediately on power-on

* Update Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-09-20 21:58:26 +10:00
sativaleanne
1567af6f07 Rolebanlist command UI (#30827)
* rolebanlist command opens ui

* removed commented out section
2024-09-20 21:49:31 +10:00
eoineoineoin
a9b5e39fb0 Disable resizing of lobby character editor (#32313)
No resizing character editor

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-09-20 21:47:29 +10:00
Ilya246
00002fa07f fix issues with proximity beeper (#32322)
implement
2024-09-20 21:37:06 +10:00
PJBot
99101f2e2c Automatic changelog update 2024-09-20 04:10:08 +00:00
JIPDawg
b81c7a478e Make small clamp use 2% battery instead of recharging 2% battery. (#32320)
Make small clamp user 2% battery instead of recharge 2% battery.

Co-authored-by: JIPDawg <JIPDawg93@gmail.com>
2024-09-19 22:09:00 -06:00
spanky-spanky
fba67979c8 Modifications to bring Omega up to date. (#32317) 2024-09-19 22:07:49 -06:00
Spessmann
2d42a6bf98 Cog update (Mail) (#32315)
make mailing better
2024-09-19 21:55:48 -06:00
PJBot
7aae8c0099 Automatic changelog update 2024-09-19 23:28:29 +00:00
PopGamer46
1a601c49a5 Makes the rat king's cheeseEm order more convenient to use (#32181)
more convenient cheeseem
2024-09-20 01:27:23 +02:00
PJBot
d74d44acff Automatic changelog update 2024-09-19 22:16:52 +00:00
Plykiya
24c412f16e Removes cockroach/mothroach melee damage (#32221)
no more cockroach and mothroach damage
2024-09-20 00:15:45 +02:00
PJBot
937940bcc7 Automatic changelog update 2024-09-19 19:18:28 +00:00
Saphire Lattice
3e1c067c41 Fland change - Add glasslocks to the Contiguous Fland Hallway Volume (#32264)
* Add glasslocks to the Contiguous Fland Hallway Volume

* Fix up the firelocks, hopefully!
2024-09-19 13:17:18 -06:00
PJBot
b32bdbf8e9 Automatic changelog update 2024-09-19 14:09:39 +00:00
Plykiya
d5d6fb51aa Allows you to buckle transfer person from bed to bed (#32089)
* unbuckle if the target is buckled

* better way to do it
2024-09-20 00:08:33 +10:00
PJBot
30ac40f088 Automatic changelog update 2024-09-19 14:03:00 +00:00
Winkarst
0093fce5b4 Dialog windows now grab the keyboard focus (#31294)
* Dialog windows now grab the keyboard focus

* Comment
2024-09-20 00:01:54 +10:00
PJBot
90d19367f8 Automatic changelog update 2024-09-19 13:56:37 +00:00
deltanedas
fdfbd74bcb increase thieving beacon range to 2 (#31340)
* increase thieving beacon range to 2

* add obstruction check

* review

* Entity<T?> strikes again

* webedit ops because github died or something

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-09-19 23:55:31 +10:00
lzk
e490b69b4e fix conjugate have in cryo locale string (#31993) 2024-09-19 15:50:59 +02:00
PJBot
bac7093f84 Automatic changelog update 2024-09-19 13:46:12 +00:00
deltanedas
9b9853439c make flare recipe roundstart instead of blueprint (#32303)
* make flare recipe roundstart instead of blueprint

* migrate it

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-09-19 07:45:03 -06:00
Spessmann
cd8ba1d6b3 Cog update (Engineering update) (#32263)
* updated cog atmos and engi

* fixed that

* updated
2024-09-19 07:37:28 -06:00
lzk
37a8c23f79 Update Fland (#32241) 2024-09-19 07:36:29 -06:00
lzk
2e37b1fb2f Update Meta (#32238) 2024-09-19 07:36:12 -06:00
lzk
67b34cf8cf Update Omega (#32237) 2024-09-19 07:35:57 -06:00
IProduceWidgets
3c0be539ec Oasis updoot. (#32133)
* updoooooooooooot

* had to change to closed shutters

* I press wrong button

* ngl logic gates kinda ass to work with

* get linked

* Why is it so easy to place entities twice!?

* camer
2024-09-19 07:35:39 -06:00
PJBot
eb9047982a Automatic changelog update 2024-09-19 10:24:51 +00:00
Errant
854bfd27cb Crew Monitor filter (#31659)
* crewmon filter

* string case matching

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

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2024-09-19 12:23:45 +02:00
PJBot
ccadcc9781 Automatic changelog update 2024-09-19 10:23:08 +00:00
Эдуард
1468cbdb8a Wanted list cartridge (#31223)
* WantedListCartridge has been added

* WantedListCartridge user interface works

* WantedListCartridge is added as standard in some PDAs

* The CriminalRecordsSystem can now also take into account who created the record

* Added offense history table

* Fix of missing loaderUid for a cartridge without installing the program

* Added personalized information about the target

* The crime history has been finalized

* Added StatusList

* The officer's name has been added to the automatic history

* WantedListCartridge has been added to the HOS locker

* WantedListCartridge has been removed from brigmedic's preset programs

* The StealConditionSystem now takes into account whether a cartridge is inserted or installed

* Added target to thief on WantedListCartridge

* Merge fix

* Removing copypaste

* Fix merge 2

* The sprite of WantedListCartridge has been changed

* Update pda.yml

* Fix scrollbar in the history table

* Upstream localization fix

* `StatusList` has been replaced by `ListContainer` with `TextureRect`

* Margin fix
2024-09-19 12:22:02 +02:00
PJBot
75ff65d108 Automatic changelog update 2024-09-19 08:42:31 +00:00
Boaz1111
59a8f4445d adds plasma and uranium arrows (#31241) 2024-09-19 10:41:24 +02:00
Tayrtahn
94ad76fd07 Fix Set Outfit command/verb (#29672)
* Filter Set Outfit menu to exclude loadout sets

* Apply loadouts to job outfits

* Use appropriate species for Urists

* squishy

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-09-19 18:02:37 +10:00
Willhelm53
3acf6b93a1 Padded ItemStatus Text (#29560)
* Back in the saddle again! <(8o)

* if you like my STYLE you should see my SHEETS ;-)

* stylesheet change works for ItemStatusNotHeld but broken for ItemStatus. Just using xaml for now.

* teehee

* beeg

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-09-19 17:51:33 +10:00
ShadowCommander
3fc9f96b75 Move PlaceableSurfaceComponent usages to PlaceableSurfaceSystem (#28384)
* Move placeable check to PlaceableSurfaceSystem

This check stops entities from being inserted into a storage entity
when it has a PlaceableSurfaceComponent.

The entity is instead placed on top of the entity like a table.

* Move SetPlaceable to PlaceableSurfaceSystem

* Update to transform system and consolidate code

* Fix interaction with storage that has a placeable component

* deadlock

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-09-19 17:42:49 +10:00
Leon Friedrich
bdd0561254 Make status effect networking not use TryAddStatusEffect (#28766)
* Make status effect networking not use `TryAddStatusEffect`

* a
2024-09-19 12:21:26 +10:00
IProduceWidgets
550c423181 Clean up solution regen and drain comps (#29777)
* clean up solution regen and drain comps

* Tape applied.

* Update Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs

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

* remain entity

* That has to be a rogue test fail.

---------

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
2024-09-19 12:17:13 +10:00
PJBot
b129629405 Automatic changelog update 2024-09-19 02:16:50 +00:00
Luiz Costa
9c905cd58f Fix TEG acting as infinite energy source on destruction (#29972)
* TEG now checks for power supply before checking for IsFullyBuilt

* Update Content.Server/Power/Generation/Teg/TegSystem.cs

Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
2024-09-19 12:15:44 +10:00
PJBot
c2f0626e02 Automatic changelog update 2024-09-19 01:26:53 +00:00
ArchRBX
1c3cfeeb35 Coordinates under IFF Label on Mass Scanners and Shuttle Consoles (#31501)
* adds coord label beneath iff label

* fixed wrong coordinate system being used

* changes the clamping on the label UI to instead normalise the UI's distance vector from the centre of the screen, fixes corner-hugging

* cleaned up if-statement by moving the calc ahead of it

* fixed clamping, fixed parenting issue, added draw cull on coord label

---------

Co-authored-by: archrbx <punk.gear5260@fastmail.com>
2024-09-19 11:25:47 +10:00
PJBot
0c5a053ae4 Automatic changelog update 2024-09-19 00:24:56 +00:00
Winkarst
c2a201d998 Make fire leave burnt decals on the tiles (#31939)
* Make fire leave burnt decals on the tiles

* License

* Yes

* Update

* Spelling error

* Prototypes reload support

* To array
2024-09-19 10:23:50 +10:00
SlamBamActionman
cc7e5e0150 Allow containment field generators to be enabled on mapinit (#31158)
* Initial commit

* review fix
2024-09-19 10:14:29 +10:00
ShadowCommander
6958789f37 Give prototype refactor (#29697)
* Update GivePrototype

* File scoped namespace

* Change to EntProtoId instead of ProtoId<> for better validation
2024-09-19 10:08:37 +10:00
metalgearsloth
4f77709eed Add flip button to mapping state (#30636) 2024-09-19 10:02:27 +10:00
deltanedas
1c839da604 move TriggerExplosion to shared (#30227)
* move component to shared

* add fake systems

* update server explosion system and remove duplicate transform query

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-09-19 10:01:40 +10:00
deltanedas
84062da128 let FlashArea be called from shared (#30343)
* let FlashArea be called from shared

* untroll

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-09-19 09:58:10 +10:00
PJBot
e6e166405d Automatic changelog update 2024-09-18 23:56:32 +00:00
ShadowCommander
7ceb2d2507 Add a method to get the first available ItemSlot (#29846)
* Add a method to get the first available ItemSlot

* Make TryInsertEmpty use TryGetAvailableSlot

* Add param doc comments
2024-09-19 09:55:53 +10:00
ShadowCommander
d4a5bc8d6b Fix unbuckling others when clicking on the strap entity (#29998)
* Add failing unbuckle InteractHand test

* Skip trybuckle if strap doesn't have space

* Unbuckle others not just user

* Fix test failing due to delay

* Change to raise event instead of calling OnInteractHand

* Add test for buckle and unbuckle on InteractHand

* Add tick delay

* Remove unneeded tick delay and clean up

* Comment code

* Cleanup

* Swap to fastest checks first

* Fix reading empty sequence when there are no buckled entities
2024-09-19 09:55:26 +10:00
PJBot
a8686b3597 Automatic changelog update 2024-09-18 23:01:54 +00:00
deltanedas
2c9a3020ab make epinephrine adrenaline (#32076)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-09-19 01:00:48 +02:00
deltanedas
8a924c84ae add interaction success/failure events (#32216)
* add interaction success/failure events

* pro

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-09-19 00:36:44 +02:00
chavonadelal
ba24ebfb4f Localization cooldown/remaining string in alerts (#32282)
Cooldown localization
2024-09-19 00:21:53 +02:00
PJBot
64aab9e41d Automatic changelog update 2024-09-18 22:00:05 +00:00
beck-thompson
58119bc3f7 Fix recycler eating materials (Salvage mains rejoice) (#32144)
first commit
2024-09-18 23:58:58 +02:00
Skarletto
55b7e3ce0e change jamjar glasses description (#32215)
nerds only please
2024-09-18 23:51:11 +02:00
chavonadelal
6d4177567e Localization of the shuttle call sender (#32286) 2024-09-18 21:16:47 +02:00
chavonadelal
9fad1ab14e Wires ui tooltip localization (#32284)
* Wires ui tooltip localization

* Corrections after review
2024-09-18 21:10:53 +02:00
PJBot
697f4f5ef9 Automatic changelog update 2024-09-18 15:16:42 +00:00
Calecute
ed83593948 Fix guidebook cakebatter recipe (#32276)
Bugfix: Add 5 milk to cake batter recipe in the guidebook to correctly reflect new recipe
2024-09-18 17:15:34 +02:00
AsnDen
489938cdb1 ghost-role-information-silicon-rules (#32275)
changes missing ghost-role-information-rules-default-silicon to ghost-role-information-silicon-rules
2024-09-18 16:54:00 +02:00
Pieter-Jan Briers
b55366cf9b chmod +x publish_multi_request.py (#32274)
Fuck.
2024-09-18 16:09:25 +02:00
Pieter-Jan Briers
8322b1c2d1 New publish workflow for Robust.Cdn (#32222)
This uses multiple API requests to directly send the publish to the CDN server, no more GitHub artifacts.

Faster, less moving parts.

Needs Robust.Cdn 2.2.0
2024-09-18 15:28:09 +02:00
lzk
a1237910c5 Fix bagel vox box (#32208)
Fix vox box on bagel
2024-09-18 10:37:35 +03:00
metalgearsloth
54e4cfecfe Update submodule to 235.0.0 (#32265) 2024-09-18 12:32:16 +10:00
Winkarst
2bceaad785 Use TurfSystem.IsTileBlocked instead of TurfHelpers (#32174)
* Use TurfSystem.IsTileBlocked instead of TurfHelpers

* !
2024-09-18 11:49:37 +10:00
Leon Friedrich
974c08596b Fix AudioSystem nullability checks for engine PR (#32233) 2024-09-18 11:43:30 +10:00
Ed
675a9197f2 Easy IconSmooth spriting (#32210)
* фыр

* Update IconSmoothingTemplate README.txt
2024-09-18 11:41:24 +10:00
Pieter-Jan Briers
eca63a4603 Fix borg defib module throwing an exception (#32260)
ToggleCellDraw was erroneously added to the parent prototype instead of the one that actually has a battery.
2024-09-18 11:40:24 +10:00
Ed
61089355f0 Fix Anomaly infections infinity growing after curing (#32259) 2024-09-18 00:19:34 +02:00
PJBot
870bacbcac Automatic changelog update 2024-09-17 22:11:01 +00:00
Moomoobeef
6fc4e9682c Added a number of new and very nerdy names for the AI (#31951)
* added many new names for AIs

* fixed mistakes

* removed Intel and AMD trademarks. Rip AI named Pentium.
2024-09-18 00:09:55 +02:00
PJBot
60887dd2e5 Automatic changelog update 2024-09-17 19:46:48 +00:00
drakewill-CRL
337af483ca Fix plant mutations carrying over to other plants and future rounds (#32257)
Lists are a reference type, so each component should get a new one, not point at the previous one.

Co-authored-by: PraxisMapper <praxismapper@gmail.com>
2024-09-17 11:45:42 -08:00
PJBot
9afc786573 Automatic changelog update 2024-09-17 16:06:45 +00:00
Ed
dce537df07 fix Tech anomaly loud sounds and superfast flickering (#32245)
Update TechAnomalySystem.cs
2024-09-17 12:05:38 -04:00
PJBot
21bd9df477 Automatic changelog update 2024-09-17 09:50:26 +00:00
Ed
92be69a5ab Anomalous infections (#31876)
* inner anomaly

* anomaly pulse action

* test anom mine

* Update anomalies.yml

* fix action cooldown

* pyro_eyes

* clientsystem

* experiments

* blya

* some telegraphy

* shock eyes!

* shadow eyes

* separate files

* frosty eyes

* fix

* flora eyes

* bluespace eyes

* flesh eyes

* redoing injction

* auto add layers

* пипяу

* new injector component

* stupid me

* nice marker injectors

* anomaly spawn on shutdown

* gravity anom

* dead anomaly spawning

* add VOX states

* sprite specific layers support

* technology anom infection

* auto detach anomalies that have moved away

* Update anomaly_injections.yml

* anomalyspawner integration

* rock anomaly!

* Update anomaly_injections.yml

* fix crash bug

* tag filter

* fix anom dublication spawns

* Update anomaly.yml

* Update InnerBodyAnomalyComponent.cs

* Update anomaly_injections.yml

* dont spawn anomalies after decay

* fix morb sprite, add end message

* gravity resprite

* admin logging, double injection fix

* make flesh and living light mobs friendly to anomaly hosts

* popups

* severity feedback

* sloth review

* A

* keep organs after gib

* punpun host

* sloth synchronization

* Update arachnid.yml

* increase infections spawnrate
2024-09-17 12:49:19 +03:00
1944 changed files with 163095 additions and 59719 deletions

20
.github/workflows/CP14Publish.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Publish
concurrency:
group: publish
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Send POST-request
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.BUILD_HOST }}
username: ${{ secrets.BUILD_USER }}
password: ${{ secrets.BUILD_PASS }}
port: 22
script: sh update.sh &> /dev/null

View File

@@ -5,8 +5,8 @@ concurrency:
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * *'
# schedule:
# - cron: '0 10 * * *'
jobs:
build:
@@ -41,21 +41,10 @@ jobs:
- name: Package client
run: dotnet run --project Content.Packaging client --no-wipe-release
- name: Upload build artifact
id: artifact-upload-step
uses: actions/upload-artifact@v4
with:
name: build
path: release/*.zip
compression-level: 0
retention-days: 0
- name: Publish version
run: Tools/publish_github_artifact.py
run: Tools/publish_multi_request.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
ARTIFACT_ID: ${{ steps.artifact-upload-step.outputs.artifact-id }}
GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }}
- name: Publish changelog (Discord)
@@ -68,8 +57,3 @@ jobs:
run: Tools/actions_changelog_rss.py
env:
CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }}
- uses: geekyeggo/delete-artifact@v5
if: always()
with:
name: build

View File

@@ -51,6 +51,29 @@ namespace Content.Client.Actions
SubscribeLocalEvent<EntityWorldTargetActionComponent, ComponentHandleState>(OnEntityWorldTargetHandleState);
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
var worldActionQuery = EntityQueryEnumerator<WorldTargetActionComponent>();
while (worldActionQuery.MoveNext(out var uid, out var action))
{
UpdateAction(uid, action);
}
var instantActionQuery = EntityQueryEnumerator<InstantActionComponent>();
while (instantActionQuery.MoveNext(out var uid, out var action))
{
UpdateAction(uid, action);
}
var entityActionQuery = EntityQueryEnumerator<EntityTargetActionComponent>();
while (entityActionQuery.MoveNext(out var uid, out var action))
{
UpdateAction(uid, action);
}
}
private void OnInstantHandleState(EntityUid uid, InstantActionComponent component, ref ComponentHandleState args)
{
if (args.Current is not InstantActionComponentState state)
@@ -95,6 +118,8 @@ namespace Content.Client.Actions
component.Icon = state.Icon;
component.IconOn = state.IconOn;
component.IconColor = state.IconColor;
component.OriginalIconColor = state.OriginalIconColor;
component.DisabledIconColor = state.DisabledIconColor;
component.Keywords.Clear();
component.Keywords.UnionWith(state.Keywords);
component.Enabled = state.Enabled;
@@ -125,6 +150,8 @@ namespace Content.Client.Actions
if (!ResolveActionData(actionId, ref action))
return;
action.IconColor = action.Charges < 1 ? action.DisabledIconColor : action.OriginalIconColor;
base.UpdateAction(actionId, action);
if (_playerManager.LocalEntity != action.AttachedEntity)
return;

View File

@@ -101,7 +101,7 @@ namespace Content.Client.Actions.UI
{
var duration = Cooldown.Value.End - Cooldown.Value.Start;
if (!FormattedMessage.TryFromMarkup($"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]", out var markup))
if (!FormattedMessage.TryFromMarkup(Loc.GetString("ui-actionslot-duration", ("duration", (int)duration.TotalSeconds), ("timeLeft", (int)timeLeft.TotalSeconds + 1)), out var markup))
return;
_cooldownLabel.SetMessage(markup);

View File

@@ -1,14 +1,13 @@
using System.Linq;
using System.Numerics;
using Content.Client.UserInterface.Controls;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.UI.SetOutfit
@@ -65,9 +64,18 @@ namespace Content.Client.Administration.UI.SetOutfit
PopulateByFilter(SearchBar.Text);
}
private IEnumerable<StartingGearPrototype> GetPrototypes()
{
// Filter out any StartingGearPrototypes that belong to loadouts
var loadouts = _prototypeManager.EnumeratePrototypes<LoadoutPrototype>();
var loadoutGears = loadouts.Select(l => l.StartingGear);
return _prototypeManager.EnumeratePrototypes<StartingGearPrototype>()
.Where(p => !loadoutGears.Contains(p.ID));
}
private void PopulateList()
{
foreach (var gear in _prototypeManager.EnumeratePrototypes<StartingGearPrototype>())
foreach (var gear in GetPrototypes())
{
OutfitList.Add(GetItem(gear, OutfitList));
}
@@ -76,7 +84,7 @@ namespace Content.Client.Administration.UI.SetOutfit
private void PopulateByFilter(string filter)
{
OutfitList.Clear();
foreach (var gear in _prototypeManager.EnumeratePrototypes<StartingGearPrototype>())
foreach (var gear in GetPrototypes())
{
if (!string.IsNullOrEmpty(filter) &&
gear.ID.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant()))

View File

@@ -20,8 +20,9 @@ public sealed class AnomalySystem : SharedAnomalySystem
SubscribeLocalEvent<AnomalyComponent, AppearanceChangeEvent>(OnAppearanceChanged);
SubscribeLocalEvent<AnomalyComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<AnomalyComponent, AnimationCompletedEvent>(OnAnimationComplete);
}
SubscribeLocalEvent<AnomalySupercriticalComponent, ComponentShutdown>(OnShutdown);
}
private void OnStartup(EntityUid uid, AnomalyComponent component, ComponentStartup args)
{
_floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime);
@@ -75,4 +76,13 @@ public sealed class AnomalySystem : SharedAnomalySystem
}
}
}
private void OnShutdown(Entity<AnomalySupercriticalComponent> ent, ref ComponentShutdown args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
sprite.Scale = Vector2.One;
sprite.Color = sprite.Color.WithAlpha(1f);
}
}

View File

@@ -0,0 +1,50 @@
using Content.Shared.Anomaly.Components;
using Content.Shared.Anomaly.Effects;
using Content.Shared.Body.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Anomaly.Effects;
public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
{
public override void Initialize()
{
SubscribeLocalEvent<InnerBodyAnomalyComponent, AfterAutoHandleStateEvent>(OnAfterHandleState);
SubscribeLocalEvent<InnerBodyAnomalyComponent, ComponentShutdown>(OnCompShutdown);
}
private void OnAfterHandleState(Entity<InnerBodyAnomalyComponent> ent, ref AfterAutoHandleStateEvent args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
if (ent.Comp.FallbackSprite is null)
return;
if (!sprite.LayerMapTryGet(ent.Comp.LayerMap, out var index))
index = sprite.LayerMapReserveBlank(ent.Comp.LayerMap);
if (TryComp<BodyComponent>(ent, out var body) &&
body.Prototype is not null &&
ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite))
{
sprite.LayerSetSprite(index, speciesSprite);
}
else
{
sprite.LayerSetSprite(index, ent.Comp.FallbackSprite);
}
sprite.LayerSetVisible(index, true);
sprite.LayerSetShader(index, "unshaded");
}
private void OnCompShutdown(Entity<InnerBodyAnomalyComponent> ent, ref ComponentShutdown args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
var index = sprite.LayerMapGet(ent.Comp.LayerMap);
sprite.LayerSetVisible(index, false);
}
}

View File

@@ -306,6 +306,9 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
.WithMaxDistance(comp.Range);
var stream = _audio.PlayEntity(comp.Sound, Filter.Local(), uid, false, audioParams);
if (stream == null)
continue;
_playingSounds[sourceEntity] = (stream.Value.Entity, comp.Sound, key);
playingCount++;

View File

@@ -67,7 +67,7 @@ public sealed class ClientGlobalSoundSystem : SharedGlobalSoundSystem
if(!_adminAudioEnabled) return;
var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams);
_adminAudio.Add(stream.Value.Entity);
_adminAudio.Add(stream?.Entity);
}
private void PlayStationEventMusic(StationEventMusicEvent soundEvent)
@@ -76,7 +76,7 @@ public sealed class ClientGlobalSoundSystem : SharedGlobalSoundSystem
if(!_eventAudioEnabled || _eventAudio.ContainsKey(soundEvent.Type)) return;
var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams);
_eventAudio.Add(soundEvent.Type, stream.Value.Entity);
_eventAudio.Add(soundEvent.Type, stream?.Entity);
}
private void PlayGameSound(GameGlobalSoundEvent soundEvent)

View File

@@ -214,9 +214,9 @@ public sealed partial class ContentAudioSystem
false,
AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider));
_ambientMusicStream = strim.Value.Entity;
_ambientMusicStream = strim?.Entity;
if (_musicProto.FadeIn)
if (_musicProto.FadeIn && strim != null)
{
FadeIn(_ambientMusicStream, strim.Value.Component, AmbientMusicFadeTime);
}

View File

@@ -80,6 +80,10 @@ public sealed partial class ContentAudioSystem
.WithLoop(true)
.WithVolume(proto.Sound.Params.Volume + _volumeSlider)
.WithPlayOffset(_random.NextFloat(0f, 100f)));
if (newLoop is null)
return;
_loopStreams.Add(proto, newLoop.Value.Entity);
FadeIn(newLoop.Value.Entity, newLoop.Value.Component, AmbientLoopFadeInTime);

View File

@@ -20,7 +20,6 @@ public sealed partial class ContentAudioSystem
{
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, 0, 0, 0, false, 0f);
@@ -71,7 +70,7 @@ public sealed partial class ContentAudioSystem
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
_stateManager.OnStateChanged += StateManagerOnStateChanged;
_state.OnStateChanged += StateManagerOnStateChanged;
_client.PlayerLeaveServer += OnLeave;
@@ -115,7 +114,7 @@ public sealed partial class ContentAudioSystem
private void LobbyMusicCVarChanged(bool musicEnabled)
{
if (musicEnabled && _stateManager.CurrentState is LobbyState)
if (musicEnabled && _state.CurrentState is LobbyState)
{
StartLobbyMusic();
}
@@ -185,7 +184,7 @@ public sealed partial class ContentAudioSystem
false,
_lobbySoundtrackParams.WithVolume(_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
);
if (playResult.Value.Entity == default)
if (playResult == null)
{
_sawmill.Warning(
$"Tried to play lobby soundtrack '{{Filename}}' using {nameof(SharedAudioSystem)}.{nameof(SharedAudioSystem.PlayGlobal)} but it returned default value of EntityUid!",
@@ -234,7 +233,7 @@ public sealed partial class ContentAudioSystem
private void ShutdownLobbyMusic()
{
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
_state.OnStateChanged -= StateManagerOnStateChanged;
_client.PlayerLeaveServer -= OnLeave;

View File

@@ -15,7 +15,6 @@ internal sealed class BuckleSystem : SharedBuckleSystem
{
base.Initialize();
SubscribeLocalEvent<BuckleComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<BuckleComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<StrapComponent, MoveEvent>(OnStrapMoveEvent);
}
@@ -57,21 +56,6 @@ internal sealed class BuckleSystem : SharedBuckleSystem
}
}
private void OnHandleState(Entity<BuckleComponent> ent, ref ComponentHandleState args)
{
if (args.Current is not BuckleState state)
return;
ent.Comp.DontCollide = state.DontCollide;
ent.Comp.BuckleTime = state.BuckleTime;
var strapUid = EnsureEntity<BuckleComponent>(state.BuckledTo, ent);
SetBuckledTo(ent, strapUid == null ? null : new (strapUid.Value, null));
var (uid, component) = ent;
}
private void OnAppearanceChange(EntityUid uid, BuckleComponent component, ref AppearanceChangeEvent args)
{
if (!TryComp<RotationVisualsComponent>(uid, out var rotVisuals))

View File

@@ -0,0 +1,21 @@
using Content.Shared.Timing;
using Content.Shared.Cargo.Systems;
namespace Content.Client.Cargo.Systems;
/// <summary>
/// This handles...
/// </summary>
public sealed class ClientPriceGunSystem : SharedPriceGunSystem
{
[Dependency] private readonly UseDelaySystem _useDelay = default!;
protected override bool GetPriceOrBounty(EntityUid priceGunUid, EntityUid target, EntityUid user)
{
if (!TryComp(priceGunUid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((priceGunUid, useDelay)))
return false;
// It feels worse if the cooldown is predicted but the popup isn't! So only do the cooldown reset on the server.
return true;
}
}

View File

@@ -0,0 +1,30 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.UserInterface;
namespace Content.Client.CartridgeLoader.Cartridges;
public sealed partial class WantedListUi : UIFragment
{
private WantedListUiFragment? _fragment;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new WantedListUiFragment();
}
public override void UpdateState(BoundUserInterfaceState state)
{
switch (state)
{
case WantedListUiState cast:
_fragment?.UpdateState(cast.Records);
break;
}
}
}

View File

@@ -0,0 +1,240 @@
using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Shared.CriminalRecords.Systems;
using Content.Shared.Security;
using Content.Shared.StatusIcon;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Input;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.CartridgeLoader.Cartridges;
[GenerateTypedNameReferences]
public sealed partial class WantedListUiFragment : BoxContainer
{
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly SpriteSystem _spriteSystem;
private string? _selectedTargetName;
private List<WantedRecord> _wantedRecords = new();
public WantedListUiFragment()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
SearchBar.OnTextChanged += OnSearchBarTextChanged;
}
private void OnSearchBarTextChanged(LineEdit.LineEditEventArgs args)
{
var found = !String.IsNullOrWhiteSpace(args.Text)
? _wantedRecords.FindAll(r =>
r.TargetInfo.Name.Contains(args.Text) ||
r.Status.ToString().Contains(args.Text, StringComparison.OrdinalIgnoreCase))
: _wantedRecords;
UpdateState(found, false);
}
public void UpdateState(List<WantedRecord> records, bool refresh = true)
{
if (records.Count == 0)
{
NoRecords.Visible = true;
RecordsList.Visible = false;
RecordUnselected.Visible = false;
PersonContainer.Visible = false;
_selectedTargetName = null;
if (refresh)
_wantedRecords.Clear();
RecordsList.PopulateList(new List<ListData>());
return;
}
NoRecords.Visible = false;
RecordsList.Visible = true;
RecordUnselected.Visible = true;
PersonContainer.Visible = false;
var dataList = records.Select(r => new StatusListData(r)).ToList();
RecordsList.GenerateItem = GenerateItem;
RecordsList.ItemPressed = OnItemSelected;
RecordsList.PopulateList(dataList);
if (refresh)
_wantedRecords = records;
}
private void OnItemSelected(BaseButton.ButtonEventArgs args, ListData data)
{
if (data is not StatusListData(var record))
return;
FormattedMessage GetLoc(string fluentId, params (string,object)[] args)
{
var msg = new FormattedMessage();
var fluent = Loc.GetString(fluentId, args);
msg.AddMarkupPermissive(fluent);
return msg;
}
// Set personal info
PersonName.Text = record.TargetInfo.Name;
TargetAge.SetMessage(GetLoc(
"wanted-list-age-label",
("age", record.TargetInfo.Age)
));
TargetJob.SetMessage(GetLoc(
"wanted-list-job-label",
("job", record.TargetInfo.JobTitle.ToLower())
));
TargetSpecies.SetMessage(GetLoc(
"wanted-list-species-label",
("species", record.TargetInfo.Species.ToLower())
));
TargetGender.SetMessage(GetLoc(
"wanted-list-gender-label",
("gender", record.TargetInfo.Gender)
));
// Set reason
WantedReason.SetMessage(GetLoc(
"wanted-list-reason-label",
("reason", record.Reason ?? Loc.GetString("wanted-list-unknown-reason-label"))
));
// Set status
PersonState.SetMessage(GetLoc(
"wanted-list-status-label",
("status", record.Status.ToString().ToLower())
));
// Set initiator
InitiatorName.SetMessage(GetLoc(
"wanted-list-initiator-label",
("initiator", record.Initiator ?? Loc.GetString("wanted-list-unknown-initiator-label"))
));
// History table
// Clear table if it exists
HistoryTable.RemoveAllChildren();
HistoryTable.AddChild(new Label()
{
Text = Loc.GetString("wanted-list-history-table-time-col"),
StyleClasses = { "LabelSmall" },
HorizontalAlignment = HAlignment.Center,
});
HistoryTable.AddChild(new Label()
{
Text = Loc.GetString("wanted-list-history-table-reason-col"),
StyleClasses = { "LabelSmall" },
HorizontalAlignment = HAlignment.Center,
HorizontalExpand = true,
});
HistoryTable.AddChild(new Label()
{
Text = Loc.GetString("wanted-list-history-table-initiator-col"),
StyleClasses = { "LabelSmall" },
HorizontalAlignment = HAlignment.Center,
});
if (record.History.Count > 0)
{
HistoryTable.Visible = true;
foreach (var history in record.History.OrderByDescending(h => h.AddTime))
{
HistoryTable.AddChild(new Label()
{
Text = $"{history.AddTime.Hours:00}:{history.AddTime.Minutes:00}:{history.AddTime.Seconds:00}",
StyleClasses = { "LabelSmall" },
VerticalAlignment = VAlignment.Top,
});
HistoryTable.AddChild(new RichTextLabel()
{
Text = $"[color=white]{history.Crime}[/color]",
HorizontalExpand = true,
VerticalAlignment = VAlignment.Top,
StyleClasses = { "LabelSubText" },
Margin = new(10f, 0f),
});
HistoryTable.AddChild(new RichTextLabel()
{
Text = $"[color=white]{history.InitiatorName}[/color]",
StyleClasses = { "LabelSubText" },
VerticalAlignment = VAlignment.Top,
});
}
}
RecordUnselected.Visible = false;
PersonContainer.Visible = true;
// Save selected item
_selectedTargetName = record.TargetInfo.Name;
}
private void GenerateItem(ListData data, ListContainerButton button)
{
if (data is not StatusListData(var record))
return;
var box = new BoxContainer() { Orientation = LayoutOrientation.Horizontal, HorizontalExpand = true };
var label = new Label() { Text = record.TargetInfo.Name };
var rect = new TextureRect()
{
TextureScale = new(2.2f),
VerticalAlignment = VAlignment.Center,
HorizontalAlignment = HAlignment.Center,
Margin = new(0f, 0f, 6f, 0f),
};
if (record.Status is not SecurityStatus.None)
{
var proto = "SecurityIcon" + record.Status switch
{
SecurityStatus.Detained => "Incarcerated",
_ => record.Status.ToString(),
};
if (_prototypeManager.TryIndex<SecurityIconPrototype>(proto, out var prototype))
{
rect.Texture = _spriteSystem.Frame0(prototype.Icon);
}
}
box.AddChild(rect);
box.AddChild(label);
button.AddChild(box);
button.AddStyleClass(ListContainer.StyleClassListContainerButton);
if (record.TargetInfo.Name.Equals(_selectedTargetName))
{
button.Pressed = true;
// For some reason the event is not called when `Pressed` changed, call it manually.
OnItemSelected(
new(button, new(new(), BoundKeyState.Down, new(), false, new(), new())),
data);
}
}
}
internal record StatusListData(WantedRecord Record) : ListData;

View File

@@ -0,0 +1,50 @@
<cartridges:WantedListUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True">
<LineEdit Name="SearchBar" PlaceHolder="{Loc 'wanted-list-search-placeholder'}"/>
<BoxContainer Name="MainContainer" Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<Label Name="NoRecords" Text="{Loc 'wanted-list-label-no-records'}" Align="Center" VAlign="Center" HorizontalExpand="True" FontColorOverride="DarkGray"/>
<!-- Any attempts to set dimensions for ListContainer breaks the renderer, I have to roughly set sizes and margins in other controllers. -->
<controls:ListContainer
Name="RecordsList"
HorizontalAlignment="Left"
VerticalExpand="True"
Visible="False"
Toggle="True"
Group="True"
SetWidth="192" />
<Label Name="RecordUnselected"
Text="{Loc 'criminal-records-console-select-record-info'}"
Align="Center"
FontColorOverride="DarkGray"
Visible="False"
HorizontalExpand="True" />
<BoxContainer Name="PersonContainer" Orientation="Vertical" HorizontalExpand="True" SetWidth="334" Margin="5 0 77 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Name="PersonName" StyleClasses="LabelBig" />
<RichTextLabel Name="PersonState" HorizontalAlignment="Right" HorizontalExpand="True" />
</BoxContainer>
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5"/>
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
<BoxContainer Name="DataContainer" Orientation="Vertical">
<RichTextLabel Name="TargetAge" />
<RichTextLabel Name="TargetJob" />
<RichTextLabel Name="TargetSpecies" />
<RichTextLabel Name="TargetGender" />
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5"/>
<RichTextLabel Name="InitiatorName" VerticalAlignment="Stretch"/>
<RichTextLabel Name="WantedReason" VerticalAlignment="Stretch"/>
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5" />
<controls:TableContainer Name="HistoryTable" Columns="3" Visible="False" HorizontalAlignment="Stretch" />
</BoxContainer>
</ScrollContainer>
</BoxContainer>
</BoxContainer>
</cartridges:WantedListUiFragment>

View File

@@ -21,6 +21,16 @@ internal sealed class ChatManager : IChatManager
_sawmill.Level = LogLevel.Info;
}
public void SendAdminAlert(string message)
{
// See server-side manager. This just exists for shared code.
}
public void SendAdminAlert(EntityUid player, string message)
{
// See server-side manager. This just exists for shared code.
}
public void SendMessage(string text, ChatSelectChannel channel)
{
var str = text.ToString();

View File

@@ -2,10 +2,8 @@ using Content.Shared.Chat;
namespace Content.Client.Chat.Managers
{
public interface IChatManager
public interface IChatManager : ISharedChatManager
{
void Initialize();
public void SendMessage(string text, ChatSelectChannel channel);
}
}

View File

@@ -327,7 +327,8 @@ public sealed class ClientClothingSystem : ClothingSystem
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
continue;
_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers);
if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers))
index++;
}
}

View File

@@ -2,7 +2,7 @@ using Content.Shared.Ensnaring;
using Content.Shared.Ensnaring.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Ensnaring.Visualizers;
namespace Content.Client.Ensnaring;
public sealed class EnsnareableSystem : SharedEnsnareableSystem
{
@@ -12,13 +12,14 @@ public sealed class EnsnareableSystem : SharedEnsnareableSystem
{
base.Initialize();
SubscribeLocalEvent<EnsnareableComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<EnsnareableComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnComponentInit(EntityUid uid, EnsnareableComponent component, ComponentInit args)
protected override void OnEnsnareInit(Entity<EnsnareableComponent> ent, ref ComponentInit args)
{
if(!TryComp<SpriteComponent>(uid, out var sprite))
base.OnEnsnareInit(ent, ref args);
if(!TryComp<SpriteComponent>(ent.Owner, out var sprite))
return;
// TODO remove this, this should just be in yaml.

View File

@@ -70,7 +70,6 @@ namespace Content.Client.Entry
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly ContentReplayPlaybackManager _replayMan = default!;
[Dependency] private readonly DebugMonitorManager _debugMonitorManager = default!;
public override void Init()
@@ -192,7 +191,7 @@ namespace Content.Client.Entry
_resourceManager,
ReplayConstants.ReplayZipFolder.ToRootedPath());
_replayMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
_playbackMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
_replayLoad.LoadAndStartReplay(reader);
}
else if (_gameController.LaunchState.FromLauncher)

View File

@@ -2,7 +2,4 @@ using Content.Shared.Explosion.EntitySystems;
namespace Content.Client.Explosion.EntitySystems;
public sealed class ExplosionSystem : SharedExplosionSystem
{
}
public sealed class ExplosionSystem : SharedExplosionSystem;

View File

@@ -16,6 +16,7 @@ namespace Content.Client.Flash
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly SharedFlashSystem _flash;
private readonly StatusEffectsSystem _statusSys;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
@@ -27,6 +28,7 @@ namespace Content.Client.Flash
{
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index<ShaderPrototype>("FlashedEffect").InstanceUnique();
_flash = _entityManager.System<SharedFlashSystem>();
_statusSys = _entityManager.System<StatusEffectsSystem>();
}
@@ -41,7 +43,7 @@ namespace Content.Client.Flash
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
return;
if (!_statusSys.TryGetTime(playerEntity.Value, SharedFlashSystem.FlashedKey, out var time, status))
if (!_statusSys.TryGetTime(playerEntity.Value, _flash.FlashedKey, out var time, status))
return;
var curTime = _timing.CurTime;

View File

@@ -1,9 +0,0 @@
using Content.Shared.GPS;
namespace Content.Client.GPS.Components
{
[RegisterComponent]
public sealed partial class HandheldGPSComponent : SharedHandheldGPSComponent
{
}
}

View File

@@ -1,4 +1,4 @@
using Content.Client.GPS.Components;
using Content.Shared.GPS.Components;
using Content.Client.GPS.UI;
using Content.Client.Items;

View File

@@ -1,4 +1,4 @@
using Content.Client.GPS.Components;
using Content.Shared.GPS.Components;
using Content.Client.Message;
using Content.Client.Stylesheets;
using Robust.Client.GameObjects;
@@ -30,6 +30,13 @@ public sealed class HandheldGpsStatusControl : Control
{
base.FrameUpdate(args);
// don't display the label if the gps component is being removed
if (_parent.Comp.LifeStage > ComponentLifeStage.Running)
{
_label.Visible = false;
return;
}
_updateDif += args.DeltaSeconds;
if (_updateDif < _parent.Comp.UpdateRate)
return;
@@ -44,9 +51,9 @@ public sealed class HandheldGpsStatusControl : Control
var posText = "Error";
if (_entMan.TryGetComponent(_parent, out TransformComponent? transComp))
{
var pos = _transform.GetMapCoordinates(_parent.Owner, xform: transComp);
var x = (int) pos.X;
var y = (int) pos.Y;
var pos = _transform.GetMapCoordinates(_parent.Owner, xform: transComp);
var x = (int)pos.X;
var y = (int)pos.Y;
posText = $"({x}, {y})";
}
_label.SetMarkup(Loc.GetString("handheld-gps-coordinates-title", ("coordinates", posText)));

View File

@@ -5,6 +5,7 @@ using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Controls.FancyTree;
using Content.Client.UserInterface.Systems.Info;
using Content.Shared.Guidebook;
using Content.Shared.Localizations;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@@ -168,6 +169,8 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
foreach (var entry in GetSortedEntries(roots))
{
if (!entry.CrystallPunkAllowed) continue; //CrystallPunk guidebook filter
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallPunk guidebook filter
AddEntry(entry.Id, parent, addedEntries);
}

View File

@@ -21,6 +21,7 @@
Orientation="Vertical">
<BoxContainer Orientation="Horizontal" Margin="0 0 0 5">
<SpriteView OverrideDirection="South" Scale="2 2" Name="SpriteView" Access="Public" SetSize="64 64" />
<TextureRect Name="NoDataTex" Access="Public" SetSize="64 64" Visible="false" Stretch="KeepAspectCentered" TexturePath="/Textures/Interface/Misc/health_analyzer_out_of_range.png"/>
<BoxContainer Margin="5 0 0 0" Orientation="Vertical" VerticalAlignment="Top">
<RichTextLabel Name="NameLabel" SetWidth="150" />
<Label Name="SpeciesLabel" VerticalAlignment="Top" StyleClasses="LabelSubText" />

View File

@@ -73,6 +73,8 @@ namespace Content.Client.HealthAnalyzer.UI
// Patient Information
SpriteView.SetEntity(target.Value);
SpriteView.Visible = msg.ScanMode.HasValue && msg.ScanMode.Value;
NoDataTex.Visible = !SpriteView.Visible;
var name = new FormattedMessage();
name.PushColor(Color.White);

View File

@@ -98,7 +98,7 @@ namespace Content.Client.Inventory
}
}
if (EntMan.TryGetComponent<HandsComponent>(Owner, out var handsComp))
if (EntMan.TryGetComponent<HandsComponent>(Owner, out var handsComp) && handsComp.CanBeStripped)
{
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
// and not gui hands... which are different...
@@ -136,7 +136,7 @@ namespace Content.Client.Inventory
StyleClasses = { StyleBase.ButtonOpenRight }
};
button.OnPressed += (_) => SendMessage(new StrippingEnsnareButtonPressed());
button.OnPressed += (_) => SendPredictedMessage(new StrippingEnsnareButtonPressed());
_strippingMenu.SnareContainer.AddChild(button);
}
@@ -177,7 +177,7 @@ namespace Content.Client.Inventory
// So for now: only stripping & examining
if (ev.Function == EngineKeyFunctions.Use)
{
SendMessage(new StrippingSlotButtonPressed(slot.SlotName, slot is HandButton));
SendPredictedMessage(new StrippingSlotButtonPressed(slot.SlotName, slot is HandButton));
return;
}

View File

@@ -18,8 +18,11 @@ using Content.Client.Viewport;
using Content.Client.Voting;
using Content.Shared.Administration.Logs;
using Content.Client.Lobby;
using Content.Client.Players.RateLimiting;
using Content.Shared.Administration.Managers;
using Content.Shared.Chat;
using Content.Shared.Players.PlayTimeTracking;
using Content.Shared.Players.RateLimiting;
namespace Content.Client.IoC
{
@@ -31,6 +34,7 @@ namespace Content.Client.IoC
collection.Register<IParallaxManager, ParallaxManager>();
collection.Register<IChatManager, ChatManager>();
collection.Register<ISharedChatManager, ChatManager>();
collection.Register<IClientPreferencesManager, ClientPreferencesManager>();
collection.Register<IStylesheetManager, StylesheetManager>();
collection.Register<IScreenshotHook, ScreenshotHook>();
@@ -47,10 +51,12 @@ namespace Content.Client.IoC
collection.Register<ExtendedDisconnectInformationManager>();
collection.Register<JobRequirementsManager>();
collection.Register<DocumentParsingManager>();
collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
collection.Register<ContentReplayPlaybackManager>();
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
collection.Register<MappingManager>();
collection.Register<DebugMonitorManager>();
collection.Register<PlayerRateLimitManager>();
collection.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
}
}
}

View File

@@ -14,7 +14,7 @@
Stretch="KeepAspectCovered" />
<BoxContainer Name="MainContainer" VerticalExpand="True" HorizontalExpand="True" Orientation="Horizontal"
Margin="10 10 10 10" SeparationOverride="2">
<SplitContainer State="Auto" HorizontalExpand="True">
<SplitContainer State="Auto" ResizeMode="NotResizable" HorizontalExpand="True">
<!-- LHS Controls -->
<BoxContainer Name="LeftSide" Orientation="Vertical" SeparationOverride="4" HorizontalExpand="True">
<Control Name="DefaultState" VerticalExpand="True">

View File

@@ -78,6 +78,7 @@
ToolTip="Pick (Hold 5)" />
<mapping:MappingActionsButton Name="Delete" Access="Public"
ToolTip="Delete (Hold 6)" />
<mapping:MappingActionsButton Name="Flip" Access="Public" ToggleMode="False"/>
</BoxContainer>
</PanelContainer>
</LayoutContainer>

View File

@@ -96,6 +96,22 @@ public sealed partial class MappingScreen : InGameScreen
Pick.Texture.TexturePath = "/Textures/Interface/eyedropper.svg.png";
Delete.Texture.TexturePath = "/Textures/Interface/eraser.svg.png";
Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png";
Flip.OnPressed += args => FlipSides();
}
public void FlipSides()
{
ScreenContainer.Flip();
if (SpawnContainer.GetPositionInParent() == 0)
{
Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png";
}
else
{
Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png";
}
}
private void OnDecalColorPicked(Color color)

View File

@@ -15,6 +15,9 @@
</PanelContainer>
</controls:StripeBack>
<LineEdit Name="SearchLineEdit" HorizontalExpand="True"
PlaceHolder="{Loc crew-monitor-filter-line-placeholder}" />
<ScrollContainer Name="SensorScroller"
VerticalExpand="True"
SetWidth="520"

View File

@@ -156,6 +156,11 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
// Populate departments
foreach (var sensor in departmentSensors)
{
if (!string.IsNullOrEmpty(SearchLineEdit.Text)
&& !sensor.Name.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase)
&& !sensor.Job.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase))
continue;
var coordinates = _entManager.GetCoordinates(sensor.Coordinates);
// Add a button that will hold a username and other details

View File

@@ -1,149 +0,0 @@
using System.Numerics;
using Content.Client.Buckle;
using Content.Client.Gravity;
using Content.Shared.ActionBlocker;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
namespace Content.Client.Movement.Systems;
public sealed class WaddleAnimationSystem : SharedWaddleAnimationSystem
{
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly GravitySystem _gravity = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
[Dependency] private readonly BuckleSystem _buckle = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
public override void Initialize()
{
base.Initialize();
SubscribeAllEvent<StartedWaddlingEvent>(OnStartWaddling);
SubscribeLocalEvent<WaddleAnimationComponent, AnimationCompletedEvent>(OnAnimationCompleted);
SubscribeAllEvent<StoppedWaddlingEvent>(OnStopWaddling);
}
private void OnStartWaddling(StartedWaddlingEvent msg, EntitySessionEventArgs args)
{
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
StartWaddling((GetEntity(msg.Entity), comp));
}
private void OnStopWaddling(StoppedWaddlingEvent msg, EntitySessionEventArgs args)
{
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
StopWaddling((GetEntity(msg.Entity), comp));
}
private void StartWaddling(Entity<WaddleAnimationComponent> entity)
{
if (_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
return;
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
return;
if (_gravity.IsWeightless(entity.Owner))
return;
if (!_actionBlocker.CanMove(entity.Owner, mover))
return;
// Do nothing if buckled in
if (_buckle.IsBuckled(entity.Owner))
return;
// Do nothing if crit or dead (for obvious reasons)
if (_mobState.IsIncapacitated(entity.Owner))
return;
PlayWaddleAnimationUsing(
(entity.Owner, entity.Comp),
CalculateAnimationLength(entity.Comp, mover),
CalculateTumbleIntensity(entity.Comp)
);
}
private static float CalculateTumbleIntensity(WaddleAnimationComponent component)
{
return component.LastStep ? 360 - component.TumbleIntensity : component.TumbleIntensity;
}
private static float CalculateAnimationLength(WaddleAnimationComponent component, InputMoverComponent mover)
{
return mover.Sprinting ? component.AnimationLength * component.RunAnimationLengthMultiplier : component.AnimationLength;
}
private void OnAnimationCompleted(Entity<WaddleAnimationComponent> entity, ref AnimationCompletedEvent args)
{
if (args.Key != entity.Comp.KeyName)
return;
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
return;
PlayWaddleAnimationUsing(
(entity.Owner, entity.Comp),
CalculateAnimationLength(entity.Comp, mover),
CalculateTumbleIntensity(entity.Comp)
);
}
private void StopWaddling(Entity<WaddleAnimationComponent> entity)
{
if (!_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
return;
_animation.Stop(entity.Owner, entity.Comp.KeyName);
if (!TryComp<SpriteComponent>(entity.Owner, out var sprite))
return;
sprite.Offset = new Vector2();
sprite.Rotation = Angle.FromDegrees(0);
}
private void PlayWaddleAnimationUsing(Entity<WaddleAnimationComponent> entity, float len, float tumbleIntensity)
{
entity.Comp.LastStep = !entity.Comp.LastStep;
var anim = new Animation()
{
Length = TimeSpan.FromSeconds(len),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Rotation),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0),
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(tumbleIntensity), len/2),
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), len/2),
}
},
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(), 0),
new AnimationTrackProperty.KeyFrame(entity.Comp.HopIntensity, len/2),
new AnimationTrackProperty.KeyFrame(new Vector2(), len/2),
}
}
}
};
_animation.Play(entity.Owner, anim, entity.Comp.KeyName);
}
}

View File

@@ -1,5 +1,6 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
xmlns:options="clr-namespace:Content.Client._CP14.Options"
Title="{Loc 'ui-options-title'}"
MinSize="800 450">
<TabContainer Name="Tabs" Access="Public">
@@ -8,5 +9,8 @@
<tabs:KeyRebindTab Name="KeyRebindTab" />
<tabs:AudioTab Name="AudioTab" />
<tabs:AccessibilityTab Name="AccessibilityTab" />
<!-- CP14-options-menu-start -->
<options:CP14OptionsMenuMainTab Name="CP14OptionsMenuTab"/>
<!-- CP14-options-menu-end -->
</TabContainer>
</DefaultWindow>

View File

@@ -19,6 +19,10 @@ namespace Content.Client.Options.UI
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-accessibility"));
// CP14-options-menu-start
Tabs.SetTabTitle(5, Loc.GetString("cp14-ui-options-tab-main"));
// CP14-options-menu-end
UpdateTabs();
}

View File

@@ -60,7 +60,7 @@ public sealed partial class StencilOverlay
// Draw the rain
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilDraw").Instance());
_parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, Vector2.Zero, modulate: (weatherProto.Color ?? Color.White).WithAlpha(alpha));
_parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, weatherProto.OffsetSpeed, modulate: (weatherProto.Color ?? Color.White).WithAlpha(alpha*weatherProto.Alpha)); //CP14 alpha and offset scrolling
worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.UseShader(null);

View File

@@ -74,16 +74,19 @@ public sealed partial class StencilOverlay : Overlay
DrawRestrictedRange(args, restrictedRangeComponent, invMatrix);
}
//CP14 Overlays
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
{
DrawWorldEdge(args, worldEdge, invMatrix);
}
//CP14 Overlays end
//CP14 Overlays
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
{
DrawCloudShadows(args, shadows, invMatrix);
}
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
{
DrawWorldEdge(args, worldEdge, invMatrix);
}
//CP14 Overlays end
args.WorldHandle.UseShader(null);

View File

@@ -2,6 +2,7 @@ using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Utility;
using Content.Shared.Paper;
using static Content.Shared.Paper.PaperComponent;
namespace Content.Client.Paper.UI;
@@ -23,6 +24,10 @@ public sealed class PaperBoundUserInterface : BoundUserInterface
_window = this.CreateWindow<PaperWindow>();
_window.OnSaved += InputOnTextEntered;
if (EntMan.TryGetComponent<PaperComponent>(Owner, out var paper))
{
_window.MaxInputLength = paper.ContentSize;
}
if (EntMan.TryGetComponent<PaperVisualsComponent>(Owner, out var visuals))
{
_window.InitVisuals(Owner, visuals);

View File

@@ -15,10 +15,13 @@
<Control Name="TextAlignmentPadding" VerticalAlignment="Top"/>
<RichTextLabel Name="BlankPaperIndicator" StyleClasses="LabelSecondaryColor" VerticalAlignment="Top" HorizontalAlignment="Center"/>
<RichTextLabel StyleClasses="PaperWrittenText" Name="WrittenTextLabel" VerticalAlignment="Top"/>
<PanelContainer Name="InputContainer" StyleClasses="TransparentBorderedWindowPanel" MinHeight="100"
VerticalAlignment="Stretch" VerticalExpand="True" HorizontalExpand="True">
<TextEdit Name="Input" StyleClasses="PaperLineEdit" Access="Public" />
</PanelContainer>
<BoxContainer Name="InputContainer" Orientation="Vertical" VerticalExpand="True" VerticalAlignment="Stretch">
<PanelContainer StyleClasses="TransparentBorderedWindowPanel" MinHeight="100"
VerticalAlignment="Stretch" VerticalExpand="True" HorizontalExpand="True">
<TextEdit Name="Input" StyleClasses="PaperLineEdit" Access="Public" />
</PanelContainer>
<Label Name="FillStatus" StyleClasses="LabelSecondaryColor"/>
</BoxContainer>
</BoxContainer>
<paper:StampCollection Name="StampDisplay" VerticalAlignment="Bottom" Margin="6"/>

View File

@@ -48,6 +48,20 @@ namespace Content.Client.Paper.UI
public event Action<string>? OnSaved;
private int _MaxInputLength = -1;
public int MaxInputLength
{
get
{
return _MaxInputLength;
}
set
{
_MaxInputLength = value;
UpdateFillState();
}
}
public PaperWindow()
{
IoCManager.InjectDependencies(this);
@@ -63,11 +77,21 @@ namespace Content.Client.Paper.UI
{
if (args.Function == EngineKeyFunctions.MultilineTextSubmit)
{
RunOnSaved();
args.Handle();
// SaveButton is disabled when we hit the max input limit. Just check
// that flag instead of trying to calculate the input length again
if (!SaveButton.Disabled)
{
RunOnSaved();
args.Handle();
}
}
};
Input.OnTextChanged += args =>
{
UpdateFillState();
};
SaveButton.OnPressed += _ =>
{
RunOnSaved();
@@ -126,6 +150,7 @@ namespace Content.Client.Paper.UI
PaperContent.ModulateSelfOverride = visuals.ContentImageModulate;
WrittenTextLabel.ModulateSelfOverride = visuals.FontAccentColor;
FillStatus.ModulateSelfOverride = visuals.FontAccentColor;
var contentImage = visuals.ContentImagePath != null ? _resCache.GetResource<TextureResource>(visuals.ContentImagePath) : null;
if (contentImage != null)
@@ -294,7 +319,29 @@ namespace Content.Client.Paper.UI
private void RunOnSaved()
{
// Prevent further saving while text processing still in
SaveButton.Disabled = true;
OnSaved?.Invoke(Rope.Collapse(Input.TextRope));
}
private void UpdateFillState()
{
if (MaxInputLength != -1)
{
var inputLength = Input.TextLength;
FillStatus.Text = Loc.GetString("paper-ui-fill-level",
("currentLength", inputLength),
("maxLength", MaxInputLength));
// Disable the save button if we've gone over the limit
SaveButton.Disabled = inputLength > MaxInputLength;
}
else
{
FillStatus.Text = "";
SaveButton.Disabled = false;
}
}
}
}

View File

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

View File

@@ -0,0 +1,50 @@
using Content.Shared.Pinpointer;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Map;
namespace Content.Client.Pinpointer.UI;
[GenerateTypedNameReferences]
public sealed partial class StationMapBeaconControl : Control, IComparable<StationMapBeaconControl>
{
[Dependency] private readonly IEntityManager _entMan = default!;
public readonly EntityCoordinates BeaconPosition;
public Action<EntityCoordinates>? OnPressed;
public string? Label => BeaconNameLabel.Text;
private StyleBoxFlat _styleBox;
public Color Color => _styleBox.BackgroundColor;
public StationMapBeaconControl(EntityUid mapUid, SharedNavMapSystem.NavMapBeacon beacon)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
BeaconPosition = new EntityCoordinates(mapUid, beacon.Position);
_styleBox = new StyleBoxFlat { BackgroundColor = beacon.Color };
ColorPanel.PanelOverride = _styleBox;
BeaconNameLabel.Text = beacon.Text;
MainButton.OnPressed += args => OnPressed?.Invoke(BeaconPosition);
}
public int CompareTo(StationMapBeaconControl? other)
{
if (other == null)
return 1;
// Group by color
var colorCompare = Color.ToArgb().CompareTo(other.Color.ToArgb());
if (colorCompare != 0)
{
return colorCompare;
}
// If same color, sort by text
return string.Compare(Label, other.Label);
}
}

View File

@@ -24,9 +24,16 @@ public sealed class StationMapBoundUserInterface : BoundUserInterface
_window = this.CreateWindow<StationMapWindow>();
_window.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
string stationName = string.Empty;
if(EntMan.TryGetComponent<MetaDataComponent>(gridUid, out var gridMetaData))
{
stationName = gridMetaData.EntityName;
}
if (EntMan.TryGetComponent<StationMapComponent>(Owner, out var comp) && comp.ShowLocation)
_window.Set(gridUid, Owner);
_window.Set(stationName, gridUid, Owner);
else
_window.Set(gridUid, null);
_window.Set(stationName, gridUid, null);
}
}

View File

@@ -3,11 +3,28 @@
xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI"
Title="{Loc 'station-map-window-title'}"
Resizable="False"
SetSize="668 713"
MinSize="668 713">
SetSize="868 748"
MinSize="868 748">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 8 0 10" VerticalAlignment="Top">
<!-- Station name -->
<controls:StripeBack>
<PanelContainer>
<Label Name="StationName" Text="Unknown station" StyleClasses="LabelBig" Align="Center"/>
</PanelContainer>
</controls:StripeBack>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalAlignment="Top">
<ui:NavMapControl Name="NavMapScreen"/>
<BoxContainer Orientation="Vertical" SetWidth="200">
<!-- Search bar -->
<LineEdit Name="FilterBar" PlaceHolder="{Loc 'station-map-filter-placeholder'}" Margin="0 0 10 10" HorizontalExpand="True"/>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
<!-- Beacon Buttons (filled by code) -->
<BoxContainer Name="BeaconButtons" Orientation="Vertical" HorizontalExpand="True" />
</ScrollContainer>
</BoxContainer>
</BoxContainer>
<!-- Footer -->

View File

@@ -3,24 +3,75 @@ using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Map;
using Content.Shared.Pinpointer;
namespace Content.Client.Pinpointer.UI;
[GenerateTypedNameReferences]
public sealed partial class StationMapWindow : FancyWindow
{
[Dependency] private readonly IEntityManager _entMan = default!;
private readonly List<StationMapBeaconControl> _buttons = new();
public StationMapWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
FilterBar.OnTextChanged += (bar) => OnFilterChanged(bar.Text);
}
public void Set(EntityUid? mapUid, EntityUid? trackedEntity)
public void Set(string stationName, EntityUid? mapUid, EntityUid? trackedEntity)
{
NavMapScreen.MapUid = mapUid;
if (trackedEntity != null)
NavMapScreen.TrackedCoordinates.Add(new EntityCoordinates(trackedEntity.Value, Vector2.Zero), (true, Color.Cyan));
if (!string.IsNullOrEmpty(stationName))
{
StationName.Text = stationName;
}
NavMapScreen.ForceNavMapUpdate();
UpdateBeaconList(mapUid);
}
}
public void OnFilterChanged(string newFilter)
{
foreach (var button in _buttons)
{
button.Visible = string.IsNullOrEmpty(newFilter) || (
!string.IsNullOrEmpty(button.Label) &&
button.Label.Contains(newFilter, StringComparison.OrdinalIgnoreCase)
);
};
}
public void UpdateBeaconList(EntityUid? mapUid)
{
BeaconButtons.Children.Clear();
_buttons.Clear();
if (!mapUid.HasValue)
return;
if (!_entMan.TryGetComponent<NavMapComponent>(mapUid, out var navMap))
return;
foreach (var beacon in navMap.Beacons.Values)
{
var button = new StationMapBeaconControl(mapUid.Value, beacon);
button.OnPressed += NavMapScreen.CenterToCoordinates;
_buttons.Add(button);
}
_buttons.Sort();
foreach (var button in _buttons)
BeaconButtons.AddChild(button);
}
}

View File

@@ -0,0 +1,23 @@
using Content.Shared.Players.RateLimiting;
using Robust.Shared.Player;
namespace Content.Client.Players.RateLimiting;
public sealed class PlayerRateLimitManager : SharedPlayerRateLimitManager
{
public override RateLimitStatus CountAction(ICommonSession player, string key)
{
// TODO Rate-Limit
// Add support for rate limit prediction
// I.e., dont mis-predict just because somebody is clicking too quickly.
return RateLimitStatus.Allowed;
}
public override void Register(string key, RateLimitRegistration registration)
{
}
public override void Initialize()
{
}
}

View File

@@ -148,7 +148,12 @@ namespace Content.Client.Popups
}
public override void PopupCursor(string? message, PopupType type = PopupType.Small)
=> PopupCursorInternal(message, type, true);
{
if (!_timing.IsFirstTimePredicted)
return;
PopupCursorInternal(message, type, true);
}
public override void PopupCursor(string? message, ICommonSession recipient, PopupType type = PopupType.Small)
{

View File

@@ -199,7 +199,9 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
var gridMatrix = _transform.GetWorldMatrix(gUid);
var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert);
var color = _shuttles.GetIFFColor(grid, self: false, iff);
var labelColor = _shuttles.GetIFFColor(grid, self: false, iff);
var coordColor = new Color(labelColor.R * 0.8f, labelColor.G * 0.8f, labelColor.B * 0.8f, 0.5f);
// Others default:
// Color.FromHex("#FFC000FF")
@@ -213,25 +215,52 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty);
gridCentre.Y = -gridCentre.Y;
var distance = gridCentre.Length();
var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName),
("distance", $"{distance:0.0}"));
var mapCoords = _transform.GetWorldPosition(gUid);
var coordsText = $"({mapCoords.X:0.0}, {mapCoords.Y:0.0})";
// yes 1.0 scale is intended here.
var labelDimensions = handle.GetDimensions(Font, labelText, 1f);
var coordsDimensions = handle.GetDimensions(Font, coordsText, 0.7f);
// y-offset the control to always render below the grid (vertically)
var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f;
// The actual position in the UI. We offset the matrix position to render it off by half its width
// plus by the offset.
var uiPosition = ScalePosition(gridCentre)- new Vector2(labelDimensions.X / 2f, -yOffset);
// The actual position in the UI. We centre the label by offsetting the matrix position
// by half the label's width, plus the y-offset
var gridScaledPosition = ScalePosition(gridCentre) - new Vector2(0, -yOffset);
// Look this is uggo so feel free to cleanup. We just need to clamp the UI position to within the viewport.
uiPosition = new Vector2(Math.Clamp(uiPosition.X, 0f, PixelWidth - labelDimensions.X ),
Math.Clamp(uiPosition.Y, 0f, PixelHeight - labelDimensions.Y));
// Normalize the grid position if it exceeds the viewport bounds
// normalizing it instead of clamping it preserves the direction of the vector and prevents corner-hugging
var gridOffset = gridScaledPosition / PixelSize - new Vector2(0.5f, 0.5f);
var offsetMax = Math.Max(Math.Abs(gridOffset.X), Math.Abs(gridOffset.Y)) * 2f;
if (offsetMax > 1)
{
gridOffset = new Vector2(gridOffset.X / offsetMax, gridOffset.Y / offsetMax);
handle.DrawString(Font, uiPosition, labelText, color);
gridScaledPosition = (gridOffset + new Vector2(0.5f, 0.5f)) * PixelSize;
}
var labelUiPosition = gridScaledPosition - new Vector2(labelDimensions.X / 2f, 0);
var coordUiPosition = gridScaledPosition - new Vector2(coordsDimensions.X / 2f, -labelDimensions.Y);
// clamp the IFF label's UI position to within the viewport extents so it hugs the edges of the viewport
// coord label intentionally isn't clamped so we don't get ugly clutter at the edges
var controlExtents = PixelSize - new Vector2(labelDimensions.X, labelDimensions.Y); //new Vector2(labelDimensions.X * 2f, labelDimensions.Y);
labelUiPosition = Vector2.Clamp(labelUiPosition, Vector2.Zero, controlExtents);
// draw IFF label
handle.DrawString(Font, labelUiPosition, labelText, labelColor);
// only draw coords label if close enough
if (offsetMax < 1)
{
handle.DrawString(Font, coordUiPosition, coordsText, 0.7f, coordColor);
}
}
// Detailed view
@@ -241,7 +270,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
if (!gridAABB.Intersects(viewAABB))
continue;
DrawGrid(handle, matty, grid, color);
DrawGrid(handle, matty, grid, labelColor);
DrawDocks(handle, gUid, matty);
}
}

View File

@@ -1,4 +1,5 @@
using Content.Shared.Doors.Components;
using Content.Shared.Electrocution;
using Content.Shared.Silicons.StationAi;
using Robust.Shared.Utility;
@@ -6,25 +7,69 @@ namespace Content.Client.Silicons.StationAi;
public sealed partial class StationAiSystem
{
private readonly ResPath _aiActionsRsi = new ResPath("/Textures/Interface/Actions/actions_ai.rsi");
private void InitializeAirlock()
{
SubscribeLocalEvent<DoorBoltComponent, GetStationAiRadialEvent>(OnDoorBoltGetRadial);
SubscribeLocalEvent<AirlockComponent, GetStationAiRadialEvent>(OnEmergencyAccessGetRadial);
SubscribeLocalEvent<ElectrifiedComponent, GetStationAiRadialEvent>(OnDoorElectrifiedGetRadial);
}
private void OnDoorBoltGetRadial(Entity<DoorBoltComponent> ent, ref GetStationAiRadialEvent args)
{
args.Actions.Add(new StationAiRadial()
{
Sprite = ent.Comp.BoltsDown ?
new SpriteSpecifier.Rsi(
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "open") :
new SpriteSpecifier.Rsi(
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "closed"),
Tooltip = ent.Comp.BoltsDown ? Loc.GetString("bolt-open") : Loc.GetString("bolt-close"),
Event = new StationAiBoltEvent()
args.Actions.Add(
new StationAiRadial
{
Bolted = !ent.Comp.BoltsDown,
Sprite = ent.Comp.BoltsDown
? new SpriteSpecifier.Rsi(_aiActionsRsi, "unbolt_door")
: new SpriteSpecifier.Rsi(_aiActionsRsi, "bolt_door"),
Tooltip = ent.Comp.BoltsDown
? Loc.GetString("bolt-open")
: Loc.GetString("bolt-close"),
Event = new StationAiBoltEvent
{
Bolted = !ent.Comp.BoltsDown,
}
}
});
);
}
private void OnEmergencyAccessGetRadial(Entity<AirlockComponent> ent, ref GetStationAiRadialEvent args)
{
args.Actions.Add(
new StationAiRadial
{
Sprite = ent.Comp.EmergencyAccess
? new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_off")
: new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_on"),
Tooltip = ent.Comp.EmergencyAccess
? Loc.GetString("emergency-access-off")
: Loc.GetString("emergency-access-on"),
Event = new StationAiEmergencyAccessEvent
{
EmergencyAccess = !ent.Comp.EmergencyAccess,
}
}
);
}
private void OnDoorElectrifiedGetRadial(Entity<ElectrifiedComponent> ent, ref GetStationAiRadialEvent args)
{
args.Actions.Add(
new StationAiRadial
{
Sprite = ent.Comp.Enabled
? new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_off")
: new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_on"),
Tooltip = ent.Comp.Enabled
? Loc.GetString("electrify-door-off")
: Loc.GetString("electrify-door-on"),
Event = new StationAiElectrifiedEvent
{
Electrified = !ent.Comp.Enabled,
}
}
);
}
}

View File

@@ -695,6 +695,18 @@ namespace Content.Client.Stylesheets
new StyleProperty("font-color", Color.FromHex("#E5E5E581")),
}),
// ItemStatus for hands
Element()
.Class(StyleClassItemStatusNotHeld)
.Prop("font", notoSansItalic10)
.Prop("font-color", ItemStatusNotHeldColor)
.Prop(nameof(Control.Margin), new Thickness(4, 0, 0, 2)),
Element()
.Class(StyleClassItemStatus)
.Prop(nameof(RichTextLabel.LineHeightScale), 0.7f)
.Prop(nameof(Control.Margin), new Thickness(4, 0, 0, 2)),
// Context Menu window
Element<PanelContainer>().Class(ContextMenuPopup.StyleClassContextMenuPopup)
.Prop(PanelContainer.StylePropertyPanel, contextMenuBackground),

View File

@@ -69,7 +69,7 @@ public sealed class ParacusiaSystem : SharedParacusiaSystem
var newCoords = Transform(uid).Coordinates.Offset(randomOffset);
// Play the sound
paracusia.Stream = _audio.PlayStatic(paracusia.Sounds, uid, newCoords).Value.Entity;
paracusia.Stream = _audio.PlayStatic(paracusia.Sounds, uid, newCoords)?.Entity;
}
}

View File

@@ -87,6 +87,9 @@ public sealed partial class DialogWindow : FancyWindow
Prompts.AddChild(box);
}
// Grab keyboard focus for the first dialog entry
_promptLines[0].Item2.GrabKeyboardFocus();
OkButton.OnPressed += _ => Confirm();
CancelButton.OnPressed += _ =>

View File

@@ -398,10 +398,6 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
{
QueueWindowUpdate();
// TODO ACTIONS allow buttons to persist across state applications
// Then we don't have to interrupt drags any time the buttons get rebuilt.
_menuDragHelper.EndDrag();
if (_actionsSystem != null)
_container?.SetActionData(_actionsSystem, _actions.ToArray());
}

View File

@@ -28,14 +28,26 @@ public class ActionButtonContainer : GridContainer
get => (ActionButton) GetChild(index);
}
private void BuildActionButtons(int count)
public void SetActionData(ActionsSystem system, params EntityUid?[] actionTypes)
{
var uniqueCount = Math.Min(system.GetClientActions().Count(), actionTypes.Length + 1);
var keys = ContentKeyFunctions.GetHotbarBoundKeys();
Children.Clear();
for (var index = 0; index < count; index++)
for (var i = 0; i < uniqueCount; i++)
{
Children.Add(MakeButton(index));
if (i >= ChildCount)
{
AddChild(MakeButton(i));
}
if (!actionTypes.TryGetValue(i, out var action))
action = null;
((ActionButton) GetChild(i)).UpdateData(action, system);
}
for (var i = ChildCount - 1; i >= uniqueCount; i--)
{
RemoveChild(GetChild(i));
}
ActionButton MakeButton(int index)
@@ -55,20 +67,6 @@ public class ActionButtonContainer : GridContainer
}
}
public void SetActionData(ActionsSystem system, params EntityUid?[] actionTypes)
{
var uniqueCount = Math.Min(system.GetClientActions().Count(), actionTypes.Length + 1);
if (ChildCount != uniqueCount)
BuildActionButtons(uniqueCount);
for (var i = 0; i < uniqueCount; i++)
{
if (!actionTypes.TryGetValue(i, out var action))
action = null;
((ActionButton) GetChild(i)).UpdateData(action, system);
}
}
public void ClearActionData()
{
foreach (var button in Children)

View File

@@ -23,29 +23,17 @@ namespace Content.Client.VendingMachines
{
base.Open();
var vendingMachineSys = EntMan.System<VendingMachineSystem>();
_cachedInventory = vendingMachineSys.GetAllInventory(Owner);
_menu = this.CreateWindow<VendingMachineMenu>();
_menu.OpenCenteredLeft();
_menu.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
_menu.OnItemSelected += OnItemSelected;
_menu.Populate(_cachedInventory);
_menu.OpenCenteredLeft();
Refresh();
}
protected override void UpdateState(BoundUserInterfaceState state)
public void Refresh()
{
base.UpdateState(state);
if (state is not VendingMachineInterfaceState newState)
return;
_cachedInventory = newState.Inventory;
var system = EntMan.System<VendingMachineSystem>();
_cachedInventory = system.GetAllInventory(Owner);
_menu?.Populate(_cachedInventory);
}

View File

@@ -8,6 +8,7 @@ public sealed class VendingMachineSystem : SharedVendingMachineSystem
{
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
public override void Initialize()
{
@@ -15,6 +16,15 @@ public sealed class VendingMachineSystem : SharedVendingMachineSystem
SubscribeLocalEvent<VendingMachineComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<VendingMachineComponent, AnimationCompletedEvent>(OnAnimationCompleted);
SubscribeLocalEvent<VendingMachineComponent, AfterAutoHandleStateEvent>(OnVendingAfterState);
}
private void OnVendingAfterState(EntityUid uid, VendingMachineComponent component, ref AfterAutoHandleStateEvent args)
{
if (_uiSystem.TryGetOpenUi<VendingMachineBoundUserInterface>(uid, VendingMachineUiKey.Key, out var bui))
{
bui.Refresh();
}
}
private void OnAnimationCompleted(EntityUid uid, VendingMachineComponent component, AnimationCompletedEvent args)

View File

@@ -1,9 +1,9 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using Content.Client.Examine;
using Content.Client.Gameplay;
using Content.Client.Popups;
using Content.Shared.CCVar;
using Content.Shared.Examine;
using Content.Shared.Tag;
using Content.Shared.Verbs;
@@ -13,6 +13,8 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.State;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Utility;
@@ -28,11 +30,11 @@ namespace Content.Client.Verbs
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly SharedContainerSystem _containers = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
/// <summary>
/// When a user right clicks somewhere, how large is the box we use to get entities for the context menu?
/// </summary>
public const float EntityMenuLookupSize = 0.25f;
private float _lookupSize;
/// <summary>
/// These flags determine what entities the user can see on the context menu.
@@ -41,114 +43,127 @@ namespace Content.Client.Verbs
public Action<VerbsResponseEvent>? OnVerbsResponse;
private List<EntityUid> _entities = new();
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<VerbsResponseEvent>(HandleVerbResponse);
Subs.CVar(_cfg, CCVars.GameEntityMenuLookup, OnLookupChanged, true);
}
private void OnLookupChanged(float val)
{
_lookupSize = val;
}
/// <summary>
/// Get all of the entities in an area for displaying on the context menu.
/// Get all of the entities in an area for displaying on the context menu.
/// </summary>
public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true)] out List<EntityUid>? result)
/// <returns>True if any entities were found.</returns>
public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true)] out List<EntityUid>? entities)
{
result = null;
entities = null;
if (_stateManager.CurrentState is not GameplayStateBase gameScreenBase)
if (_stateManager.CurrentState is not GameplayStateBase)
return false;
var player = _playerManager.LocalEntity;
if (player == null)
if (_playerManager.LocalEntity is not { } player)
return false;
// If FOV drawing is disabled, we will modify the visibility option to ignore visiblity checks.
var visibility = _eyeManager.CurrentEye.DrawFov
? Visibility
: Visibility | MenuVisibility.NoFov;
var visibility = _eyeManager.CurrentEye.DrawFov ? Visibility : Visibility | MenuVisibility.NoFov;
var ev = new MenuVisibilityEvent()
var ev = new MenuVisibilityEvent
{
TargetPos = targetPos,
Visibility = visibility,
};
RaiseLocalEvent(player.Value, ref ev);
RaiseLocalEvent(player, ref ev);
visibility = ev.Visibility;
// Get entities
_entities.Clear();
var entitiesUnderMouse = _tree.QueryAabb(targetPos.MapId, Box2.CenteredAround(targetPos.Position, new Vector2(EntityMenuLookupSize, EntityMenuLookupSize)));
// Do we have to do FoV checks?
if ((visibility & MenuVisibility.NoFov) == 0)
// Initially, we include all entities returned by a sprite area lookup
var box = Box2.CenteredAround(targetPos.Position, new Vector2(_lookupSize, _lookupSize));
var queryResult = _tree.QueryAabb(targetPos.MapId, box);
entities = new List<EntityUid>(queryResult.Count);
foreach (var ent in queryResult)
{
bool Predicate(EntityUid e) => e == player;
TryComp(player.Value, out ExaminerComponent? examiner);
foreach (var ent in entitiesUnderMouse)
{
if (_examine.CanExamine(player.Value, targetPos, Predicate, ent.Uid, examiner))
_entities.Add(ent.Uid);
}
}
else
{
foreach (var ent in entitiesUnderMouse)
{
_entities.Add(ent.Uid);
}
entities.Add(ent.Uid);
}
if (_entities.Count == 0)
return false;
if (visibility == MenuVisibility.All)
// If we're in a container list all other entities in it.
// E.g., allow players in lockers to examine / interact with other entities in the same locker
if (_containers.TryGetContainingContainer((player, null), out var container))
{
result = new (_entities);
return true;
}
// remove any entities in containers
if ((visibility & MenuVisibility.InContainer) == 0)
{
for (var i = _entities.Count - 1; i >= 0; i--)
// Only include the container contents when clicking near it.
if (entities.Contains(container.Owner)
|| _containers.TryGetOuterContainer(container.Owner, Transform(container.Owner), out var outer)
&& entities.Contains(outer.Owner))
{
var entity = _entities[i];
// The container itself might be in some other container, so it might not have been added by the
// sprite tree lookup.
if (!entities.Contains(container.Owner))
entities.Add(container.Owner);
if (ContainerSystem.IsInSameOrTransparentContainer(player.Value, entity))
continue;
_entities.RemoveSwap(i);
}
}
// remove any invisible entities
if ((visibility & MenuVisibility.Invisible) == 0)
{
var spriteQuery = GetEntityQuery<SpriteComponent>();
for (var i = _entities.Count - 1; i >= 0; i--)
{
var entity = _entities[i];
if (!spriteQuery.TryGetComponent(entity, out var spriteComponent) ||
!spriteComponent.Visible ||
_tagSystem.HasTag(entity, "HideContextMenu"))
// TODO Context Menu
// This might miss entities in some situations. E.g., one of the contained entities entity in it, that
// itself has another entity attached to it, then we should be able to "see" that entity.
// E.g., if a security guard is on a segway and gets thrown in a locker, this wouldn't let you see the guard.
foreach (var ent in container.ContainedEntities)
{
_entities.RemoveSwap(i);
if (!entities.Contains(ent))
entities.Add(ent);
}
}
}
if (_entities.Count == 0)
return false;
if ((visibility & MenuVisibility.InContainer) != 0)
{
// This is inefficient, but I'm lazy and CBF implementing my own recursive container method. Note that
// this might actually fail to add the contained children of some entities in the menu. E.g., an entity
// with a large sprite aabb, but small broadphase might appear in the menu, but have its children added
// by this.
var flags = LookupFlags.All & ~LookupFlags.Sensors;
foreach (var e in _lookup.GetEntitiesInRange(targetPos, _lookupSize, flags: flags))
{
if (!entities.Contains(e))
entities.Add(e);
}
}
result = new(_entities);
return true;
// Do we have to do FoV checks?
if ((visibility & MenuVisibility.NoFov) == 0)
{
TryComp(player, out ExaminerComponent? examiner);
for (var i = entities.Count - 1; i >= 0; i--)
{
if (!_examine.CanExamine(player, targetPos, e => e == player, entities[i], examiner))
entities.RemoveSwap(i);
}
}
if ((visibility & MenuVisibility.Invisible) != 0)
return entities.Count != 0;
for (var i = entities.Count - 1; i >= 0; i--)
{
if (_tagSystem.HasTag(entities[i], "HideContextMenu"))
entities.RemoveSwap(i);
}
// Unless we added entities in containers, every entity should already have a visible sprite due to
// the fact that we used the sprite tree query.
if (container == null && (visibility & MenuVisibility.InContainer) == 0)
return entities.Count != 0;
var spriteQuery = GetEntityQuery<SpriteComponent>();
for (var i = entities.Count - 1; i >= 0; i--)
{
if (!spriteQuery.TryGetComponent(entities[i], out var spriteComponent) || !spriteComponent.Visible)
entities.RemoveSwap(i);
}
return entities.Count != 0;
}
/// <summary>

View File

@@ -22,6 +22,7 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
_window = this.CreateWindow<VoiceMaskNameChangeWindow>();
_window.ReloadVerbs(_protomanager);
_window.AddVerbs();
_window.OnNameChange += OnNameSelected;
_window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb));

View File

@@ -31,8 +31,6 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
OnVerbChange?.Invoke((string?) args.Button.GetItemMetadata(args.Id));
SpeechVerbSelector.SelectId(args.Id);
};
AddVerbs();
}
public void ReloadVerbs(IPrototypeManager proto)
@@ -44,7 +42,7 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
_verbs.Sort((a, b) => a.Item1.CompareTo(b.Item1));
}
private void AddVerbs()
public void AddVerbs()
{
SpeechVerbSelector.Clear();

View File

@@ -1,7 +1,7 @@
<ui:VoteCallMenu xmlns="https://spacestation14.io"
<ui:VoteCallMenu xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.Voting.UI"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MouseFilter="Stop" MinSize="350 150">
MouseFilter="Stop" MinSize="350 200">
<PanelContainer StyleClasses="AngleRect" />
<BoxContainer Orientation="Vertical">
<BoxContainer Margin="8 0" Orientation="Horizontal">
@@ -13,16 +13,18 @@
<controls:HighDivider />
<BoxContainer Orientation="Vertical" Margin="8 2 8 0" VerticalExpand="True" VerticalAlignment="Top">
<BoxContainer Orientation="Horizontal">
<OptionButton Name="VoteTypeButton" HorizontalExpand="True" />
<Control HorizontalExpand="True">
<OptionButton Name="VoteSecondButton" Visible="False" />
</Control>
<BoxContainer Orientation="Vertical">
<OptionButton Margin="2 1" Name="VoteTypeButton" HorizontalExpand="False" />
<BoxContainer Name="VoteOptionsButtonContainer" HorizontalExpand="False" Orientation="Vertical">
</BoxContainer>
<Button Margin="64 4" Name="FollowButton" Text="{Loc 'ui-vote-follow-button'}" Visible="False" />
<Label Margin="2 2" Name="VoteNotTrustedLabel" Text="{Loc 'ui-vote-trusted-users-notice'}" Visible="False" />
<Label Margin="2 2" Name="VoteWarningLabel" Text="{Loc 'ui-vote-abuse-warning'}" Visible="False" HorizontalAlignment="Center"/>
</BoxContainer>
<Label Name="VoteTypeTimeoutLabel" Visible="False" />
<Label Margin="8 2" Name="VoteTypeTimeoutLabel" Visible="False" />
</BoxContainer>
<Button Margin="8 2" Name="CreateButton" Text="{Loc 'ui-vote-create-button'}" />
<Button Margin="8 32 8 2" Name="CreateButton" Text="{Loc 'ui-vote-create-button'}" />
<PanelContainer StyleClasses="LowDivider" />
<Label Margin="12 0 0 0" StyleClasses="LabelSubText" Text="{Loc 'ui-vote-fluff'}" />

View File

@@ -1,7 +1,9 @@
using System;
using System.Linq;
using System.Numerics;
using Content.Client.Stylesheets;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.Ghost;
using Content.Shared.Voting;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
@@ -9,10 +11,8 @@ using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Timing;
@@ -25,32 +25,54 @@ namespace Content.Client.Voting.UI
[Dependency] private readonly IVoteManager _voteManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientNetManager _netManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEntityNetworkManager _entNetManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public static readonly (string name, StandardVoteType type, (string name, string id)[]? secondaries)[]
AvailableVoteTypes =
{
("ui-vote-type-restart", StandardVoteType.Restart, null),
("ui-vote-type-gamemode", StandardVoteType.Preset, null),
("ui-vote-type-map", StandardVoteType.Map, null)
};
private VotingSystem _votingSystem;
public StandardVoteType Type;
public Dictionary<StandardVoteType, CreateVoteOption> AvailableVoteOptions = new Dictionary<StandardVoteType, CreateVoteOption>()
{
{ StandardVoteType.Restart, new CreateVoteOption("ui-vote-type-restart", new(), false, null) },
{ StandardVoteType.Preset, new CreateVoteOption("ui-vote-type-gamemode", new(), false, null) },
{ StandardVoteType.Map, new CreateVoteOption("ui-vote-type-map", new(), false, null) },
{ StandardVoteType.Votekick, new CreateVoteOption("ui-vote-type-votekick", new(), true, 0) }
};
public Dictionary<string, string> VotekickReasons = new Dictionary<string, string>()
{
{ VotekickReasonType.Raiding.ToString(), Loc.GetString("ui-vote-votekick-type-raiding") },
{ VotekickReasonType.Cheating.ToString(), Loc.GetString("ui-vote-votekick-type-cheating") },
{ VotekickReasonType.Spam.ToString(), Loc.GetString("ui-vote-votekick-type-spamming") }
};
public Dictionary<NetUserId, (NetEntity, string)> PlayerList = new();
public OptionButton? _followDropdown = null;
public bool IsAllowedVotekick = false;
public VoteCallMenu()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
_votingSystem = _entityManager.System<VotingSystem>();
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
CloseButton.OnPressed += _ => Close();
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime) / 60));
for (var i = 0; i < AvailableVoteTypes.Length; i++)
foreach (StandardVoteType voteType in Enum.GetValues<StandardVoteType>())
{
var (text, _, _) = AvailableVoteTypes[i];
VoteTypeButton.AddItem(Loc.GetString(text), i);
var option = AvailableVoteOptions[voteType];
VoteTypeButton.AddItem(Loc.GetString(option.Name), (int)voteType);
}
VoteTypeButton.OnItemSelected += VoteTypeSelected;
VoteSecondButton.OnItemSelected += VoteSecondSelected;
CreateButton.OnPressed += CreatePressed;
FollowButton.OnPressed += FollowSelected;
}
protected override void Opened()
@@ -60,6 +82,8 @@ namespace Content.Client.Voting.UI
_netManager.ClientSendMessage(new MsgVoteMenu());
_voteManager.CanCallVoteChanged += CanCallVoteChanged;
_votingSystem.VotePlayerListResponse += UpdateVotePlayerList;
_votingSystem.RequestVotePlayerList();
}
public override void Close()
@@ -67,6 +91,7 @@ namespace Content.Client.Voting.UI
base.Close();
_voteManager.CanCallVoteChanged -= CanCallVoteChanged;
_votingSystem.VotePlayerListResponse -= UpdateVotePlayerList;
}
protected override void FrameUpdate(FrameEventArgs args)
@@ -82,21 +107,50 @@ namespace Content.Client.Voting.UI
Close();
}
private void UpdateVotePlayerList(VotePlayerListResponseEvent msg)
{
Dictionary<string, string> optionsList = new();
Dictionary<NetUserId, (NetEntity, string)> playerList = new();
foreach ((NetUserId, NetEntity, string) player in msg.Players)
{
optionsList.Add(player.Item1.ToString(), player.Item3);
playerList.Add(player.Item1, (player.Item2, player.Item3));
}
if (optionsList.Count == 0)
optionsList.Add(" ", " ");
PlayerList = playerList;
IsAllowedVotekick = !msg.Denied;
var updatedDropdownOption = AvailableVoteOptions[StandardVoteType.Votekick];
updatedDropdownOption.Dropdowns = new List<Dictionary<string, string>>() { optionsList, VotekickReasons };
AvailableVoteOptions[StandardVoteType.Votekick] = updatedDropdownOption;
}
private void CreatePressed(BaseButton.ButtonEventArgs obj)
{
var typeId = VoteTypeButton.SelectedId;
var (_, typeKey, secondaries) = AvailableVoteTypes[typeId];
var voteType = AvailableVoteOptions[(StandardVoteType)typeId];
if (secondaries != null)
var commandArgs = "";
if (voteType.Dropdowns == null || voteType.Dropdowns.Count == 0)
{
var secondaryId = VoteSecondButton.SelectedId;
var (_, secondKey) = secondaries[secondaryId];
_consoleHost.LocalShell.RemoteExecuteCommand($"createvote {typeKey} {secondKey}");
_consoleHost.LocalShell.RemoteExecuteCommand($"createvote {((StandardVoteType)typeId).ToString()}");
}
else
{
_consoleHost.LocalShell.RemoteExecuteCommand($"createvote {typeKey}");
int i = 0;
foreach(var dropdowns in VoteOptionsButtonContainer.Children)
{
if (dropdowns is OptionButton optionButton && AvailableVoteOptions[(StandardVoteType)typeId].Dropdowns != null)
{
commandArgs += AvailableVoteOptions[(StandardVoteType)typeId].Dropdowns[i].ElementAt(optionButton.SelectedId).Key + " ";
i++;
}
}
_consoleHost.LocalShell.RemoteExecuteCommand($"createvote {((StandardVoteType)typeId).ToString()} {commandArgs}");
}
Close();
@@ -104,9 +158,16 @@ namespace Content.Client.Voting.UI
private void UpdateVoteTimeout()
{
var (_, typeKey, _) = AvailableVoteTypes[VoteTypeButton.SelectedId];
var typeKey = (StandardVoteType)VoteTypeButton.SelectedId;
var isAvailable = _voteManager.CanCallStandardVote(typeKey, out var timeout);
CreateButton.Disabled = !isAvailable;
if (typeKey == StandardVoteType.Votekick && !IsAllowedVotekick)
{
CreateButton.Disabled = true;
}
else
{
CreateButton.Disabled = !isAvailable;
}
VoteTypeTimeoutLabel.Visible = !isAvailable;
if (!isAvailable)
@@ -123,29 +184,73 @@ namespace Content.Client.Voting.UI
}
}
private static void VoteSecondSelected(OptionButton.ItemSelectedEventArgs obj)
private static void ButtonSelected(OptionButton.ItemSelectedEventArgs obj)
{
obj.Button.SelectId(obj.Id);
}
private void FollowSelected(Button.ButtonEventArgs obj)
{
if (_followDropdown == null)
return;
if (_followDropdown.SelectedId >= PlayerList.Count)
return;
var netEntity = PlayerList.ElementAt(_followDropdown.SelectedId).Value.Item1;
var msg = new GhostWarpToTargetRequestEvent(netEntity);
_entNetManager.SendSystemNetworkMessage(msg);
}
private void VoteTypeSelected(OptionButton.ItemSelectedEventArgs obj)
{
VoteTypeButton.SelectId(obj.Id);
var (_, _, options) = AvailableVoteTypes[obj.Id];
if (options == null)
VoteNotTrustedLabel.Visible = false;
if ((StandardVoteType)obj.Id == StandardVoteType.Votekick)
{
VoteSecondButton.Visible = false;
}
else
{
VoteSecondButton.Visible = true;
VoteSecondButton.Clear();
for (var i = 0; i < options.Length; i++)
if (!IsAllowedVotekick)
{
var (text, _) = options[i];
VoteSecondButton.AddItem(Loc.GetString(text), i);
VoteNotTrustedLabel.Visible = true;
var updatedDropdownOption = AvailableVoteOptions[StandardVoteType.Votekick];
updatedDropdownOption.Dropdowns = new List<Dictionary<string, string>>();
AvailableVoteOptions[StandardVoteType.Votekick] = updatedDropdownOption;
}
else
{
_votingSystem.RequestVotePlayerList();
}
}
VoteWarningLabel.Visible = AvailableVoteOptions[(StandardVoteType)obj.Id].EnableVoteWarning;
FollowButton.Visible = false;
var voteList = AvailableVoteOptions[(StandardVoteType)obj.Id].Dropdowns;
VoteOptionsButtonContainer.RemoveAllChildren();
if (voteList != null)
{
int i = 0;
foreach (var voteDropdown in voteList)
{
var optionButton = new OptionButton();
int j = 0;
foreach (var (key, value) in voteDropdown)
{
optionButton.AddItem(Loc.GetString(value), j);
j++;
}
VoteOptionsButtonContainer.AddChild(optionButton);
optionButton.Visible = true;
optionButton.OnItemSelected += ButtonSelected;
optionButton.Margin = new Thickness(2, 1);
if (AvailableVoteOptions[(StandardVoteType)obj.Id].FollowDropdownId != null && AvailableVoteOptions[(StandardVoteType)obj.Id].FollowDropdownId == i)
{
_followDropdown = optionButton;
FollowButton.Visible = true;
}
i++;
}
}
}
@@ -168,4 +273,20 @@ namespace Content.Client.Voting.UI
new VoteCallMenu().OpenCentered();
}
}
public record struct CreateVoteOption
{
public string Name;
public List<Dictionary<string, string>> Dropdowns;
public bool EnableVoteWarning;
public int? FollowDropdownId; // If set, this will enable the Follow button and use the dropdown matching the ID as input.
public CreateVoteOption(string name, List<Dictionary<string, string>> dropdowns, bool enableVoteWarning, int? followDropdownId)
{
Name = name;
Dropdowns = dropdowns;
EnableVoteWarning = enableVoteWarning;
FollowDropdownId = followDropdownId;
}
}
}

View File

@@ -1,10 +1,11 @@
<Control xmlns="https://spacestation14.io" MinWidth="300" MaxWidth="500">
<Control xmlns="https://spacestation14.io" MinWidth="300" MaxWidth="500">
<PanelContainer StyleClasses="AngleRect" />
<BoxContainer Margin="4" Orientation="Vertical">
<Label Name="VoteCaller" />
<RichTextLabel Name="VoteTitle" />
<GridContainer Columns="3" Name="VoteOptionsContainer" />
<Button Margin="4 4" Name="FollowVoteTarget" Text="{Loc 'ui-vote-follow-button-popup'}" Visible="False"></Button>
<GridContainer Columns="3" Name="VoteOptionsContainer"/>
<BoxContainer Orientation="Horizontal">
<ProgressBar Margin="4" HorizontalExpand="True" Name="TimeLeftBar" MinValue="0" MaxValue="1" />
<Label Name="TimeLeftText" />

View File

@@ -1,12 +1,10 @@
using System;
using System;
using Content.Client.Stylesheets;
using Content.Shared.Ghost;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -17,9 +15,11 @@ namespace Content.Client.Voting.UI
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IVoteManager _voteManager = default!;
[Dependency] private readonly IEntityNetworkManager _net = default!;
private readonly VoteManager.ActiveVote _vote;
private readonly Button[] _voteButtons;
private readonly NetEntity? _targetEntity;
public VotePopup(VoteManager.ActiveVote vote)
{
@@ -29,6 +29,13 @@ namespace Content.Client.Voting.UI
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
if (_vote.TargetEntity != null && _vote.TargetEntity != 0)
{
_targetEntity = new NetEntity(_vote.TargetEntity.Value);
FollowVoteTarget.Visible = true;
FollowVoteTarget.OnPressed += _ => AttemptFollowVoteEntity();
}
Modulate = Color.White.WithAlpha(0.75f);
_voteButtons = new Button[vote.Entries.Length];
var group = new ButtonGroup();
@@ -55,13 +62,29 @@ namespace Content.Client.Voting.UI
for (var i = 0; i < _voteButtons.Length; i++)
{
var entry = _vote.Entries[i];
_voteButtons[i].Text = Loc.GetString("ui-vote-button", ("text", entry.Text), ("votes", entry.Votes));
if (_vote.DisplayVotes)
{
_voteButtons[i].Text = Loc.GetString("ui-vote-button", ("text", entry.Text), ("votes", entry.Votes));
}
else
{
_voteButtons[i].Text = Loc.GetString("ui-vote-button-no-votes", ("text", entry.Text));
}
if (_vote.OurVote == i)
_voteButtons[i].Pressed = true;
}
}
private void AttemptFollowVoteEntity()
{
if (_targetEntity != null)
{
var msg = new GhostWarpToTargetRequestEvent(_targetEntity.Value);
_net.SendSystemNetworkMessage(msg);
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
// Logger.Debug($"{_gameTiming.ServerTime}, {_vote.StartTime}, {_vote.EndTime}");

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Shared.Voting;
@@ -184,6 +184,8 @@ namespace Content.Client.Voting
existingVote.Title = message.VoteTitle;
existingVote.StartTime = _gameTiming.RealServerToLocal(message.StartTime);
existingVote.EndTime = _gameTiming.RealServerToLocal(message.EndTime);
existingVote.DisplayVotes = message.DisplayVotes;
existingVote.TargetEntity = message.TargetEntity;
// Logger.Debug($"{existingVote.StartTime}, {existingVote.EndTime}, {_gameTiming.RealTime}");
@@ -245,7 +247,8 @@ namespace Content.Client.Voting
public string Initiator = "";
public int? OurVote;
public int Id;
public bool DisplayVotes;
public int? TargetEntity; // NetEntity
public ActiveVote(int voteId)
{
Id = voteId;

View File

@@ -0,0 +1,34 @@
using Content.Client.Ghost;
using Content.Shared.Voting;
namespace Content.Client.Voting;
public sealed class VotingSystem : EntitySystem
{
public event Action<VotePlayerListResponseEvent>? VotePlayerListResponse; //Provides a list of players elligble for vote actions
[Dependency] private readonly GhostSystem _ghostSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<VotePlayerListResponseEvent>(OnVotePlayerListResponseEvent);
}
private void OnVotePlayerListResponseEvent(VotePlayerListResponseEvent msg)
{
if (!_ghostSystem.IsGhost)
{
return;
}
VotePlayerListResponse?.Invoke(msg);
}
public void RequestVotePlayerList()
{
RaiseNetworkEvent(new VotePlayerListRequestEvent());
}
}

View File

@@ -47,10 +47,11 @@ public sealed class WeatherSystem : SharedWeatherSystem
if (!Timing.IsFirstTimePredicted || weatherProto.Sound == null)
return;
weather.Stream ??= _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true).Value.Entity;
weather.Stream ??= _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true)?.Entity;
if (!TryComp(weather.Stream, out AudioComponent? comp))
return;
var stream = weather.Stream.Value;
var comp = Comp<AudioComponent>(stream);
var occlusion = 0f;
// Work out tiles nearby to determine volume.
@@ -115,7 +116,7 @@ public sealed class WeatherSystem : SharedWeatherSystem
var alpha = GetPercent(weather, uid);
alpha *= SharedAudioSystem.VolumeToGain(weatherProto.Sound.Params.Volume);
_audio.SetGain(stream, alpha, comp);
_audio.SetGain(weather.Stream, alpha, comp);
comp.Occlusion = occlusion;
}

View File

@@ -584,17 +584,10 @@ namespace Content.Client.Wires.UI
private sealed class HelpPopup : Popup
{
private const string Text = "Click on the gold contacts with a multitool in hand to pulse their wire.\n" +
"Click on the wires with a pair of wirecutters in hand to cut/mend them.\n\n" +
"The lights at the top show the state of the machine, " +
"messing with wires will probably do stuff to them.\n" +
"Wire layouts are different each round, " +
"but consistent between machines of the same type.";
public HelpPopup()
{
var label = new RichTextLabel();
label.SetMessage(Text);
label.SetMessage(Loc.GetString("wires-menu-help-popup"));
AddChild(new PanelContainer
{
StyleClasses = {ExamineSystem.StyleClassEntityTooltip},

View File

@@ -0,0 +1,35 @@
using Content.Shared._CP14.MagicRitual;
using Robust.Client.GameObjects;
namespace Content.Server._CP14.MagicRituals;
public partial class CP14ClientRitualSystem : CP14SharedRitualSystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14MagicRitualComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(Entity<CP14MagicRitualComponent> ent, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (!args.Sprite.LayerMapTryGet(ent.Comp.RitualLayerMap, out var ritualLayer))
return;
if (_appearance.TryGetData<Color>(ent, RitualVisuals.Color, out var ritualColor, args.Component))
{
args.Sprite.LayerSetColor(ritualLayer, ritualColor);
}
if (_appearance.TryGetData<bool>(ent, RitualVisuals.Enabled, out var enabled, args.Component))
{
args.Sprite.LayerSetVisible(ritualLayer, enabled);
}
}
}

View File

@@ -0,0 +1,35 @@
<options:CP14OptionsMenuMainTab
xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.Options.UI"
xmlns:options="clr-namespace:Content.Client._CP14.Options">
<!--
Place for all custom settings of CP14
-->
<BoxContainer Orientation="Vertical">
<!-- Main options container -->
<ScrollContainer VerticalExpand="True" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<!-- Graphics group -->
<Label Text="{Loc 'cp14-ui-options-main-graphics-label'}"
StyleClasses="LabelKeyText"/>
<!-- CP14 Wave shader settings -->
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'cp14-ui-options-main-graphics-wave-shader'}" Margin="0 0 4 0"/>
<CheckBox Name="WaveShaderEnabled"/>
</BoxContainer>
</BoxContainer>
</ScrollContainer>
<!--
Utilitarian element to simplify configuration work,
ust don't touch that, okay?
-->
<ui:OptionsTabControlRow Name="Control" />
</BoxContainer>
</options:CP14OptionsMenuMainTab>

View File

@@ -0,0 +1,19 @@
using Content.Shared._CP14.Configuration;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._CP14.Options;
[GenerateTypedNameReferences]
public sealed partial class CP14OptionsMenuMainTab : Control
{
public CP14OptionsMenuMainTab()
{
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CP14ConfigVars.WaveShaderEnabled, WaveShaderEnabled);
Control.Initialize();
}
}

View File

@@ -0,0 +1,22 @@
<Control xmlns="https://spacestation14.io">
<GridContainer Columns="6">
<TextureRect Name="GoldView"
MinSize="10 10"
Stretch="KeepAspectCentered"/>
<Label Name="GoldText"
Margin="0,0,5,0"/>
<TextureRect Name="SilverView"
MinSize="10 10"
Stretch="KeepAspectCentered"/>
<Label Name="SilverText"
Margin="0,0,5,0"/>
<TextureRect Name="CopperView"
MinSize="10 10"
Stretch="KeepAspectCentered"/>
<Label Name="CopperText"
Margin="0,0,5,0"/>
</GridContainer>
</Control>

View File

@@ -0,0 +1,46 @@
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14PriceControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
private readonly SpriteSystem _sprite;
public CP14PriceControl(int price)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
var rsiPath = new ResPath("_CP14/Interface/Misc/coins.rsi");
var total = price;
var gp = total / 100;
total %= 100;
var sp = total / 10;
total %= 10;
var cp = total;
CopperView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "c"));
CopperText.Text = cp.ToString();
SilverView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "s"));
SilverText.Text = sp.ToString();
GoldView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "g"));
GoldText.Text = gp.ToString();
}
}

View File

@@ -0,0 +1,34 @@
using Content.Shared._CP14.TravelingStoreShip;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client._CP14.TravelingStoreShip;
public sealed class CP14StoreBoundUserInterface : BoundUserInterface
{
private CP14StoreWindow? _window;
public CP14StoreBoundUserInterface(EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<CP14StoreWindow>();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
switch (state)
{
case CP14StoreUiState storeState:
_window?.UpdateUI(storeState);
break;
}
}
}

View File

@@ -0,0 +1,15 @@
<Control xmlns="https://spacestation14.io">
<Button Name="ProductButton" Access="Public">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<TextureRect Name="View"
MinSize="48 48"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Stretch="KeepAspectCentered"/>
<RichTextLabel Name="ProductName" VerticalAlignment="Center" Access="Public"/>
<BoxContainer Name="PriceHolder" VerticalAlignment="Center" HorizontalExpand="True" HorizontalAlignment="Right"/>
</BoxContainer>
</BoxContainer>
</Button>
</Control>

View File

@@ -0,0 +1,44 @@
using Content.Shared._CP14.TravelingStoreShip;
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;
[GenerateTypedNameReferences]
public sealed partial class CP14StoreProductControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
private readonly SpriteSystem _sprite;
public CP14StoreProductControl(CP14StoreUiProductEntry entry)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
UpdateName(entry.Name);
UpdateView(entry.Icon);
UpdatePrice(entry.Price);
}
private void UpdatePrice(int price)
{
PriceHolder.RemoveAllChildren();
PriceHolder.AddChild(new CP14PriceControl(price));
}
private void UpdateName(string name)
{
ProductName.Text = $"[bold]{name}[/bold]";
}
private void UpdateView(SpriteSpecifier spriteSpecifier)
{
View.Texture = _sprite.Frame0(spriteSpecifier);
}
}

View File

@@ -0,0 +1,31 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'cp14-store-ui-title'}"
MinSize="800 600"
SetSize="800 600">
<BoxContainer Orientation="Horizontal">
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
<!-- Product list (left side UI) -->
<TabContainer SizeFlagsStretchRatio="0.5" Name="Tabs" HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="BuyProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="SellProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
</TabContainer>
<!-- Station trading data (right side UI) -->
<BoxContainer SizeFlagsStretchRatio="0.5" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 10 0">
<controls:StripeBack>
<PanelContainer>
<Label Text="{Loc 'cp14-store-ui-order'}" Align="Center" Margin="0 5 0 3"/>
</PanelContainer>
</controls:StripeBack>
<Label Name="TravelTimeLabel" Text="00:00" HorizontalAlignment="Center" HorizontalExpand="True" Margin="0 15 0 0"/>
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
<RichTextLabel Name="SelectedName" HorizontalExpand="True" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="5"/>
<RichTextLabel Name="SelectedDesc" HorizontalExpand="True" VerticalExpand="True" VerticalAlignment="Top" Margin="5"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,79 @@
using Content.Shared._CP14.TravelingStoreShip;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14StoreWindow : DefaultWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
private TimeSpan? _nextTravelTime;
private bool _onStation;
public CP14StoreWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
Tabs.SetTabTitle(0, Loc.GetString("cp14-store-ui-tab-buy"));
Tabs.SetTabTitle(1, Loc.GetString("cp14-store-ui-tab-sell"));
}
public void UpdateUI(CP14StoreUiState state)
{
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)
{
BuyProductsContainer.RemoveAllChildren();
SellProductsContainer.RemoveAllChildren();
foreach (var product in state.ProductsBuy)
{
var control = new CP14StoreProductControl(product);
control.ProductButton.OnPressed += _ =>
{
SelectProduct(product);
};
BuyProductsContainer.AddChild(control);
}
foreach (var product in state.ProductsSell)
{
var control = new CP14StoreProductControl(product);
control.ProductButton.OnPressed += _ =>
{
SelectProduct(product);
};
SellProductsContainer.AddChild(control);
}
}
private void SelectProduct(CP14StoreUiProductEntry? entry)
{
SelectedName.Text = entry is null ? string.Empty : $"[bold]{entry.Value.Name}[/bold]";
SelectedDesc.Text = entry is null ? string.Empty : entry.Value.Desc;
}
}

View File

@@ -35,9 +35,9 @@ public sealed partial class TestPair
mapData.GridCoords = new EntityCoordinates(mapData.Grid, 0, 0);
var plating = tileDefinitionManager[tile];
var platingTile = new Tile(plating.TileId);
mapData.Grid.Comp.SetTile(mapData.GridCoords, platingTile);
Server.System<SharedMapSystem>().SetTile(mapData.Grid.Owner, mapData.Grid.Comp, mapData.GridCoords, platingTile);
mapData.MapCoords = new MapCoordinates(0, 0, mapData.MapId);
mapData.Tile = mapData.Grid.Comp.GetAllTiles().First();
mapData.Tile = Server.System<SharedMapSystem>().GetAllTiles(mapData.Grid.Owner, mapData.Grid.Comp).First();
});
TestMap = mapData;

View File

@@ -36,7 +36,9 @@ public static partial class PoolManager
(CCVars.ConfigPresetDevelopment.Name, "false"),
(CCVars.AdminLogsEnabled.Name, "false"),
(CCVars.AutosaveEnabled.Name, "false"),
(CVars.NetBufferSize.Name, "0")
(CVars.NetBufferSize.Name, "0"),
(CCVars.InteractionRateLimitCount.Name, "9999999"),
(CCVars.InteractionRateLimitPeriod.Name, "0.1"),
};
public static async Task SetupCVars(RobustIntegrationTest.IntegrationInstance instance, PoolSettings settings)

View File

@@ -0,0 +1,108 @@
using Content.Shared.Buckle;
using Content.Shared.Buckle.Components;
using Content.Shared.Interaction;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests.Buckle;
public sealed partial class BuckleTest
{
[Test]
public async Task BuckleInteractUnbuckleOther()
{
await using var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var entMan = server.ResolveDependency<IServerEntityManager>();
var buckleSystem = entMan.System<SharedBuckleSystem>();
EntityUid user = default;
EntityUid victim = default;
EntityUid chair = default;
BuckleComponent buckle = null;
StrapComponent strap = null;
await server.WaitAssertion(() =>
{
user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace);
victim = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace);
chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace);
Assert.That(entMan.TryGetComponent(victim, out buckle));
Assert.That(entMan.TryGetComponent(chair, out strap));
#pragma warning disable RA0002
buckle.Delay = TimeSpan.Zero;
#pragma warning restore RA0002
// Buckle victim to chair
Assert.That(buckleSystem.TryBuckle(victim, user, chair, buckle));
Assert.Multiple(() =>
{
Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair.");
Assert.That(buckle.Buckled, "Victim is not buckled.");
Assert.That(strap.BuckledEntities, Does.Contain(victim), "Chair does not have victim buckled to it.");
});
// InteractHand with chair to unbuckle victim
entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair));
Assert.Multiple(() =>
{
Assert.That(buckle.BuckledTo, Is.Null);
Assert.That(buckle.Buckled, Is.False);
Assert.That(strap.BuckledEntities, Does.Not.Contain(victim));
});
});
await pair.CleanReturnAsync();
}
[Test]
public async Task BuckleInteractBuckleUnbuckleSelf()
{
await using var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var entMan = server.ResolveDependency<IServerEntityManager>();
EntityUid user = default;
EntityUid chair = default;
BuckleComponent buckle = null;
StrapComponent strap = null;
await server.WaitAssertion(() =>
{
user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace);
chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace);
Assert.That(entMan.TryGetComponent(user, out buckle));
Assert.That(entMan.TryGetComponent(chair, out strap));
#pragma warning disable RA0002
buckle.Delay = TimeSpan.Zero;
#pragma warning restore RA0002
// Buckle user to chair
entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair));
Assert.Multiple(() =>
{
Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair.");
Assert.That(buckle.Buckled, "Victim is not buckled.");
Assert.That(strap.BuckledEntities, Does.Contain(user), "Chair does not have victim buckled to it.");
});
// InteractHand with chair to unbuckle
entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair));
Assert.Multiple(() =>
{
Assert.That(buckle.BuckledTo, Is.Null);
Assert.That(buckle.Buckled, Is.False);
Assert.That(strap.BuckledEntities, Does.Not.Contain(user));
});
});
await pair.CleanReturnAsync();
}
}

View File

@@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.Buckle
[TestFixture]
[TestOf(typeof(BuckleComponent))]
[TestOf(typeof(StrapComponent))]
public sealed class BuckleTest
public sealed partial class BuckleTest
{
private const string BuckleDummyId = "BuckleDummy";
private const string StrapDummyId = "StrapDummy";

View File

@@ -39,7 +39,7 @@ public sealed class ComputerConstruction : InteractionTest
await StartDeconstruction(ComputerId);
// Initial interaction turns id computer into generic computer
await InteractUsing(Screw);
await InteractUsing(Pry);
AssertPrototype(ComputerFrame);
// Perform deconstruction steps
@@ -69,7 +69,7 @@ public sealed class ComputerConstruction : InteractionTest
await SpawnTarget(ComputerId);
// Initial interaction turns id computer into generic computer
await InteractUsing(Screw);
await InteractUsing(Pry);
AssertPrototype(ComputerFrame);
// Perform partial deconstruction steps

View File

@@ -1,4 +1,5 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using Content.Server.Body.Components;
using Content.Server.GameTicking;
@@ -120,8 +121,8 @@ public sealed class NukeOpsTest
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
var roles = roleSys.MindGetAllRoles(mind);
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander" && x.Component is NukeopsRoleComponent);
var roles = roleSys.MindGetAllRoleInfo(mind);
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander");
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
// The second dummy player should be a medic
@@ -131,8 +132,8 @@ public sealed class NukeOpsTest
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(dummyMind));
Assert.That(factionSys.IsMember(dummyEnts[1], "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(dummyEnts[1], "NanoTrasen"), Is.False);
roles = roleSys.MindGetAllRoles(dummyMind);
cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic" && x.Component is NukeopsRoleComponent);
roles = roleSys.MindGetAllRoleInfo(dummyMind);
cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic");
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
// The other two players should have just spawned in as normal.
@@ -141,13 +142,14 @@ public sealed class NukeOpsTest
void CheckDummy(int i)
{
var ent = dummyEnts[i];
var mind = mindSys.GetMind(ent)!.Value;
var mindCrew = mindSys.GetMind(ent)!.Value;
Assert.That(entMan.HasComponent<NukeOperativeComponent>(ent), Is.False);
Assert.That(roleSys.MindIsAntagonist(mind), Is.False);
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind), Is.False);
Assert.That(roleSys.MindIsAntagonist(mindCrew), Is.False);
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mindCrew), Is.False);
Assert.That(factionSys.IsMember(ent, "Syndicate"), Is.False);
Assert.That(factionSys.IsMember(ent, "NanoTrasen"), Is.True);
Assert.That(roleSys.MindGetAllRoles(mind).Any(x => x.Component is NukeopsRoleComponent), Is.False);
var nukeroles = new List<string>() { "Nukeops", "NukeopsMedic", "NukeopsCommander" };
Assert.That(roleSys.MindGetAllRoleInfo(mindCrew).Any(x => nukeroles.Contains(x.Prototype)), Is.False);
}
// The game rule exists, and all the stations/shuttles/maps are properly initialized
@@ -238,7 +240,8 @@ public sealed class NukeOpsTest
for (var i = 0; i < nukies.Length - 1; i++)
{
entMan.DeleteEntity(nukies[i]);
Assert.That(roundEndSys.IsRoundEndRequested, Is.False,
Assert.That(roundEndSys.IsRoundEndRequested,
Is.False,
$"The round ended, but {nukies.Length - i - 1} nukies are still alive!");
}
// Delete the last nukie and make sure the round ends.

View File

@@ -2,7 +2,6 @@ using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Systems;
using Content.Server.Station.Systems;
using Content.Shared.Preferences;
using Content.Shared.Roles.Jobs;
namespace Content.IntegrationTests.Tests.Internals;
@@ -25,10 +24,7 @@ public sealed class AutoInternalsTests
await server.WaitAssertion(() =>
{
var profile = new HumanoidCharacterProfile();
var dummy = stationSpawning.SpawnPlayerMob(testMap.GridCoords, new JobComponent()
{
Prototype = "TestInternalsDummy"
}, profile, station: null);
var dummy = stationSpawning.SpawnPlayerMob(testMap.GridCoords, "TestInternalsDummy", profile, station: null);
Assert.That(atmos.HasAtmosphere(testMap.Grid), Is.False, "Test map has atmosphere - test needs adjustment!");
Assert.That(internals.AreInternalsWorking(dummy), "Internals did not automatically connect!");

View File

@@ -1,10 +1,8 @@
#nullable enable
using System.Linq;
using Content.Server.Ghost;
using Content.Server.Ghost.Roles;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Mind.Commands;
using Content.Server.Players;
using Content.Server.Roles;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
@@ -18,7 +16,6 @@ using Robust.Server.Console;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
@@ -287,27 +284,27 @@ public sealed partial class MindTests
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
});
var traitorRole = new TraitorRoleComponent();
var traitorRole = "MindRoleTraitor";
roleSystem.MindAddRole(mindId, traitorRole);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
});
var jobRole = new JobComponent();
var jobRole = "";
roleSystem.MindAddRole(mindId, jobRole);
roleSystem.MindAddJobRole(mindId, jobPrototype:jobRole);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId));
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId));
});
roleSystem.MindRemoveRole<TraitorRoleComponent>(mindId);
@@ -315,15 +312,15 @@ public sealed partial class MindTests
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId));
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId));
});
roleSystem.MindRemoveRole<JobComponent>(mindId);
roleSystem.MindRemoveRole<JobRoleComponent>(mindId);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
});
});

View File

@@ -3,7 +3,6 @@ using Content.Server.Station.Systems;
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles.Jobs;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
@@ -68,10 +67,7 @@ public sealed class LoadoutTests
profile.SetLoadout(new RoleLoadout("LoadoutTester"));
var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: new JobComponent()
{
Prototype = "LoadoutTester"
}, profile, station: null);
var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: "LoadoutTester", profile, station: null);
var slotQuery = inventorySystem.GetSlotEnumerator(tester);
var checkedCount = 0;

View File

@@ -0,0 +1,53 @@
using Content.Shared._CP14.MagicRitual;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests._CP14;
#nullable enable
[TestFixture]
public sealed class CP14RitualTest
{
/// <summary>
/// States that all edges of the ritual phase have triggers.
/// </summary>
[Test]
public async Task RitualHasAllTriggersTest()
{
await using var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var compFactory = server.ResolveDependency<IComponentFactory>();
var protoManager = server.ResolveDependency<IPrototypeManager>();
await server.WaitAssertion(() =>
{
Assert.Multiple(() =>
{
foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>())
{
if (!proto.TryGetComponent(out CP14MagicRitualPhaseComponent? phase, compFactory))
continue;
if (phase.DeadEnd)
{
Assert.That(phase.Edges.Count == 0, $"{proto} is a ritual node, but has no paths to other nodes. Either add deadEnd = true, or add paths to other nodes.");
}
else
{
Assert.That(phase.Edges.Count > 0, $"{proto} is a deadEnd ritual node, but has {phase.Edges.Count} edges! Remove all edges, or make it a non dead-end node");
}
foreach (var edge in phase.Edges)
{
Assert.That(edge.Triggers.Count > 0, $"{{proto}} is ritual node, but edge to {edge.Target} has no triggers and cannot be activated.");
}
}
});
});
await pair.CleanReturnAsync();
}
}

View File

@@ -32,7 +32,7 @@ namespace Content.Server.Access.Systems
private void OnAfterInteract(EntityUid uid, AgentIDCardComponent component, AfterInteractEvent args)
{
if (!TryComp<AccessComponent>(args.Target, out var targetAccess) || !HasComp<IdCardComponent>(args.Target) || args.Target == null)
if (args.Target == null || !args.CanReach || !TryComp<AccessComponent>(args.Target, out var targetAccess) || !HasComp<IdCardComponent>(args.Target))
return;
if (!TryComp<AccessComponent>(uid, out var access) || !HasComp<IdCardComponent>(uid))
@@ -67,7 +67,7 @@ namespace Content.Server.Access.Systems
if (!TryComp<IdCardComponent>(uid, out var idCard))
return;
var state = new AgentIDCardBoundUserInterfaceState(idCard.FullName ?? "", idCard.JobTitle ?? "", idCard.JobIcon);
var state = new AgentIDCardBoundUserInterfaceState(idCard.FullName ?? "", idCard.LocalizedJobTitle ?? "", idCard.JobIcon);
_uiSystem.SetUiState(uid, AgentIDCardUiKey.Key, state);
}

View File

@@ -96,7 +96,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
PrivilegedIdIsAuthorized(uid, component),
true,
targetIdComponent.FullName,
targetIdComponent.JobTitle,
targetIdComponent.LocalizedJobTitle,
targetAccessComponent.Tags.ToList(),
possibleAccess,
jobProto,

View File

@@ -1,5 +1,7 @@
using System.Linq;
using System.Text;
using Content.Server.Administration.BanList;
using Content.Server.EUI;
using Content.Server.Database;
using Content.Shared.Administration;
using Robust.Server.Player;
@@ -10,6 +12,12 @@ namespace Content.Server.Administration.Commands;
[AdminCommand(AdminFlags.Ban)]
public sealed class RoleBanListCommand : IConsoleCommand
{
[Dependency] private readonly IServerDbManager _dbManager = default!;
[Dependency] private readonly EuiManager _eui = default!;
[Dependency] private readonly IPlayerLocator _locator = default!;
public string Command => "rolebanlist";
public string Description => Loc.GetString("cmd-rolebanlist-desc");
public string Help => Loc.GetString("cmd-rolebanlist-help");
@@ -29,66 +37,37 @@ public sealed class RoleBanListCommand : IConsoleCommand
return;
}
var dbMan = IoCManager.Resolve<IServerDbManager>();
var data = await _locator.LookupIdByNameOrIdAsync(args[0]);
var target = args[0];
var locator = IoCManager.Resolve<IPlayerLocator>();
var located = await locator.LookupIdByNameOrIdAsync(target);
if (located == null)
if (data == null)
{
shell.WriteError("Unable to find a player with that name or id.");
return;
}
var targetUid = located.UserId;
var targetHWid = located.LastHWId;
var targetAddress = located.LastAddress;
var bans = await dbMan.GetServerRoleBansAsync(targetAddress, targetUid, targetHWid, includeUnbanned);
if (bans.Count == 0)
if (shell.Player is not { } player)
{
shell.WriteLine("That user has no bans in their record.");
var bans = await _dbManager.GetServerRoleBansAsync(data.LastAddress, data.UserId, data.LastHWId, includeUnbanned);
if (bans.Count == 0)
{
shell.WriteLine("That user has no bans in their record.");
return;
}
foreach (var ban in bans)
{
var msg = $"ID: {ban.Id}: Role: {ban.Role} Reason: {ban.Reason}";
shell.WriteLine(msg);
}
return;
}
var bansString = new StringBuilder("Bans in record:\n");
var ui = new BanListEui();
_eui.OpenEui(ui, player);
await ui.ChangeBanListPlayer(data.UserId);
var first = true;
foreach (var ban in bans)
{
if (!first)
bansString.Append("\n\n");
else
first = false;
bansString
.Append("Ban ID: ")
.Append(ban.Id)
.Append('\n')
.Append("Role: ")
.Append(ban.Role)
.Append('\n')
.Append("Banned on ")
.Append(ban.BanTime);
if (ban.ExpirationTime != null)
{
bansString
.Append(" until ")
.Append(ban.ExpirationTime.Value);
}
bansString
.Append('\n');
bansString
.Append("Reason: ")
.Append(ban.Reason);
}
shell.WriteLine(bansString.ToString());
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)

View File

@@ -4,11 +4,15 @@ using Content.Server.Hands.Systems;
using Content.Server.Preferences.Managers;
using Content.Shared.Access.Components;
using Content.Shared.Administration;
using Content.Shared.Clothing;
using Content.Shared.Hands.Components;
using Content.Shared.Humanoid;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Content.Shared.Station;
using Robust.Shared.Console;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
@@ -82,9 +86,11 @@ namespace Content.Server.Administration.Commands
return false;
HumanoidCharacterProfile? profile = null;
ICommonSession? session = null;
// Check if we are setting the outfit of a player to respect the preferences
if (entityManager.TryGetComponent(target, out ActorComponent? actorComponent))
{
session = actorComponent.PlayerSession;
var userId = actorComponent.PlayerSession.UserId;
var preferencesManager = IoCManager.Resolve<IServerPreferencesManager>();
var prefs = preferencesManager.GetPreferences(userId);
@@ -128,6 +134,36 @@ namespace Content.Server.Administration.Commands
}
}
// See if this starting gear is associated with a job
var jobs = prototypeManager.EnumeratePrototypes<JobPrototype>();
foreach (var job in jobs)
{
if (job.StartingGear != gear)
continue;
var jobProtoId = LoadoutSystem.GetJobPrototype(job.ID);
if (!prototypeManager.TryIndex<RoleLoadoutPrototype>(jobProtoId, out var jobProto))
break;
// Don't require a player, so this works on Urists
profile ??= entityManager.TryGetComponent<HumanoidAppearanceComponent>(target, out var comp)
? HumanoidCharacterProfile.DefaultWithSpecies(comp.Species)
: new HumanoidCharacterProfile();
// Try to get the user's existing loadout for the role
profile.Loadouts.TryGetValue(jobProtoId, out var roleLoadout);
if (roleLoadout == null)
{
// If they don't have a loadout for the role, make a default one
roleLoadout = new RoleLoadout(jobProtoId);
roleLoadout.SetDefault(profile, session, prototypeManager);
}
// Equip the target with the job loadout
var stationSpawning = entityManager.System<SharedStationSpawningSystem>();
stationSpawning.EquipRoleLoadout(target, roleLoadout, jobProto);
}
return true;
}
}

View File

@@ -52,7 +52,6 @@ public sealed partial class AdminVerbSystem
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
[Dependency] private readonly JointSystem _jointSystem = default!;
[Dependency] private readonly BatterySystem _batterySystem = default!;
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
[Dependency] private readonly GunSystem _gun = default!;
@@ -90,22 +89,22 @@ public sealed partial class AdminVerbSystem
args.Verbs.Add(bolt);
}
if (TryComp<AirlockComponent>(args.Target, out var airlock))
if (TryComp<AirlockComponent>(args.Target, out var airlockComp))
{
Verb emergencyAccess = new()
{
Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
Text = airlockComp.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
Act = () =>
{
_airlockSystem.ToggleEmergencyAccess(args.Target, airlock);
_airlockSystem.SetEmergencyAccess((args.Target, airlockComp), !airlockComp.EmergencyAccess);
},
Impact = LogImpact.Medium,
Message = Loc.GetString(airlock.EmergencyAccess
Message = Loc.GetString(airlockComp.EmergencyAccess
? "admin-trick-emergency-access-off-description"
: "admin-trick-emergency-access-on-description"),
Priority = (int) (airlock.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
Priority = (int) (airlockComp.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
};
args.Verbs.Add(emergencyAccess);
}
@@ -327,7 +326,7 @@ public sealed partial class AdminVerbSystem
Act = () =>
{
var (mapUid, gridUid) = _adminTestArenaSystem.AssertArenaLoaded(player);
_xformSystem.SetCoordinates(args.Target, new EntityCoordinates(gridUid ?? mapUid, Vector2.One));
_transformSystem.SetCoordinates(args.Target, new EntityCoordinates(gridUid ?? mapUid, Vector2.One));
},
Impact = LogImpact.Medium,
Message = Loc.GetString("admin-trick-send-to-test-arena-description"),
@@ -533,7 +532,7 @@ public sealed partial class AdminVerbSystem
if (shuttle is null)
return;
_xformSystem.SetCoordinates(args.User, new EntityCoordinates(shuttle.Value, Vector2.Zero));
_transformSystem.SetCoordinates(args.User, new EntityCoordinates(shuttle.Value, Vector2.Zero));
},
Impact = LogImpact.Low,
Message = Loc.GetString("admin-trick-locate-cargo-shuttle-description"),

View File

@@ -35,10 +35,8 @@ using Robust.Shared.Toolshed;
using Robust.Shared.Utility;
using System.Linq;
using Content.Server.Silicons.Laws;
using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components;
using Robust.Server.Player;
using Content.Shared.Mind;
using Robust.Shared.Physics.Components;
using static Content.Shared.Configurable.ConfigurationComponent;
@@ -63,7 +61,6 @@ namespace Content.Server.Administration.Systems
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly PrayerSystem _prayerSystem = default!;
[Dependency] private readonly EuiManager _eui = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly ToolshedManager _toolshed = default!;
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
@@ -294,7 +291,7 @@ namespace Content.Server.Administration.Systems
Act = () =>
{
var ui = new AdminLogsEui();
_eui.OpenEui(ui, player);
_euiManager.OpenEui(ui, player);
ui.SetLogFilter(search:args.Target.Id.ToString());
},
Impact = LogImpact.Low

View File

@@ -15,6 +15,7 @@ using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Mind;
using Content.Shared.Players.RateLimiting;
using JetBrains.Annotations;
using Robust.Server.Player;
using Robust.Shared;
@@ -104,12 +105,10 @@ namespace Content.Server.Administration.Systems
_rateLimit.Register(
RateLimitKey,
new RateLimitRegistration
{
CVarLimitPeriodLength = CCVars.AhelpRateLimitPeriod,
CVarLimitCount = CCVars.AhelpRateLimitCount,
PlayerLimitedAction = PlayerRateLimitedAction
});
new RateLimitRegistration(CCVars.AhelpRateLimitPeriod,
CCVars.AhelpRateLimitCount,
PlayerRateLimitedAction)
);
}
private void PlayerRateLimitedAction(ICommonSession obj)

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System.Numerics;
using Content.Server.Anomaly.Components;
using Content.Server.DeviceLinking.Systems;
using Content.Server.Power.Components;
@@ -10,6 +11,7 @@ using Content.Shared.Popups;
using Content.Shared.Power;
using Robust.Shared.Audio.Systems;
using Content.Shared.Verbs;
using Robust.Shared.Timing;
namespace Content.Server.Anomaly;
@@ -25,6 +27,7 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly PowerReceiverSystem _power = default!;
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
@@ -40,6 +43,34 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
SubscribeLocalEvent<AnomalyStabilityChangedEvent>(OnAnomalyStabilityChanged);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<AnomalySynchronizerComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var sync, out var xform))
{
if (sync.ConnectedAnomaly is null)
continue;
if (_timing.CurTime < sync.NextCheckTime)
continue;
sync.NextCheckTime += sync.CheckFrequency;
if (Transform(sync.ConnectedAnomaly.Value).MapUid != Transform(uid).MapUid)
{
DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value);
continue;
}
if (!xform.Coordinates.TryDistance(EntityManager, Transform(sync.ConnectedAnomaly.Value).Coordinates, out var distance))
continue;
if (distance > sync.AttachRange)
DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value);
}
}
/// <summary>
/// If powered, try to attach a nearby anomaly.
/// </summary>
@@ -73,10 +104,10 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
if (args.Powered)
return;
if (!TryComp<AnomalyComponent>(ent.Comp.ConnectedAnomaly, out var anomaly))
if (ent.Comp.ConnectedAnomaly is null)
return;
DisconnectFromAnomaly(ent, anomaly);
DisconnectFromAnomaly(ent, ent.Comp.ConnectedAnomaly.Value);
}
private void OnExamined(Entity<AnomalySynchronizerComponent> ent, ref ExaminedEvent args)
@@ -125,13 +156,16 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
//TODO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
//Currently only bluespace anomaly can do this, but for some reason it is the only one that cannot be connected to the synchronizer.
private void DisconnectFromAnomaly(Entity<AnomalySynchronizerComponent> ent, AnomalyComponent anomaly)
private void DisconnectFromAnomaly(Entity<AnomalySynchronizerComponent> ent, EntityUid other)
{
if (ent.Comp.ConnectedAnomaly == null)
return;
if (ent.Comp.PulseOnDisconnect)
_anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly);
if (TryComp<AnomalyComponent>(other, out var anomaly))
{
if (ent.Comp.PulseOnDisconnect)
_anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly);
}
_popup.PopupEntity(Loc.GetString("anomaly-sync-disconnected"), ent, PopupType.Large);
_audio.PlayPvs(ent.Comp.ConnectedSound, ent);

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