Files
crystall-punk-14/Content.Server/NPC/Systems/NPCUtilitySystem.cs
Ed 0a46df78ea Upstream sync (#1035)
* Add new implants to deimplant list (#35563)

Initial commit

* Doxarubixadone Description Fix (#35568)

Changed medicine.ftl for Doxa.

* Reptilians Can Eat Chicken Nuggets (#35569)

Added meat tag to misc.yml for chicken nuggets.

* Automatic changelog update

* Unheck Admin Smites (#35348)

* Fix admin verb names

Fixed admin verb names.

* Add antag verb names

* Adjust antag verb icons

* Amber Station - A Couple Changes (#35548)

* [ADMIN] Minor Refactor AdminNameOverlay (#35520)

* refactor(src): Minor refactor of Draw in "AdminNameOverlay. And new info about playtime player

* fix(src): Add configure classic admin owerlay

* fix

* tweak(src): Use _antagLabelClassic and tweak style

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

* tweak(src): Vector2 is replaced by var

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

* Automatic changelog update

* Wizard PDA (#35572)

* wizard PDA

* colour change to brown

* Automatic changelog update

* Increase line spacing of the admin overlay (#35591)

line spacing

* make slime hair less transparent (#35158)

* blabl blump or something

* +0.3

* blimpuf

* Automatic changelog update

* Fix being able to write on/stamp/fax paper scrap (#35596)

* init

* item

* requested changes

* Apply suggestions from code review

---------

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

* Automatic changelog update

* Changed Pride to Hubris in ion_storm.yml (#35602)

Update ion_storm.yml

* Sentry turrets - Part 3: Turret AI (#35058)

* Initial commit

* Updated Access/command.yml

* Fix for Access/AccessLevelPrototype.cs

* Added silicon access levels to admin items

* Included self-recharging battery changes

* Revert "Included self-recharging battery changes"

* Addressed reviewers comments

* Additional reviewer comments

* DetGadget Hat Revitalization (#35438)

* DetGadget Hat

* uh... half-assed item description

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

* Fix Integration Errors

* Only the wearer can access voice commands

* init work - handscomp is unable to be pulled

* second bit of progress

* basic working implementation

* nuke storageslots and add adminlogging

* disallow trolling nukies or hiding objective items

* remove unnecessary tags additions

* finish nuking unused tags

* death to yamllinter

* int tests be damned

* milon is a furry

* address review

* upd desc

* address reviews part 2

* address more reviews

* remove unused refs

* fix order of dependencies

* add ShowVerb to SharedStorageSystem.cs

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

* orks is a nerd

* add proper locale, fix adminlogging

* orks is a nerd 2

---------

Co-authored-by: Coenx-flex <coengmurray@gmail.com>

* Automatic changelog update

* Fingerprint Reader System (#35600)

* init

* public api

* stuff

* weh

* Remove cellular resistance for slimes (#35583)

* Remove cellular resistance for slimes

* Update guidebook

* Automatic changelog update

* Give the station map inhand sprites (#35605)

map has inhands

* Reagent guidebook reactions UI dividers (#35608)

* Update GuideReagentReaction.xaml

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

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

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

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

---------

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

* fix cluwne pda pen slot (#35611)

Co-authored-by: deltanedas <@deltanedas:kde.org>

* Revert "Make radioactive material radioactive" (#35330)

* Automatic changelog update

* Predict vending machine UI (#33412)

* Automatic changelog update

* #32209 changelog (#35619)

Since it was merged into staging no changelog was made, but we should at least have it for next release. (And vulture)

* Automatic changelog update

* Cloning Refactor and bugfixes (#35555)

* cloning refactor

* cleanup and fixes

* don't pick from 0

* give dwarves the correct species

* fix dna and bloodstream reagent data cloning

* don't copy helmets

* be less redundant

* Automatic changelog update

* centcomm update (#35627)

* Better Insectoid Glasses (#31812)

Sprites and file changes

Adds the variants for arachnid and moth glasses, adds the code for those in the meta.json files, and adds the speciesID tag in both arachnid and moth prototype files.

* Automatic changelog update

* Add GetBaseName method to NameModifierSystem (#35633)

* Add GetBaseName method to NameModifierSystem

* Use Name

* Save Space Station 14 from the Toilet Gibber Forever (#35587)

* The evil is defeated

* Tag body bags

* uwu, cwush me cwusher-chan

* absolute 18+ sloggery

* botos binted? 👽

* Automatic changelog update

* Changed Damage Overlay to check Burn Damage (#34535)

* updated BruteLevel to be PainLevel with burn damage checks in DamageOverlayUiController.cs

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

* re-added the name for painDamageGroups

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

* renamed to PainDamageGroups and removed obsolete tag

* Automatic changelog update

* Wizard's Magical Pen (#35623)

* wizard pen

* description change

* Automatic changelog update

* Added decelerator percentage drain (#35643)

* Added variable PercentageDrain to SinguloFoodComponent

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

* Added percentageDrain logic in public OnConsumed

* Simplify SinguloFoodComponent and set percentageDrain to negative

* EnergyFactor now applies to positive values too

* Better commenting on EnergyFactor

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

* Documentation of EnergyFactor

* Fixing spelling mistake

---------

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

* Automatic changelog update

* Made butter require less milk (#35650)

made butter take less milk

* Automatic changelog update

* Delete SolutionContainerVisualsComponent.InitialName (#35654)

* Fix name of cotton dough rope (#35657)

changed in-game name of cotton dough rope to differentiate from normal dough rope

* CVar - Toggle display of round-end greentext (#35651)

* hide greentext if cvar false

* change IFs around a lil

* reviews

* Open State for cowtools (#35666)

Open State

* Make implants unshielded (#35667)

* Add undergarments & "Censor Nudity" toggle to options (#33185)

* Initial commit

* Attribution

* Review changes

* Added comment for upstream

* Automatic changelog update

* centcomm update (#35674)

* More scars! (#35644)

* :3

* whitespace, stomach scar

* Automatic changelog update

* Lathe menu UI displays a count of available recipes (#35570)

* commit

* jumped the gun

* changes

* Players with unknown playtimes now are tagged as new players, take 2 (#35648)

* your commit? our commit.

* skreee

* show joined players before lobby players; comments

* comments

* playerinfo retains playtime data after disconnect

* new connection status symbols

* Automatic changelog update

* Add firelocks and locked external airlocks to ATS (#35516)

* Add firelocks and locked airlocks to ATS

* Add fire alarms

* Elkridge Tesla and TEG Improvements + Other stuff (#35684)

* better tesla, better TEG, better sci maints, chef gets chef closet

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

* ran fixgridatmos and added some vacuum markers

* unflatpacked containment shit

* Cargo Mail System (#35429)

* shitcode init

* biocoding, SpawnTableOnUse, Moving shit to shared

* server :(

* fixes

* ok works

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

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

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

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

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

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

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

* big stuff

* preperation

* temperory spawning thing for testing

* Update CargoDeliveryDataComponent.cs

* kinda proper spawning idk god save me

* cleanup (kinda)

* preparation 2.0

* stuff i think

* entity table work

* renames

* spawn ratio based on players

* comment

* letter tables

* more spam

* package tables

* comment

* biocodedn't

* builds correctly

* cleaning

* Update deliveries_tables.yml

* labels

* package sprites

* mail teleporter

* revert testing value

* fix test

* fix other test

* i love tests

* mail teleporter enabled by default

* random cooldowns

* fixtures

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

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

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

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

* clean

* fuck paper scrap

* oops

* fuck SpawnTableOnUse

* mail teleporter board in QM locker + addressed review

* oops

* clean

* sound on delivery spawn

* address review

* partial review address

* partial review addressing

* addressing partial review

* pratarial revivew address

* misprediction hell

* stuff

* more stuff

* unrelated

* TODO

* link

* partial review

* DirtyField

---------

Co-authored-by: Milon <milonpl.git@proton.me>

* Automatic changelog update

* Add AssertMultiple to ContrabandTest (#35662)

* add AssertMultiple to ContrabandTest

* do the same for magazine visuals test

* :trollface:

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>

* add forceghost admin command (#35518)

* add forceghost admin command

* sweep linq under the rug

* braces

* ûse LocalizedEntityCommands

* Automatic changelog update

* Text related keybinds can now be changed in Controls (#35630)

* Add ability to rebind text related keybinds

* fix placement of locales

* Automatic changelog update

* Update b2dynamictree (#30630)

* Update submodule to 248.0.0 (#35720)

* Add sun shadows (planet lighting stage 2) (#35145)

* Implements a Dynamic Lighting System on maps.

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

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

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

* Removing ununsed import

* Minor tweaks

* Tweak in time precision

* Minor tweak + Unused import removed

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

* Fix: Now the time is calculated correctly.

* Minor tweaks

* Adds condition for when the light should be updated

* Add planet lighting

* she

* close-ish

* c

* bittersweat

* Fixes

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

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

* Europa and day-night

* weh

* rooves working

* Clean

* Remove Europa

* Fixes

* fix

* Update

* Fix caves

* Update for engine

* Add sun shadows (planet lighting v2)

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

* Documentation

* a

* Fixes

* Move blur to an overlay

* Slughands

* Fixes

* Apply RoofOverlay per-grid not per-map

* Fix light render scales

* sangas

* Juice it a bit

* Better angle

* Fixes

* Add color support

* Rounding bandaid

* Wehs

* Better

* Remember I forgot to do this when writing docs

---------

Co-authored-by: DoutorWhite <thedoctorwhite@gmail.com>

* Automatic changelog update

* Omega Mail Teleporter (#35705)

Mail!

* Packed Mail Teleporter (#35706)

Mail!

* Box Mail Teleporter (#35707)

Mail!

* Oasis Mail Teleporter (#35708)

Mail!

* Meta Mail Teleporter (#35709)

Mail!

* Marathon Mail Teleporter (#35710)

Mail!

* Fland Mail Teleporter (#35711)

Mail!

* Plasma fixes 4 (#35716)

Fixes 15

Co-authored-by: jbox1 <40789662+jbox144@users.noreply.github.com>

* Aroace pride pin, scarf, and cloak (#35718)

cloak, pin, and scarf added yayyyy

* Automatic changelog update

* [Part of #32893] Localize silicon dataset names (#33352)

* Localize ai names

* Apply requested changes

* Localize autoborg

* Localize borg names

* Localize atv names

* Correct prototypes ids to follow naming conventions

* Remove AI localization (Moved to another PR)

* Weh

* [Part of #32893] Localize arachnid dataset names (#33353)

* Localize arachnid dataset names

* Correct prototype ids to follow naming conventions

* Combine arachnid_first.yml and arachnid_last.yml

* Upstream names

* [Part of #32893] Localize summonable creatures dataset names (#33392)

* Localize clown names

* Localize golem names

* Localize hologram names

* Correct prototype ids to follow naming conventions

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

---------

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

* [Part of #32893] Localize antagonists dataset names (#33393)

* Localize fake human names

* Localize ninja names

* Localize operation names

* Localize regalrat names

* Localize revenant names

* Localize syndicate names

* Localize wizard names

* Correct prototype ids to follow naming conventions

* Combine fake_human_first.yml and fake_human_last.yml

* Move contents of ninja_title.yml into ninja.yml

* Combine Operation_prefix.yml and Operation_suffix.yml

* Combine wizard_first.yml and wizard_last.yml

* Upstream names

* fix wizard

---------

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

* [Part of #32893] Localize humanoid species dataset names (#33395)

* Localize diona names

* Localize moth names

* Localize mushman names

* Localize reptilian names

* Localize skeleton names

* Upstream diona names

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

* Correct prototype ids to follow naming conventions

* NamesSkeletonFirst -> NamesSkeleton

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

* Forgot about skeleton prototype

* Upstream names

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

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

* keep first name for skeleton

---------

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

* [Part of #32893] Localize vox dataset names (#33396)

* Localize vox names

* Correct prototype id to follow naming conventions

* Upstream names

* [Part of #32893] Localize first & last dataset names (#33401)

* Localize first names

* Localize last names

* Correct prototype ids to follow naming conventions

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

* Forgot about = in last

* [Part of #32893] Localize first male & female dataset names (#33402)

* Localize first_name

* Localize first_female

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

* Correct prototype ids to follow naming conventions

* Combine first_male.yml and first_female.yml into base_gendered.yml

* [Part of #32893] Localize misc dataset names (#33404)

* Localize cargo_shuttle names

* Localize death_commando names

* Localize fortunes

* Localize military names

* Localize rollie names

* fortunes.ftl -> cookie_fortune.ftl

* Correct prototype ids to follow naming conventions

* Localize all dataset names (#32893)

* Use `LocalizedDatasetPrototype` instead of `DatasetPrototype` in `RoleLoadoutPrototype`

* Localize ai names

* Replace to `LocalizedDatasetPrototype` in `NamingSystem`

* Localize arachnid first and last names

* Localize atv names

* Localize autoborg names

* Forgot to change type to localizedDataset

* Localize borer names

* Localize borg names

* Localize cargo shuttle names

* Localize clown names

* Localize death_commando names

* Localize diona names

* Localize fake_human names

* Localize first and last names

* Localize first male and female names

* Localize fortunes descriptions

* Forgot about equal sign

* Localize golem names

* Localize hologram names

* Localize military names

* Localize moth first male and female names

* Localize moth last names

* Fix autoborg name error

* Localize mushman first and last names

* Localize ninja names

* Localize operation names

* Localize regalrat names

* Fix mushman_first

* Forgot about `Loc.GetString`

* Move comments into comment section & fix names

* Localize reptilian male and female names

* Localize revenant names

* Fix locale word order in operation

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

* Localize skeleton_first names

* Localize syndicate names

* Localize vox names

* Localize wizard first and last names

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

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

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

* I hate those mothname comments

* Combine name datasets prototypes

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

* Remove ftl files

* Get every dataset yml back

* Remove changes for planets. Move it in another PR

* Revert these changes (Moved to another PR)

* How

* Apply suggested changes

* Fix integration tests (#35727)

* test

* fix names

* fix more

* Initial delivery balance changes (#35728)

* init

* small balance

* guess not

* Update Content.Server/Delivery/CargoDeliveryDataComponent.cs

---------

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

* Fixed delivery popups (#35724)

* :)

* cool stuff

* Remove a bonus Loc.GetString (#35731)

oops

* Bagel Engineering Improvements (#35717)

* woe, better engineering be upon ye

* im going to lose it

* radical plan

* oopsie

* Revert "oopsie"

This reverts commit 45ab057f55b46acd795e58257c3cc5967e5cb946.

* Revert "radical plan"

This reverts commit 57b1ae081725a47aef3ae03111cecbc91b4f47a8.

* Revert "im going to lose it"

This reverts commit e7b4afaf5d9a10a42e89831ffc9294d3b9bd96d4.

* Revert "woe, better engineering be upon ye"

This reverts commit 471dc3716b58a39631aa8bee00de79e981391d63.

* complete revamp

* revision

* oops 2 electric boogaloo

* another one

* every time i push to fix a minor mistake i found in walking around i get closer to my limit

* Update Credits (#35733)

Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>

* Loop mail teleporter (#35729)

* latejoin

* youve got mail

* Core mail update (#35719)

* core mail update

* empty

* derotate core (#35740)

Update default.yml

* Elkridge Mail Update (#35738)

add mail teleporter and mailing unit system

* Automatic changelog update

* Plasma Mail Teleporter (#35741)

Mail!

* Convex Mail Teleporter (#35742)

Mail!

* Remove unneeded Loc.GetString (#35739)

* Steal the mail thieving objective (#35746)

* mail theft

* networked

* Automatic changelog update

* fix UpdateBankAccount (#35749)

* trolled

* fun

* fuck me

* Slightly better letter loot table (#35748)

* init

* review

---------

Co-authored-by: Milon <milonpl.git@proton.me>

* Python Suit Storage Visual  (#35593)

* Python-SUITSTORAGE-Visuals

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

* REVised Sprite

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

* Copyright

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

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

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

---------

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

* fix nukeops commander name (#35753)

* bagel update (#35754)

* Predict some power PowerReceiver stuff (#33834)

* Predict some power PowerReceiver stuff

Need it for some atmos device prediction.

* Also this

* Localize traitor codeverbs datasets (#35737)

* Localize verbs dataset

* Localize adjectives dataset

* Localize corporations dataset

* Update TraitorRuleSystem to use LocalizedDatasetPrototype instead of DatasetPrototype

* Fix sun shadows in ANGLE (#35757)

I think I fat-fingered a ctrl-Z on this at some point but the intermediate blur is necessary.

* Automatic changelog update

* Tweak sun shadow rotations (#35758)

Won't use the entity's rotation for the matrix, I just forgot to do this. Means shadows will always point in the same direction and the points will correctly adjust as the entity rotates.

* Automatic changelog update

* Fix Ahelp window playerlist resize (#35747)

reorganize bwoink window layout

* Automatic changelog update

* Ensure speech bubble cap is always respected (#32223)

Ensure speech bubble cap is respected, even when messages are sent very fast

* Cleanup: Fix ``PaperWriteEvent`` in ``PaperSystem`` (#35763)

* Cleanup + fix

* Revert

* Cleanup: Add missing locale ``cmd-planet-map-prototype`` (#35766)

Cleanup

* Added New Cocktails and new fill level sprites to existing drinks. (#33570)

* Added New Cocktails and new fill level sprites to existing drinks

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

---------

Co-authored-by: RedBookcase <Usualmoves@gmail.com>

* Automatic changelog update

* Performer's Wig (#35764)

* miku wig

* fix to correct json convention

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

---------

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

* Automatic changelog update

* Merge showsubfloorforever into showsubfloor (#33682)

* convex fix

* Removable mindshields and revolutionary tweaks. (#35769)

* I fucking hate revs

* Update preset-revolutionary.ftl

* fixy fix

* Automatic changelog update

* Mail Resprite (#35776)

* init commit

* init commit

* delete those

* added github to copyright info

* Fix Chameleon PDAs renaming the user in station records (#35782)

* Automatic changelog update

* Restore the order of admin overlay elements (#35783)

admin overlay order fix

* Automatic changelog update

* Fixes and refactoring to discord changelog script (#33859)

* Fixes and refactoring to discord changelog script

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

* Add some prints back in

* Update to borg ion storms (#35751)

* Updates ion storms for borgs.

* Remove additional ion laws into future PR

* Automatic changelog update

* TriggerSystem improvements (#35762)

* desynchronizer real

* yaml stuff from slarti branch

* C# stuff

* oops

* fix triggers

* atomize PR

---------

Co-authored-by: Flareguy <woaj9999@outlook.com>

* Roleban command error handling (#35784)

roleban command jobid fail handling

* Localize news dataset (#35774)

* Localize news dataset

* Remove the `"`

* Localize rat king commands datasets (#35780)

* Added mail room

* Update submodule to 248.0.2 (#35787)

* Update Space Law to reflect Implant changes (#35701)

* Change implanter Space Law

* Add clarification regarding unidentified implanter vs. unidentified implant sentensing

* Add support for antag-before-job selection (#35789)

* Add support for antag-before-job selection

* Include logging

* forensics cleanup (#35795)

* polymorph popup fixes (#35796)

polymorph fixes

* fix more syndicate names (#35788)

* New Feature: Warden job rolls before security officer/cadet/detective (#35313)

Commit

* Automatic changelog update

* Fix anomaly doublelogging (#34297)

cull doublelogging

* Add wallmount N2 closets, Revived (#34042)

* Add standard, wallmount and improvised N2 closets, Revived

* remove improvised locker

* Parent>ID

* Undo sprite replacement

* Update meta.json

---------

Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
Co-authored-by: Milon <milonpl.git@proton.me>

* Cryo and grinder cleanup (#34842)

* cryopod and grinder cleanup

* lower case name

* 4 spaces

* prototype clean

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

* grinder too

* both should be empty

* cleanup

* Add Gold and Coal Rock Anomalies (#34809)

* This commit adds 2 new Rock Anomaly types, Coal and Gold. It also adds Resource Crabs, colored crystals, and lights for both.

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

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

* Updated Texture Copyright information

* Attempted to fix Merge Conflict

* Added bulb light variants for both yellow and black crystals.

* Automatic changelog update

* Tools/Devices: In-hand Sprites (#33689)

* Adds in-hand sprites to the barber scissors.

* adds in-hand sprites to the floodlight.

* adds in-hand sprites to the gas analyzer.

* adds in-hand sprites to the gps.

* Update copyright wording, linting

* resprite gps inhand sprites.

* adds in-hand sprites to the mass scanner.

* adds in-hand sprites to the spray_painter.

* resprite in-hand sprites to the mass_scanner.

* fix in-hand sprites to the mass_scanner.

* Resprite mass_scanner in-hand sprites.

* Automatic changelog update

* IconSmooth additional smoothing keys (#35790)

* additionalKeys

* Update lava.yml

* Update Content.Client/IconSmoothing/IconSmoothComponent.cs

---------

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

* Locks nitrous oxide canisters (#35785)

lock nitrous oxide canisters

* Automatic changelog update

* Cleanup Objective files, add PickSpecificPersonComponent (#35802)

* cleanup objectives

* remove unrelated access restriction

* review

* Adds popup when firing gun while gun has no ammo (#34816)

* Adds popup when firing gun while gun has no ammo

* simplify

---------

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

* Automatic changelog update

* Add the ability to pet the mail teleporter (#35819)

good mailbox

* Automatic changelog update

* Whitehole/Singularity grenade price adjustments + whitehole grenade fix (#35821)

* prices + adjustments

* teehee

* Automatic changelog update

* Update Lobby Music Attribtions (#35817)

Biggest change is updating the attributions and links for Sunbeamstress' to reflect the changes in their online profile as the previous link is now a dead link.
Updated Comet Haley's link to go directly to Stellardrone's Bandcamp instead of diverting to Free Music Archive
Fixed a double the in the comment for Space Asshole

* Paradox Clone (#35794)

* polymorph fixes

* paradox clone

* forensics cleanup

* bump doors

* 4

* attribution

* polymorphn't

* clean up objectives

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

* review

* add virtual items to blacklist

* allow them to roll sleeper agent

* Automatic changelog update

* Improvements to antag-before-job selection system (#35822)

* Fix the latejoin-antag-deficit bug, add datafield, add logging

* Fix multiple roles being made for single-role defs,

* HOTFIX: Fix paradox clone event (#35858)

fix paradox clone event

* Update CP14TownSendConditionSystem.cs

---------

Signed-off-by: Prole <172158352+Prole0@users.noreply.github.com>
Co-authored-by: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Co-authored-by: Smith <182301147+AgentSmithRadio@users.noreply.github.com>
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
Co-authored-by: Pancake <Pangogie@users.noreply.github.com>
Co-authored-by: Southbridge <7013162+southbridge-fur@users.noreply.github.com>
Co-authored-by: Schrödinger <132720404+Schrodinger71@users.noreply.github.com>
Co-authored-by: Velken <8467292+Velken@users.noreply.github.com>
Co-authored-by: Errant <35878406+Errant-4@users.noreply.github.com>
Co-authored-by: LaCumbiaDelCoronavirus <90893484+LaCumbiaDelCoronavirus@users.noreply.github.com>
Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: FungiFellow <151778459+FungiFellow@users.noreply.github.com>
Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
Co-authored-by: Coenx-flex <coengmurray@gmail.com>
Co-authored-by: hivehum <ketchupfaced@gmail.com>
Co-authored-by: Thomas <87614336+Aeshus@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: Myra <vasilis@pikachu.systems>
Co-authored-by: Emisse <99158783+Emisse@users.noreply.github.com>
Co-authored-by: HTML/Crystal <152909599+HTMLSystem@users.noreply.github.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: Hannah Giovanna Dawson <karakkaraz@gmail.com>
Co-authored-by: Coolsurf6 <coolsurf24@yahoo.com.au>
Co-authored-by: rokudara-sen <160833839+rokudara-sen@users.noreply.github.com>
Co-authored-by: DuckManZach <144298822+DuckManZach@users.noreply.github.com>
Co-authored-by: MisterImp <101299120+MisterImp@users.noreply.github.com>
Co-authored-by: Killerqu00 <47712032+Killerqu00@users.noreply.github.com>
Co-authored-by: Ps3Moira <113228053+ps3moira@users.noreply.github.com>
Co-authored-by: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com>
Co-authored-by: Boaz1111 <149967078+Boaz1111@users.noreply.github.com>
Co-authored-by: āda <ss.adasts@gmail.com>
Co-authored-by: War Pigeon <54217755+minus1over12@users.noreply.github.com>
Co-authored-by: Deerstop <edainturner@gmail.com>
Co-authored-by: Milon <milonpl.git@proton.me>
Co-authored-by: Łukasz Mędrek <lukasz@lukaszm.xyz>
Co-authored-by: DoutorWhite <thedoctorwhite@gmail.com>
Co-authored-by: compilatron <40789662+Compilatron144@users.noreply.github.com>
Co-authored-by: jbox1 <40789662+jbox144@users.noreply.github.com>
Co-authored-by: Momo <Rsnesrud@gmail.com>
Co-authored-by: MilenVolf <63782763+MilenVolf@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: TytosB <54259736+TytosB@users.noreply.github.com>
Co-authored-by: Prole <172158352+Prole0@users.noreply.github.com>
Co-authored-by: Evelyn Gordon <evelyn.gordon20@gmail.com>
Co-authored-by: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com>
Co-authored-by: RedBookcase <crazykid1590@gmail.com>
Co-authored-by: RedBookcase <Usualmoves@gmail.com>
Co-authored-by: SpaceManiac <tad@platymuus.com>
Co-authored-by: Spessmann <156740760+Spessmann@users.noreply.github.com>
Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
Co-authored-by: imcb <irismessage@protonmail.com>
Co-authored-by: valquaint <57813693+valquaint@users.noreply.github.com>
Co-authored-by: Flareguy <woaj9999@outlook.com>
Co-authored-by: ninruB <ninrub@tuta.io>
Co-authored-by: Velcroboy <107660393+IamVelcroboy@users.noreply.github.com>
Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
Co-authored-by: Łukasz Lindert <lukasz.lindert@protonmail.com>
Co-authored-by: Firewars763 <35506916+Firewars763@users.noreply.github.com>
Co-authored-by: onesch <118821520+onesch@users.noreply.github.com>
Co-authored-by: K-Dynamic <20566341+K-Dynamic@users.noreply.github.com>
Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com>
Co-authored-by: Crude Oil <124208219+CroilBird@users.noreply.github.com>
Co-authored-by: Lusatia <ultimate_doge@outlook.com>
2025-03-17 11:54:43 +03:00

594 lines
21 KiB
C#

using Content.Server.Atmos.Components;
using Content.Server.Fluids.EntitySystems;
using Content.Server.NPC.Queries;
using Content.Server.NPC.Queries.Considerations;
using Content.Server.NPC.Queries.Curves;
using Content.Server.NPC.Queries.Queries;
using Content.Server.Nutrition.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Server.Storage.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Fluids.Components;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.NPC.Systems;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Tools.Systems;
using Content.Shared.Turrets;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Whitelist;
using Microsoft.Extensions.ObjectPool;
using Robust.Server.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
namespace Content.Server.NPC.Systems;
/// <summary>
/// Handles utility queries for NPCs.
/// </summary>
public sealed class NPCUtilitySystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly DrinkSystem _drink = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly FoodSystem _food = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly OpenableSystem _openable = default!;
[Dependency] private readonly PuddleSystem _puddle = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutions = default!;
[Dependency] private readonly WeldableSystem _weldable = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly MobThresholdSystem _thresholdSystem = default!;
[Dependency] private readonly TurretTargetSettingsSystem _turretTargetSettings = default!;
private EntityQuery<PuddleComponent> _puddleQuery;
private EntityQuery<TransformComponent> _xformQuery;
private ObjectPool<HashSet<EntityUid>> _entPool =
new DefaultObjectPool<HashSet<EntityUid>>(new SetPolicy<EntityUid>(), 256);
// Temporary caches.
private List<EntityUid> _entityList = new();
private HashSet<Entity<IComponent>> _entitySet = new();
private List<EntityPrototype.ComponentRegistryEntry> _compTypes = new();
public override void Initialize()
{
base.Initialize();
_puddleQuery = GetEntityQuery<PuddleComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
}
/// <summary>
/// Runs the UtilityQueryPrototype and returns the best-matching entities.
/// </summary>
/// <param name="bestOnly">Should we only return the entity with the best score.</param>
public UtilityResult GetEntities(
NPCBlackboard blackboard,
string proto,
bool bestOnly = true)
{
// TODO: PickHostilesop or whatever needs to juse be UtilityQueryOperator
var weh = _proto.Index<UtilityQueryPrototype>(proto);
var ents = _entPool.Get();
foreach (var query in weh.Query)
{
switch (query)
{
case UtilityQueryFilter filter:
Filter(blackboard, ents, filter);
break;
default:
Add(blackboard, ents, query);
break;
}
}
if (ents.Count == 0)
{
_entPool.Return(ents);
return UtilityResult.Empty;
}
var results = new Dictionary<EntityUid, float>();
var highestScore = 0f;
foreach (var ent in ents)
{
if (results.Count > weh.Limit)
break;
var score = 1f;
foreach (var con in weh.Considerations)
{
var conScore = GetScore(blackboard, ent, con);
var curve = con.Curve;
var curveScore = GetScore(curve, conScore);
var adjusted = GetAdjustedScore(curveScore, weh.Considerations.Count);
score *= adjusted;
// If the score is too low OR we only care about best entity then early out.
// Due to the adjusted score only being able to decrease it can never exceed the highest from here.
if (score <= 0f || bestOnly && score <= highestScore)
{
break;
}
}
if (score <= 0f)
continue;
highestScore = MathF.Max(score, highestScore);
results.Add(ent, score);
}
var result = new UtilityResult(results);
blackboard.Remove<EntityUid>(NPCBlackboard.UtilityTarget);
_entPool.Return(ents);
return result;
}
private float GetScore(IUtilityCurve curve, float conScore)
{
switch (curve)
{
case BoolCurve:
return conScore > 0f ? 1f : 0f;
case InverseBoolCurve:
return conScore.Equals(0f) ? 1f : 0f;
case PresetCurve presetCurve:
return GetScore(_proto.Index<UtilityCurvePresetPrototype>(presetCurve.Preset).Curve, conScore);
case QuadraticCurve quadraticCurve:
return Math.Clamp(quadraticCurve.Slope * MathF.Pow(conScore - quadraticCurve.XOffset, quadraticCurve.Exponent) + quadraticCurve.YOffset, 0f, 1f);
default:
throw new NotImplementedException();
}
}
private float GetScore(NPCBlackboard blackboard, EntityUid targetUid, UtilityConsideration consideration)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
switch (consideration)
{
case FoodValueCon:
{
if (!TryComp<FoodComponent>(targetUid, out var food))
return 0f;
// mice can't eat unpeeled bananas, need monkey's help
if (_openable.IsClosed(targetUid))
return 0f;
if (!_food.IsDigestibleBy(owner, targetUid, food))
return 0f;
var avoidBadFood = !HasComp<IgnoreBadFoodComponent>(owner);
// only eat when hungry or if it will eat anything
if (TryComp<HungerComponent>(owner, out var hunger) && hunger.CurrentThreshold > HungerThreshold.Okay && avoidBadFood)
return 0f;
// no mouse don't eat the uranium-235
if (avoidBadFood && HasComp<BadFoodComponent>(targetUid))
return 0f;
return 1f;
}
case DrinkValueCon:
{
if (!TryComp<DrinkComponent>(targetUid, out var drink))
return 0f;
// can't drink closed drinks
if (_openable.IsClosed(targetUid))
return 0f;
// only drink when thirsty
if (TryComp<ThirstComponent>(owner, out var thirst) && thirst.CurrentThirstThreshold > ThirstThreshold.Okay)
return 0f;
// no janicow don't drink the blood puddle
if (HasComp<BadDrinkComponent>(targetUid))
return 0f;
// needs to have something that will satiate thirst, mice wont try to drink 100% pure mutagen.
var hydration = _drink.TotalHydration(targetUid, drink);
if (hydration <= 1.0f)
return 0f;
return 1f;
}
case OrderedTargetCon:
{
if (!blackboard.TryGetValue<EntityUid>(NPCBlackboard.CurrentOrderedTarget, out var orderedTarget, EntityManager))
return 0f;
if (targetUid != orderedTarget)
return 0f;
return 1f;
}
case TargetAccessibleCon:
{
if (_container.TryGetContainingContainer(targetUid, out var container))
{
if (TryComp<EntityStorageComponent>(container.Owner, out var storageComponent))
{
if (storageComponent is { Open: false } && _weldable.IsWelded(container.Owner))
{
return 0.0f;
}
}
else
{
// If we're in a container (e.g. held or whatever) then we probably can't get it. Only exception
// Is a locker / crate
// TODO: Some mobs can break it so consider that.
return 0.0f;
}
}
// TODO: Pathfind there, though probably do it in a separate con.
return 1f;
}
case TargetAmmoMatchesCon:
{
if (!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out Hand? activeHand, EntityManager) ||
!TryComp<BallisticAmmoProviderComponent>(activeHand.HeldEntity, out var heldGun))
{
return 0f;
}
if (_whitelistSystem.IsWhitelistFailOrNull(heldGun.Whitelist, targetUid))
{
return 0f;
}
return 1f;
}
case TargetDistanceCon:
{
var radius = blackboard.GetValueOrDefault<float>(blackboard.GetVisionRadiusKey(EntityManager), EntityManager);
if (!TryComp(targetUid, out TransformComponent? targetXform) ||
!TryComp(owner, out TransformComponent? xform))
{
return 0f;
}
if (!targetXform.Coordinates.TryDistance(EntityManager, _transform, xform.Coordinates,
out var distance))
{
return 0f;
}
return Math.Clamp(distance / radius, 0f, 1f);
}
case TargetAmmoCon:
{
if (!HasComp<GunComponent>(targetUid))
return 0f;
var ev = new GetAmmoCountEvent();
RaiseLocalEvent(targetUid, ref ev);
if (ev.Count == 0)
return 0f;
// Wat
if (ev.Capacity == 0)
return 1f;
return (float) ev.Count / ev.Capacity;
}
case TargetHealthCon con:
{
if (!TryComp(targetUid, out DamageableComponent? damage))
return 0f;
if (con.TargetState != MobState.Invalid && _thresholdSystem.TryGetPercentageForState(targetUid, con.TargetState, damage.TotalDamage, out var percentage))
return Math.Clamp((float)(1 - percentage), 0f, 1f);
if (_thresholdSystem.TryGetIncapPercentage(targetUid, damage.TotalDamage, out var incapPercentage))
return Math.Clamp((float)(1 - incapPercentage), 0f, 1f);
return 0f;
}
case TargetInLOSCon:
{
var radius = blackboard.GetValueOrDefault<float>(blackboard.GetVisionRadiusKey(EntityManager), EntityManager);
return _examine.InRangeUnOccluded(owner, targetUid, radius + 0.5f, null) ? 1f : 0f;
}
case TargetInLOSOrCurrentCon:
{
var radius = blackboard.GetValueOrDefault<float>(blackboard.GetVisionRadiusKey(EntityManager), EntityManager);
const float bufferRange = 0.5f;
if (blackboard.TryGetValue<EntityUid>("Target", out var currentTarget, EntityManager) &&
currentTarget == targetUid &&
TryComp(owner, out TransformComponent? xform) &&
TryComp(targetUid, out TransformComponent? targetXform) &&
xform.Coordinates.TryDistance(EntityManager, _transform, targetXform.Coordinates, out var distance) &&
distance <= radius + bufferRange)
{
return 1f;
}
return _examine.InRangeUnOccluded(owner, targetUid, radius + bufferRange, null) ? 1f : 0f;
}
case TargetIsAliveCon:
{
return _mobState.IsAlive(targetUid) ? 1f : 0f;
}
case TargetIsCritCon:
{
return _mobState.IsCritical(targetUid) ? 1f : 0f;
}
case TargetIsDeadCon:
{
return _mobState.IsDead(targetUid) ? 1f : 0f;
}
case TargetMeleeCon:
{
if (TryComp<MeleeWeaponComponent>(targetUid, out var melee))
{
return melee.Damage.GetTotal().Float() * melee.AttackRate / 100f;
}
return 0f;
}
case TargetOnFireCon:
{
if (TryComp(targetUid, out FlammableComponent? fire) && fire.OnFire)
return 1f;
return 0f;
}
case TurretTargetingCon:
{
if (!TryComp<TurretTargetSettingsComponent>(owner, out var turretTargetSettings) ||
_turretTargetSettings.EntityIsTargetForTurret((owner, turretTargetSettings), targetUid))
return 1f;
return 0f;
}
default:
throw new NotImplementedException();
}
}
private float GetAdjustedScore(float score, int considerations)
{
/*
* Now using the geometric mean
* for n scores you take the n-th root of the scores multiplied
* e.g. a, b, c scores you take Math.Pow(a * b * c, 1/3)
* To get the ACTUAL geometric mean at any one stage you'd need to divide by the running consideration count
* however, the downside to this is it will fluctuate up and down over time.
* For our purposes if we go below the minimum threshold we want to cut it off, thus we take a
* "running geometric mean" which can only ever go down (and by the final value will equal the actual geometric mean).
*/
var adjusted = MathF.Pow(score, 1 / (float) considerations);
return Math.Clamp(adjusted, 0f, 1f);
}
private void Add(NPCBlackboard blackboard, HashSet<EntityUid> entities, UtilityQuery query)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
var vision = blackboard.GetValueOrDefault<float>(blackboard.GetVisionRadiusKey(EntityManager), EntityManager);
switch (query)
{
case ComponentQuery compQuery:
{
if (compQuery.Components.Count == 0)
return;
var mapPos = _transform.GetMapCoordinates(owner, xform: _xformQuery.GetComponent(owner));
_compTypes.Clear();
var i = -1;
EntityPrototype.ComponentRegistryEntry compZero = default!;
foreach (var compType in compQuery.Components.Values)
{
i++;
if (i == 0)
{
compZero = compType;
continue;
}
_compTypes.Add(compType);
}
_entitySet.Clear();
_lookup.GetEntitiesInRange(compZero.Component.GetType(), mapPos, vision, _entitySet);
foreach (var comp in _entitySet)
{
var ent = comp.Owner;
if (ent == owner)
continue;
var othersFound = true;
foreach (var compOther in _compTypes)
{
if (!HasComp(ent, compOther.Component.GetType()))
{
othersFound = false;
break;
}
}
if (!othersFound)
continue;
entities.Add(ent);
}
break;
}
case InventoryQuery:
{
if (!_inventory.TryGetContainerSlotEnumerator(owner, out var enumerator))
break;
while (enumerator.MoveNext(out var slot))
{
foreach (var child in slot.ContainedEntities)
{
RecursiveAdd(child, entities);
}
}
break;
}
case NearbyHostilesQuery:
{
foreach (var ent in _npcFaction.GetNearbyHostiles(owner, vision))
{
entities.Add(ent);
}
break;
}
default:
throw new NotImplementedException();
}
}
private void RecursiveAdd(EntityUid uid, HashSet<EntityUid> entities)
{
// TODO: Probably need a recursive struct enumerator on engine.
var xform = _xformQuery.GetComponent(uid);
var enumerator = xform.ChildEnumerator;
entities.Add(uid);
while (enumerator.MoveNext(out var child))
{
RecursiveAdd(child, entities);
}
}
private void Filter(NPCBlackboard blackboard, HashSet<EntityUid> entities, UtilityQueryFilter filter)
{
switch (filter)
{
case ComponentFilter compFilter:
{
_entityList.Clear();
foreach (var ent in entities)
{
foreach (var comp in compFilter.Components)
{
if (HasComp(ent, comp.Value.Component.GetType()))
continue;
_entityList.Add(ent);
break;
}
}
foreach (var ent in _entityList)
{
entities.Remove(ent);
}
break;
}
case RemoveAnchoredFilter:
{
_entityList.Clear();
foreach (var ent in entities)
{
if (!TryComp(ent, out TransformComponent? xform))
continue;
if (xform.Anchored)
_entityList.Add(ent);
}
foreach (var ent in _entityList)
{
entities.Remove(ent);
}
break;
}
case PuddleFilter:
{
_entityList.Clear();
foreach (var ent in entities)
{
if (!_puddleQuery.TryGetComponent(ent, out var puddleComp) ||
!_solutions.TryGetSolution(ent, puddleComp.SolutionName, out _, out var sol) ||
_puddle.CanFullyEvaporate(sol))
{
_entityList.Add(ent);
}
}
foreach (var ent in _entityList)
{
entities.Remove(ent);
}
break;
}
default:
throw new NotImplementedException();
}
}
}
public readonly record struct UtilityResult(Dictionary<EntityUid, float> Entities)
{
public static readonly UtilityResult Empty = new(new Dictionary<EntityUid, float>());
public readonly Dictionary<EntityUid, float> Entities = Entities;
/// <summary>
/// Returns the entity with the highest score.
/// </summary>
public EntityUid GetHighest()
{
if (Entities.Count == 0)
return EntityUid.Invalid;
return Entities.MaxBy(x => x.Value).Key;
}
/// <summary>
/// Returns the entity with the lowest score. This does not consider entities with a 0 (invalid) score.
/// </summary>
public EntityUid GetLowest()
{
if (Entities.Count == 0)
return EntityUid.Invalid;
return Entities.MinBy(x => x.Value).Key;
}
}