Compare commits

...

146 Commits

Author SHA1 Message Date
Ed
a02cebd1de fail experiment 2024-08-06 23:40:27 +03:00
Ed
78e140b4ae Revert "SpawnSpell tweak (#393)" (#398)
This reverts commit dc853b6662.
2024-08-06 20:25:29 +03:00
Tornado Tech
1b0bf2ad18 Added base workbench window (#372)
* Added base workbench window

* Fixed serialization errors

* Created base UI layout

* Updated ui

* Updated UI after crafting
2024-08-06 14:25:59 +03:00
Ed
dc853b6662 SpawnSpell tweak (#393)
* some refactor

* Update flame_creation.yml
2024-08-06 00:42:53 +03:00
Ed
37e0ffa173 Workshop update (#392)
* kreks spell icons

* vladimirs walls update

* add flora material
2024-08-05 22:46:22 +03:00
Ed
6ab9ca6bd0 yupiiii (#391) 2024-08-05 21:08:10 +03:00
Nim
934c1e44a6 second rebalance (#390)
Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-08-05 21:00:40 +03:00
Nim
818eb30d2d spells (#389) 2024-08-05 20:59:40 +03:00
Tornado Tech
12d2af692f Update wave.swsl (#388) 2024-08-05 16:48:22 +03:00
Ed
1f4b7f68bf Playtest polishing (#383)
* fix predicting sharpening

* finish shadow step

* tweak ice dagger

* shadow grab test

* fireball spell

* ice shards spell

* battle royale crates

* loot tables

* remove expedition ship

* dev update

* br map update

* spells tweak

* tips update

* some fixes

* biome forest spawner

* give keys to orgs

* mobs and aura spawners

* expedition update: goal, new ship, new map

* fix doors layers

* add new map proto

* translate keys

* Update crates.yml

* Update PostMapInitTest.cs

* fix spawning on expedition ship

* Fuck you, Randy. Remove nails

* fix lock systems

* localize tips

* some tweaks

* update ship, remove shrooms.

* fixes

* Update StationSystem.cs

* Revert "Update StationSystem.cs"

This reverts commit f632241324.

* Update expedition_test.yml
2024-08-05 15:22:14 +03:00
Jaraten
9a07a9a052 stone upd (#384)
* stone upd

* fix ooopsiee

* fix tile
2024-08-04 12:28:31 +03:00
Skilets
1633895321 Fix Hud (#385)
Co-authored-by: SkiletsKir <113713080+Skilets@users.noreply.github.com>
2024-08-04 11:49:17 +03:00
Tornado Tech
0cd3a3c2d9 Added personal signature system (#382)
* Added personal signature system

* FUCKING RUSSIAN LANUAGE

A HATE LATTERS, HATEEEEEEEEEEEEEEEEEEEEEEE!

* Added locale and sound
2024-08-04 11:48:09 +03:00
GrandApothecary19
72cbed696f More sprites for tavern (#357)
* - add sprites

* - fixo for .ftl

* - fix because no whiskey in Eberron((

* - fixo
2024-08-03 15:51:29 +03:00
Gagarinten-Noverdo
c620d66dab Biome spawner fix. Again (#381)
* Biome spawner update. Round seed system

* Format fix

* Round seed M I T

* Error to Warning

* Test fix #2

* Test fix #3

* VV

* Del out of body

* Fix of flood
2024-08-02 18:46:00 +03:00
Ed
599c599a4e Some shit (#380)
* telegraphy effects

* shadow step spell backend

* add component spell

* predict sharpening

* Update ring.yml

* locale sync

* Update entities.ftl

* icon shadow step
2024-08-02 13:51:54 +03:00
Ed
31c9485e3b Magic rings (#378)
* flame creation spell backend

* flame creation visuals

* flame creation spell visual

* tweak

* some tweaks

* ice dagger spell

* move spells to rings

* Update ring.yml

* fix server crash
2024-08-02 00:48:36 +03:00
Ed
56da23925f Magic Items (#370)
* attuning to items start

* verbs attuning, forgot oldest attuning

* Update CP14SharedMagicAttuningSystem.cs

* some fixes

* add deattuning

* fix popups on owner

* file restructurization

* MORE FOLDER RENAMING GODD

* magic via holding yea!

* fix deattuning

* vfx bugfixs

* wearing magic items

* Cure wounds spell

* refactor spells

* more redo

* finish refactor
2024-08-01 11:52:27 +03:00
Nim
19365c0314 Statue of Gob (#376)
* statue of Gob

* fix
2024-08-01 09:15:44 +03:00
Ed
82d89a97f1 Create FUNDING.yml 2024-07-31 13:28:03 +03:00
Tornado Tech
2bb43245c8 Renamed .sln file (#371) 2024-07-31 11:17:02 +03:00
Nim
909fa27450 Rebalance melee weapons (#363)
* weapons rebalance

* Update shield.yml

* Update shield.yml

---------

Co-authored-by: Ed <edwardxperia2000@gmail.com>
Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-07-30 22:43:09 +03:00
KommissarRed
7478e6b445 Remove "bruh" (#367) 2024-07-30 20:43:13 +03:00
Jaraten
5072800d4a wood furniture resprite (#360)
* wood table + workbench

* cupboard + dresser

* wooden bucket

* wooden crates

* Update Resources/Prototypes/_CP14/Entities/Structures/Storage/Crates/crates.yml

* barrel

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-07-30 17:07:43 +03:00
Ed
1f587c10b8 Update LICENSE.TXT 2024-07-30 11:48:50 +03:00
Ed
22bb0ae283 Energy pilons WIP (#326)
* split partial magic system

* add debug sprited pilons

* some energy pilons interactions

* Update CP14MagicEnergySystem.Relay.cs

* spupers (#322)

* spupers

* meta

* aura nodes + aura scanners

* scanner sprites

* maid dress

* reverse pilon logic

* relay delete, code clean up

* delete content

* Update basic.yml

* Update shirt.yml

* Update crystal.yml

---------

Co-authored-by: Jaraten <116667537+Jaraten@users.noreply.github.com>
2024-07-29 21:01:36 +03:00
Gagarinten-Noverdo
c69cb0320e Biome spawner update. Round seed system (#359)
* Biome spawner update. Round seed system

* Format fix

* Round seed M I T

* Error to Warning

* Test fix #2

* Test fix #3

* VV

* Del out of body
2024-07-29 19:16:55 +03:00
Ed
02c5e03ae7 Merge pull request #362 from crystallpunk-14/ed-28-07-2024-upstream
Upstream sync
2024-07-28 22:22:55 +03:00
Ed
cc5f27c057 ignore traits 2024-07-28 21:04:45 +03:00
Ed
fb40f8cd25 Merge remote-tracking branch 'upstream/master' into ed-28-07-2024-upstream
# Conflicts:
#	Resources/Prototypes/Maps/core.yml
#	Resources/Prototypes/Maps/train.yml
#	Resources/Prototypes/Traits/categories.yml
#	Resources/Prototypes/Traits/disabilities.yml
2024-07-28 20:58:48 +03:00
Ed
0d345c33b9 Update dev_map.yml (#361)
* Update dev_map.yml

* Disable FTL test

* DisableEvacTest
2024-07-28 20:56:05 +03:00
Ed
9011aab26b Add 3 roles (without gameplay, alas) (#356)
* add role icons

* add roles prototype

* Update job.yml
2024-07-28 18:22:50 +03:00
Jaraten
cf6b42d20c Stone-brick wall crushed (#336) 2024-07-28 17:27:24 +03:00
Ed
655b32b720 Magic spells backend (#358)
* add EntityEffect aability support

* delayed actions

* renaming

* delayed projectile spells

* spawn on self + entityEffect on self spells

* spawn on point spell

* rename

* clean up base species components

* magic alert

* move magic energy to Shared, add manacost to spells

* magic recoil

* improve magic recoil

* verbal aspect

* somatic aspect

* add simple vfx proto and sprites

* add casting VFX

* add TODO
2024-07-28 17:26:47 +03:00
PJBot
fce5269fc0 Automatic changelog update 2024-07-28 08:33:32 +00:00
Jona-K
2951ea2bee Adjustet MobBaseAncestor class (#30424) 2024-07-28 01:32:26 -07:00
Plykiya
79fa810b9c Update stomach removal and lung removal smite to not use Component.Owner (#29927)
* Update stomach removal and lung removal smite

* New function makes things simple

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-28 01:25:40 -07:00
PJBot
ab84eee083 Automatic changelog update 2024-07-28 06:18:12 +00:00
Plykiya
1d55a439ff Make NoSlip component networked (#30425)
Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-27 23:17:06 -07:00
Brandon Hu
4a9bd17a86 tweak(geras): Add a confirmation popup for gera transformation (#29215)
* tweak(geras): Add a confirmation popup for gera transformation

* remove abstract parent
2024-07-28 14:13:15 +10:00
PJBot
d9286dd6d9 Automatic changelog update 2024-07-28 03:50:12 +00:00
lzk
e1e2d26969 Fix pancakes stacks (#30270)
Fix pancakes
2024-07-28 13:49:06 +10:00
deathride58
3a10ffa030 Makes the labeller automatically label PRs with shader changes (#30316)
adds shader label to git labeller
2024-07-28 13:46:22 +10:00
metalgearsloth
404743f073 Fix examine threading issues (#30160) 2024-07-28 13:43:59 +10:00
IProduceWidgets
925d1e3ac8 Prevent gridfill from leaking (#30395)
dont forget to set the airtights when the tights are aired
2024-07-28 13:20:29 +10:00
Plykiya
7f9e06501f Update SharedDoorSystem.cs to not use Component.Owner (#29963)
* Update SharedDoorSystem.cs

* comment

* empty space

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-28 13:18:12 +10:00
PJBot
255b7f3b7a Automatic changelog update 2024-07-28 03:15:24 +00:00
metalgearsloth
093054f7e3 Move vgroid much closer (#29943)
* Move vgroid much closer

General feedback is map spam + it takes too long to get to. This is somewhat "close" (considering 1/4 of the distance is the vgroid itself) but without a jetpack / shuttle it's going to be an endeavour.

* Decrease max

* Tweaks

* godzilla

* Update Content.Server/Shuttles/Components/GridSpawnComponent.cs
2024-07-28 13:14:18 +10:00
github-actions[bot]
e3d7c1bd6e Update Credits (#30420)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
2024-07-27 21:36:00 -04:00
PJBot
845fa31419 Automatic changelog update 2024-07-27 23:12:34 +00:00
Spessmann
34a7aa70ce Thief objectives for figurines and stamps ask for less items (#30390)
Makes thief objective for stealing figures and stamps easier
2024-07-28 02:11:26 +03:00
Brandon Hu
3283424ba8 tweak(Radiation Suits): Increase damage taken by 1000% (#30392)
wtf is 0.9% anyways
2024-07-28 02:10:07 +03:00
Brandon Hu
54e42cc4e5 tweak(NuclearBomb Keg): Give the nuclear bomb keg a hit box (#30415)
* bleh

* Bugs spread disease :(

* they are reproducing

* no lore
2024-07-27 21:45:53 +01:00
Flareguy
9bd623a927 Makes security a bit brighter (#30369)
makes sec more red
2024-07-27 13:51:10 -06:00
Brandon Hu
d846a621e5 tweak(Core_map_Jobslots): Increase round start chemist slots from 1 to 2 (#30408)
that is odd
2024-07-27 13:49:05 -06:00
Brandon Hu
dc1be42b8f tweak(Chemical Dispenser): Give the chemical dispenser a hitbox (#30412)
weh
2024-07-27 21:47:38 +03:00
PJBot
6a1efebb6a Automatic changelog update 2024-07-27 15:09:56 +00:00
BombasterDS
de7df2a760 Some plant mutations (#28993)
* Some new plants mutations

* glasstle inhand

* gapple trico increase ↑

1-10 to 3-16

* replace trico with doc delight
2024-07-27 18:08:49 +03:00
Errant
f49fc5a89c Do not duplicate Job Greeting on antag selection (#30407)
Silence MindAddRoles in AntagSelectionSystem
2024-07-27 07:58:19 -07:00
deltanedas
f67f7034b9 fix ninja not showing in round end (#30405)
fix ninja not showing in round ned

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-07-27 05:08:12 -07:00
Chief-Engineer
b66c286ecb Include whitelisting location in baby jail deny message (#30373)
include whitelist locating in baby jail deny message
2024-07-27 04:49:02 -05:00
PJBot
9f6e5e8d60 Automatic changelog update 2024-07-27 07:28:28 +00:00
Plykiya
1146f2fefe Fix thieves rule not selecting more than one thief (#30393)
More thieves

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-27 00:27:21 -07:00
IProduceWidgets
b9090e84f7 Update Evac-Accordia (#30389)
Update accordia atmos systems
2024-07-26 23:40:39 -06:00
IProduceWidgets
45a481de47 Oasis updoot (#30388)
updoot!
2024-07-26 23:39:43 -06:00
PJBot
5485ae25e0 Automatic changelog update 2024-07-27 04:10:29 +00:00
Golden Can
1149290825 Security Clown Mask (#30249)
Added Security Clown Mask available from hacked SecDrobes.
2024-07-27 00:09:23 -04:00
PJBot
d5d8c14ced Automatic changelog update 2024-07-27 01:55:44 +00:00
metalgearsloth
8f250581be Fix VGRoid grid spam (#29946)
Specifically if a grid splits under the cvar size it doesn't get a label. This also stops stuff like shuttles splitting in half creating new entries for the new grids. Splitting code leaves the largest grid as the existing one so this will always prefer to keep it large (but if there's multiple splits it won't adjust).
2024-07-27 11:54:38 +10:00
PJBot
e7aa7791b4 Automatic changelog update 2024-07-26 18:49:09 +00:00
themias
7c7f4a9f25 Fix zombie uncuffing (#30321)
* Fix zombie uncuffing

* PlaceNextTo() and rename vars
2024-07-26 14:48:03 -04:00
chavonadelal
582e6d2010 Localization of the title of the job (#30353) 2024-07-26 14:47:07 -04:00
Brandon Hu
b1d5436bcd fix(ExtinguisherCabinet): Fix cabinet whitelist to allow fire extinguishers again (#30371)
ugh

Co-authored-by: Avery Dobbins <avery.dobbins@gmail.com>
2024-07-26 14:46:40 -04:00
PJBot
18506e1f3b Automatic changelog update 2024-07-26 17:31:57 +00:00
themias
e72393df71 Fix arcade machines (#30376) 2024-07-26 10:30:49 -07:00
Errant
eab5030c39 Add vox naming convention to Rules (#30284)
vox naming conventions
2024-07-26 10:19:12 -05:00
PJBot
811da0e3d6 Automatic changelog update 2024-07-26 13:00:50 +00:00
Errant
a7fa66e956 Replayspawn logic fix (yes, again) (#30273)
* Fix replayghost spawn

* missed a spot
2024-07-26 13:59:42 +01:00
PJBot
f083d080f5 Automatic changelog update 2024-07-26 06:48:26 +00:00
Moomoobeef
5905767ce7 changed some radio colors to be more distinguishable (#30133)
* changed some radio colors to be more distinguishable

* changed sec, supply, and engineering in order to provide more accessability to deuteranomaly

* the previous commit made engi and supply hard to distinguish again. so I fixed it
2024-07-25 23:47:20 -07:00
Brandon Hu
a99ae6211d fix(cmd-Jobwhitelistadd): Fixed typo in Loc.GetString (#30355)
LET ME IN THE BAR LET ME IN THE BAR LET ME IN THE BAR. IM 18 I SWEAR PLEASE PPLEASE NOOOO I SWEAR PLEASE PLEASE I WANNA GET CRUNK
2024-07-25 23:55:44 -06:00
PJBot
76096b21f1 Automatic changelog update 2024-07-26 05:27:11 +00:00
Cojoke
333bb386d9 Add Identity Blocker to a Couple Things (#30305) 2024-07-25 23:26:04 -06:00
Brandon Hu
4e1fe975ec tweak(StatusIcons): Hide revolutionary icons in the dark. (#30367)
Wilma? eye harley no er
2024-07-25 23:25:33 -06:00
Brandon Hu
44199991bf twek(BoxStation): Reorganize atmos TEG room to be more user friendly. (#30368)
ugh
2024-07-25 23:06:31 -06:00
PJBot
af47cbd7b0 Automatic changelog update 2024-07-25 23:39:00 +00:00
Ilya246
d5236d8236 give nukie reinforcements full operative gear (#30173)
* rebase master

* free fish

* introduce recommended changes

* fix prototypes

* fix protos yet again

* fkhsdjbhehbo;ehb

* rafle
2024-07-25 16:37:54 -07:00
PJBot
ff581d4275 Automatic changelog update 2024-07-25 23:27:14 +00:00
Plykiya
0a07203121 Lets atmos build gas pipes in walls (#28707)
Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-25 16:26:06 -07:00
lzk
818f43b005 Update Meta (#30348)
fans
hardsuits
2024-07-25 15:58:39 -06:00
lzk
d1663cade4 Update Omega (#30356)
* Update Omega

fans
external airlocks
tree escape pods

* remove invalid
2024-07-25 13:48:06 -06:00
lzk
769967ac36 Update Packed (#30358)
fans
external airlocks
2024-07-25 13:15:50 -06:00
lzk
6f7719011a Update Saltern (#30357)
fans
2024-07-25 13:15:28 -06:00
lzk
e161a021c4 fix the bigest news admin notification typo in the game (#30349)
Fix typo
2024-07-25 15:02:15 +01:00
Plykiya
2a7883b92e Update vomit organ smite to not use Component.owner (#29926)
* Update vomit organ smite to not use Component.owner

* is this what you want...?

* am I winning, dad?

* update the comment

* we love entity<t>

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-25 05:24:40 -07:00
Plykiya
7388b91ef5 Replace noSpawn: true with categories: [ HideSpawnMenu ] (#30100)
* NOW THAT'S A LOT OF FILES

* categorization

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-25 05:24:00 -07:00
Ed
6f2e1d6d9f Update CP14StationAdditionalMapComponent.cs 2024-07-25 15:07:12 +03:00
PJBot
e95aaef839 Automatic changelog update 2024-07-25 10:53:26 +00:00
timur2011
bcd7a7ad00 Space adder now butcherable, snake drops snake meat (#29629) 2024-07-25 03:52:18 -07:00
lzk
f56e4f6624 Replace some to do with TODO (#30346)
Replace to do with TODO
2024-07-25 11:04:03 +03:00
Ed
99854edc93 MIT BiomeSpawner 2024-07-25 10:59:36 +03:00
Brandon Hu
50ba20c766 fix(bounties): Make winter counts count as a single warm item. (#30306)
https://news.stanford.edu/stories/2020/05/veil-darkness-reduces-racial-bias-traffic-stops
2024-07-24 23:33:22 -06:00
deltanedas
8de6b74e08 fix borg light being on by default (#30342)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-07-24 23:30:17 -06:00
Brandon Hu
2d124c5c29 fix(train): Anchor botany machine, add second artifact spawner. (#30309)
https://www.peoplesworld.org/article/free-college-was-once-the-norm-all-over-america/
2024-07-24 23:29:50 -06:00
PJBot
61efd1201e Automatic changelog update 2024-07-25 05:24:58 +00:00
themias
b0cc97fb04 Fix Ripley control panel (#30325) 2024-07-24 23:23:52 -06:00
PJBot
0d12ce54d4 Automatic changelog update 2024-07-25 03:55:58 +00:00
deltanedas
8f6326c3e0 prevent borgs unlocking eachother and robotics console (#27888)
* prevent borgs from using locks

* e

* bru

* a

* blacklist borgs and robotics console

* frogro

* add IsAllowed to EntityWhitelistSystem

* use IsAllowed

* move thing to new LockingWhitelistSystem

* :trollface:

* review

* use renamed CheckBoth in locking whitelist

* remove unused stuff and add more to doc

* Use target entity instead to remove self check

* Rename to _whitelistSystem

* Add deny lock toggle popup

* Prevent duplicate checks and popups

* Fix wrong entity in popup when toggling another borg

* Make new event

* Update comment to user for new event

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
2024-07-25 13:54:51 +10:00
marbow
b6811d3570 Medical borg add chem glasses (#27843)
* Update borg_chassis.yml

* Update borg_chassis.yml

* fix

* Removing unnecessary components and adapting changes (#28391) for the syndicate

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
2024-07-25 13:49:32 +10:00
IProduceWidgets
06d136698c Perma escape crate fills and spawner (#29497)
* perma escape crate fills and spawner

* also include maints closets because thats easy.

* oopsie daisys

* green glowsticks

* mindshield

* base folder

* mob traps.

* I skill issued a ctrl+F and wrote garabge into yml

* re work syndicate gift crate, remove ability to get syndicate guns randomly.

* Do mob traps differently to hopefully appease tests.

* mindshield probability decrease.

* lower mob chance since I forgor there are crabs in the walls

* Suffixes

* mob chance was definitely too low.

* still too low

* still a bit low

* that feels right.

* too many mk's

* increase hatchet chance since you need a cutting impliment to logs.

* alphabetize
2024-07-24 20:31:54 -06:00
Ed
50e042011d direct 2024-07-25 00:09:58 +03:00
PJBot
54e760088a Automatic changelog update 2024-07-24 20:58:54 +00:00
Cojoke
620aed5939 Fix QSI Link Range (#30332) 2024-07-24 13:57:45 -07:00
lzk
f210325460 Update Atlas (#30331)
* Update Atlas

connect missed atmos devices (part of #29025)
replace fans in fridge

* remove invalid
2024-07-24 14:52:34 -06:00
lzk
9def96d762 Update Box (#30329)
* Update Box

replace missed tiny fans with directional

* add two more security hardsuits
2024-07-24 14:17:29 -06:00
lzk
687e2c5844 Update Fland (#30330)
replace tiny fans with directional
connect missed external airlocks
2024-07-24 14:12:55 -06:00
lzk
bd4020bdfc Update Cluster (#30327)
replace tiny fans in fridge
2024-07-24 14:12:28 -06:00
lzk
ee641c2dff Update Marathon (#30328)
fans
external airlocks
one escape pod
more airlocks in arrivals
2024-07-24 14:12:21 -06:00
lzk
4536a527df Update Bagel (#30326)
replace tiny fans
fix #29482
2024-07-24 14:11:42 -06:00
Brandon Hu
492fb529df fix(Meta): Resolve every issue. (#30308)
* https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4369587/

* https://www.epa.gov/indoor-air-quality-iaq/what-epas-position-childrens-exposure-secondhand-smokeaerosol
2024-07-24 14:01:24 -06:00
osjarw
aa886ca494 Make NeedHand modifiable for injectorSystem (#29870)
* Get needhand from yml

* MovementThreshold modifiable + inheritdoc
2024-07-24 12:26:52 -07:00
Ed
08f1aa9fa1 Crew goals update (#355)
* randomization goals support

* maps update
2024-07-24 20:52:05 +03:00
Nim
bb20f3a1bc fix Mannequin (#354) 2024-07-24 19:14:18 +03:00
Brandon Hu
c4dcc90972 tweak(GunRequiresWield): State the requirement for gun wielding in the description. (#30301)
* https://en.wikipedia.org/wiki/List_of_LASD_deputy_gangs

* https://knock-la.com/tradition-of-violence-lasd-gang-history/

* https://coc.lacounty.gov/deputy-gangs/
2024-07-24 08:33:14 -04:00
Killerqu00
688a46f903 Move some disabilities traits into a new category (#30102)
split traits into disabilities and quirks
2024-07-24 06:50:19 -04:00
Ed
9c84ce9be0 Currency collect goal (#352)
* simple currency comp

* stack support + weapon cost dnd port

* add collect currency objective conditions

* clean up
2024-07-24 13:28:27 +03:00
Brandon Hu
343496faf8 tweak(chameleon): Add clown suit to chameleon tech (#29307) 2024-07-24 02:04:20 -07:00
PJBot
fc0954085f Automatic changelog update 2024-07-24 08:58:11 +00:00
BombasterDS
8b27ef8a78 Fix: Shelfs and Mannequin disassemble (#30313)
fix shelfs
2024-07-24 01:57:03 -07:00
Ed
bf93349b73 Female bodies support (#350)
* port female parts

* boobs support!

* tiefling boobs confirmed

* Update female_shirt.png

* Update female_shirt.png
2024-07-24 09:11:31 +03:00
mkanke-real
e1f3bdc748 Add spicy rock pizza (#30116)
* Added all the parts to implement spicy rock pizza

* Added sprites for pizza

* Fixed coma formatting in meta.json for pizzas

* Fix formatting and rebalance reagent quantities in pizza.yml

* Flipped Uranium and Radium values to be the correct ratio

* Updated meta.json file to have credit for sprite
2024-07-23 16:22:11 -07:00
PJBot
4f8b634f38 Automatic changelog update 2024-07-23 21:03:13 +00:00
Benjamin Velliquette
a32f9ff711 Fix Reagent Grinder being able to do work without being powered (#30267)
* Check if grinder is powered before doing work

* Use existing extention method.
2024-07-23 14:02:07 -07:00
Ed
c5a6f75def Merge pull request #348 from crystallpunk-14/ed-23-07-2024-upstream
Ed 23 07 2024 upstream
2024-07-23 22:01:51 +03:00
Ed
8c477a67c1 Update centcomm.yml 2024-07-23 21:50:00 +03:00
Ed
3b5e0003c3 Create centcomm.yml 2024-07-23 21:45:41 +03:00
Ed
ea753e5227 Update PostMapInitTest.cs 2024-07-23 21:17:41 +03:00
PJBot
ec071ceca7 Automatic changelog update 2024-07-23 17:48:15 +00:00
Scribbles0
7381df4335 Handless mobs can no longer wipe devices (#30149)
add check for hands
2024-07-23 10:47:07 -07:00
Ko4ergaPunk
e7aa97645b Change drawdepth of some wall-mounted objects (#30274)
drawdepth
2024-07-23 17:41:15 +03:00
Ed
3187006641 disable NukeOps test 2024-07-23 14:19:28 +03:00
Ed
526238bac5 fix 2024-07-23 14:04:13 +03:00
Ed
f348213750 Update arenas.yml 2024-07-23 13:46:57 +03:00
Ed
ed3e896cb8 Update debug.yml 2024-07-23 13:40:19 +03:00
Ed
0190e366a3 maps fix 2024-07-23 13:27:58 +03:00
Ed
9826b9ff38 Update goblin.yml 2024-07-23 13:16:49 +03:00
847 changed files with 177236 additions and 13129 deletions

14
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
custom: ['https://boosty.to/theshued']

4
.github/labeler.yml vendored
View File

@@ -12,6 +12,10 @@
- changed-files:
- any-glob-to-any-file: '**/*.xaml*'
"Changes: Shaders":
- changed-files:
- any-glob-to-any-file: '**/*.swsl'
"No C#":
- changed-files:
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.

View File

@@ -380,7 +380,7 @@ namespace Content.Client.Arcade
{
PanelOverride = back,
HorizontalExpand = true,
SizeFlagsStretchRatio = 60
SizeFlagsStretchRatio = 34.25f
};
var backgroundPanel = new PanelContainer
{

View File

@@ -17,6 +17,7 @@ public sealed class BlockGameBoundUserInterface : BoundUserInterface
base.Open();
_menu = this.CreateWindow<BlockGameMenu>();
_menu.OnAction += SendAction;
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)

View File

@@ -25,6 +25,7 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface
base.Open();
_menu = this.CreateWindow<SpaceVillainArcadeMenu>();
_menu.OnPlayerAction += SendAction;
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)

View File

@@ -85,8 +85,19 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
if (protoId == null)
return;
//if (sexMorph)
// protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
//CP14 female bodies support
if (sexMorph)
protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
{
var tempProto = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
if (_prototypeManager.TryIndex<HumanoidSpeciesSpriteLayer>(tempProto, out _))
{
protoId = tempProto;
}
}
//CP14 female bodies support end
var proto = _prototypeManager.Index<HumanoidSpeciesSpriteLayer>(protoId);
component.BaseLayers[key] = proto;

View File

@@ -12,7 +12,7 @@ public sealed partial class MechMenu : FancyWindow
{
[Dependency] private readonly IEntityManager _ent = default!;
private readonly EntityUid _mech;
private EntityUid _mech;
public event Action<EntityUid>? OnRemoveButtonPressed;
@@ -25,6 +25,7 @@ public sealed partial class MechMenu : FancyWindow
public void SetEntity(EntityUid uid)
{
MechView.SetEntity(uid);
_mech = uid;
}
public void UpdateMechStats()

View File

@@ -170,11 +170,12 @@ public sealed partial class ReplaySpectatorSystem
{
var size = grid.LocalAABB.Size.LengthSquared();
if (maxSize is not null && size < maxSize)
continue;
var station = HasComp<StationMemberComponent>(uid);
//We want the first station grid to overwrite any previous non-station grids no matter the size, in case the vgroid was found first
if (maxSize is not null && size < maxSize && !(!stationFound && station))
continue;
if (!station && stationFound)
continue;
@@ -183,7 +184,6 @@ public sealed partial class ReplaySpectatorSystem
if (station)
stationFound = true;
}
coords = new EntityCoordinates(maxUid ?? default, default);

View File

@@ -142,8 +142,8 @@ public sealed class CharacterUIController : UIController, IOnStateEntered<Gamepl
conditionControl.ProgressTexture.Progress = condition.Progress;
var titleMessage = new FormattedMessage();
var descriptionMessage = new FormattedMessage();
titleMessage.AddText(condition.Title);
descriptionMessage.AddText(condition.Description);
titleMessage.TryAddMarkup(condition.Title, out _); //CP14 colored objective text support
descriptionMessage.TryAddMarkup(condition.Description, out _); //CP14 colored objective text support
conditionControl.Title.SetMessage(titleMessage);
conditionControl.Description.SetMessage(descriptionMessage);

View File

@@ -0,0 +1,34 @@
using Content.Shared._CP14.Workbench;
using Robust.Client.UserInterface;
namespace Content.Client._CP14.Workbench;
public sealed class CP14WorkbenchBoundUserInterface : BoundUserInterface
{
private CP14WorkbenchWindow? _window;
public CP14WorkbenchBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<CP14WorkbenchWindow>();
_window.OnCraft += entry => SendMessage(new CP14WorkbenchUiCraftMessage(entry.ProtoId));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
switch (state)
{
case CP14WorkbenchUiRecipesState recipesState:
_window?.UpdateRecipes(recipesState);
break;
}
}
}

View File

@@ -0,0 +1,10 @@
<Control xmlns="https://spacestation14.io">
<GridContainer Columns="2">
<TextureRect Name="View"
Margin="0,0,4,0"
MinSize="48 48"
HorizontalAlignment="Left"
Stretch="KeepAspectCentered"/>
<Label Name="Name"/>
</GridContainer>
</Control>

View File

@@ -0,0 +1,45 @@
using Content.Shared._CP14.Workbench;
using Content.Shared._CP14.Workbench.Prototypes;
using Content.Shared.Stacks;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Workbench;
[GenerateTypedNameReferences]
public sealed partial class CP14WorkbenchRecipeControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
private readonly SpriteSystem _sprite;
public CP14WorkbenchRecipeControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
}
public CP14WorkbenchRecipeControl(EntityPrototype prototype, int count) : this()
{
var entityName = Loc.GetString(prototype.Name);
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
View.Texture = _sprite.GetPrototypeIcon(prototype).Default;
}
public CP14WorkbenchRecipeControl(StackPrototype prototype, int count) : this()
{
var entityName = Loc.GetString(prototype.Name);
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
var icon = prototype.Icon;
if (icon is null)
return;
View.Texture = _sprite.Frame0(icon);
}
}

View File

@@ -0,0 +1,12 @@
<Control xmlns="https://spacestation14.io">
<Button Name="Button">
<GridContainer Columns="2">
<TextureRect Name="View"
Margin="0,0,4,0"
MinSize="48 48"
HorizontalAlignment="Left"
Stretch="KeepAspectCentered"/>
<Label Name="Name"/>
</GridContainer>
</Button>
</Control>

View File

@@ -0,0 +1,59 @@
using Content.Shared._CP14.Workbench;
using Content.Shared._CP14.Workbench.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Workbench;
[GenerateTypedNameReferences]
public sealed partial class CP14WorkbenchRequirementControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public event Action<CP14WorkbenchUiRecipesEntry, CP14WorkbenchRecipePrototype>? OnSelect;
private readonly SpriteSystem _sprite;
private readonly CP14WorkbenchRecipePrototype _recipePrototype;
private readonly bool _craftable;
public CP14WorkbenchRequirementControl(CP14WorkbenchUiRecipesEntry entry)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
_recipePrototype = _prototype.Index(entry.ProtoId);
_craftable = entry.Craftable;
Button.OnPressed += _ => OnSelect?.Invoke(entry, _recipePrototype);
UpdateColor();
UpdateName();
UpdateView();
}
private void UpdateColor()
{
if (_craftable)
return;
Button.ModulateSelfOverride = Color.FromHex("#302622");
}
private void UpdateName()
{
var result = _prototype.Index(_recipePrototype.Result);
Name.Text = Loc.GetString(result.Name);
}
private void UpdateView()
{
View.Texture = _sprite.GetPrototypeIcon(_recipePrototype.Result).Default;
}
}

View File

@@ -0,0 +1,60 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="Workbench"
MinSize="700 600">
<BoxContainer Orientation="Vertical">
<!-- Main -->
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
<GridContainer HorizontalExpand="True" VerticalExpand="True" Columns="2">
<!-- Crafts container -->
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="CraftsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
<!-- Craft view -->
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
<PanelContainer HorizontalExpand="True" VerticalExpand="True">
<!-- Background -->
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#41332f"/>
</PanelContainer.PanelOverride>
<!-- Content -->
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
<!-- Item info -->
<GridContainer HorizontalExpand="True" Columns="2">
<!-- Left panel - icon -->
<TextureRect Name="ItemView"
Margin="0,0,4,0"
MinSize="64 64"
HorizontalAlignment="Left"
Stretch="KeepAspectCentered"/>
<!-- Right panel - name & description -->
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
<Label Name="ItemName" Text="Name"/>
<Label Name="ItemDescription" Text="Description" ClipText="True"/>
</BoxContainer>
</GridContainer>
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
<!-- Required title -->
<Label Text="Required"/>
<!-- Craft requirements content -->
<!-- Added by code -->
<BoxContainer Name="ItemRequirements" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True"/>
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
<!-- Craft button -->
<Button Name="CraftButton" Text="Craft"/>
</BoxContainer>
</PanelContainer>
</BoxContainer>
</GridContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,92 @@
using Content.Shared._CP14.Workbench;
using Content.Shared._CP14.Workbench.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Workbench;
[GenerateTypedNameReferences]
public sealed partial class CP14WorkbenchWindow : DefaultWindow
{
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public event Action<CP14WorkbenchUiRecipesEntry>? OnCraft;
private readonly SpriteSystem _sprite;
private CP14WorkbenchUiRecipesEntry? _selectedEntry ;
public CP14WorkbenchWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
CraftButton.OnPressed += _ =>
{
if (_selectedEntry is null)
return;
OnCraft?.Invoke(_selectedEntry.Value);
};
}
public void UpdateRecipes(CP14WorkbenchUiRecipesState recipesState)
{
CraftsContainer.RemoveAllChildren();
foreach (var entry in recipesState.Recipes)
{
var control = new CP14WorkbenchRequirementControl(entry);
control.OnSelect += RecipeSelect;
CraftsContainer.AddChild(control);
}
if (_selectedEntry is not null && recipesState.Recipes.Contains(_selectedEntry.Value))
{
RecipeSelect(_selectedEntry.Value, _prototype.Index(_selectedEntry.Value.ProtoId));
return;
}
RecipeSelect(recipesState);
}
private void RecipeSelect(CP14WorkbenchUiRecipesState recipesState)
{
foreach (var entry in recipesState.Recipes)
{
RecipeSelect(entry, _prototype.Index(entry.ProtoId));
break;
}
}
private void RecipeSelect(CP14WorkbenchUiRecipesEntry entry, CP14WorkbenchRecipePrototype recipe)
{
_selectedEntry = entry;
var result = _prototype.Index(recipe.Result);
ItemView.Texture = _sprite.GetPrototypeIcon(recipe.Result).Default;
ItemName.Text = Loc.GetString(result.Name);
ItemDescription.Text = Loc.GetString(result.Description);
ItemRequirements.RemoveAllChildren();
foreach (var (entProtoId, count) in recipe.Entities)
{
ItemRequirements.AddChild(new CP14WorkbenchRecipeControl(_prototype.Index(entProtoId), count));
}
foreach (var (entProtoId, count) in recipe.Stacks)
{
ItemRequirements.AddChild(new CP14WorkbenchRecipeControl(_prototype.Index(entProtoId), count));
}
CraftButton.Disabled = !entry.Craftable;
}
}

View File

@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using Content.Server.GameTicking;
using Content.Server.GameTicking.Presets;
using Content.Shared.CCVar;
@@ -36,7 +36,7 @@ public sealed class FailAndStartPresetTest
- type: entity
id: TestRule
parent: BaseGameRule
noSpawn: true
categories: [ GameRules ]
components:
- type: GameRule
minPlayers: 0
@@ -45,7 +45,7 @@ public sealed class FailAndStartPresetTest
- type: entity
id: TestRuleTenPlayers
parent: BaseGameRule
noSpawn: true
categories: [ GameRules ]
components:
- type: GameRule
minPlayers: 10

View File

@@ -27,7 +27,7 @@ namespace Content.IntegrationTests.Tests.GameRules;
[TestFixture]
public sealed class NukeOpsTest
{
{/*
/// <summary>
/// Check that a nuke ops game mode can start without issue. I.e., that the nuke station and such all get loaded.
/// </summary>
@@ -250,5 +250,5 @@ public sealed class NukeOpsTest
ticker.SetGamePreset((GamePresetPrototype?) null);
await pair.CleanReturnAsync();
}
}*/
}

View File

@@ -43,31 +43,16 @@ namespace Content.IntegrationTests.Tests
};
private static readonly string[] GameMaps =
{
"Dev", //CrystallPunk Map replacement
//"TestTeg",
//"Fland",
//"Meta",
//"Packed",
//"Cluster",
//"Omega",
//"Bagel",
//"Origin",
{//CrystallPunk Map replacement
"Dev",
"CentComm",
//"Box",
//"Europa",
//"Saltern",
//"Core",
//"Marathon",
"MeteorArena",
//"Atlas",
//"Reach",
//"Train",
//"Oasis"
//CrystallPunk maps
"AlchemyTest",
"BattleRoyale"
"BattleRoyale",
"ExpeditionTest",
//CrystallPunk Map replacement end
};
/// <summary>
@@ -212,10 +197,10 @@ namespace Content.IntegrationTests.Tests
targetGrid = gridEnt;
}
}
// Test shuttle can dock.
// This is done inside gamemap test because loading the map takes ages and we already have it.
var station = entManager.GetComponent<StationMemberComponent>(targetGrid!.Value).Station;
/*
if (entManager.TryGetComponent<StationEmergencyShuttleComponent>(station, out var stationEvac))
{
var shuttlePath = stationEvac.EmergencyShuttlePath;
@@ -234,7 +219,7 @@ namespace Content.IntegrationTests.Tests
}
mapManager.DeleteMap(shuttleMap);
*/ //CP14 Disable FTL test
if (entManager.HasComponent<StationJobsComponent>(station))
{
// Test that the map has valid latejoin spawn points or container spawn points

View File

@@ -13,7 +13,7 @@ namespace Content.IntegrationTests.Tests.Station;
[TestFixture]
[TestOf(typeof(EmergencyShuttleSystem))]
public sealed class EvacShuttleTest
{
{/*
/// <summary>
/// Ensure that the emergency shuttle can be called, and that it will travel to centcomm
/// </summary>
@@ -123,5 +123,5 @@ public sealed class EvacShuttleTest
pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, false);
pair.Server.CfgMan.SetCVar(CCVars.GameMap, gameMap);
await pair.CleanReturnAsync();
}
}*/
}

View File

@@ -47,7 +47,7 @@ public sealed class JobWhitelistAddCommand : LocalizedCommands
var isWhitelisted = await _db.IsJobWhitelisted(guid, job);
if (isWhitelisted)
{
shell.WriteLine(Loc.GetString("cmd-jobwhitelist-already-whitelisted",
shell.WriteLine(Loc.GetString("cmd-jobwhitelistadd-already-whitelisted",
("player", player),
("jobId", job.Id),
("jobName", jobPrototype.LocalizedName)));

View File

@@ -285,18 +285,18 @@ public sealed partial class AdminVerbSystem
{
Text = "admin-smite-remove-hands-name",
Category = VerbCategory.Smite,
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
Icon = new SpriteSpecifier.Rsi(new("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
Act = () =>
{
_vomitSystem.Vomit(args.Target, -1000, -1000); // You feel hollow!
var organs = _bodySystem.GetBodyOrganComponents<TransformComponent>(args.Target, body);
var organs = _bodySystem.GetBodyOrganEntityComps<TransformComponent>((args.Target, body));
var baseXform = Transform(args.Target);
foreach (var (xform, organ) in organs)
foreach (var organ in organs)
{
if (HasComp<BrainComponent>(xform.Owner) || HasComp<EyeComponent>(xform.Owner))
if (HasComp<BrainComponent>(organ.Owner) || HasComp<EyeComponent>(organ.Owner))
continue;
_transformSystem.AttachToGridOrMap(organ.Owner);
_transformSystem.PlaceNextTo((organ.Owner, organ.Comp1), (args.Target, baseXform));
}
_popupSystem.PopupEntity(Loc.GetString("admin-smite-vomit-organs-self"), args.Target,
@@ -361,9 +361,9 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "stomach"),
Act = () =>
{
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<StomachComponent>(args.Target, body))
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<StomachComponent>((args.Target, body)))
{
QueueDel(component.Owner);
QueueDel(entity.Owner);
}
_popupSystem.PopupEntity(Loc.GetString("admin-smite-stomach-removal-self"), args.Target,
@@ -381,9 +381,9 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "lung-r"),
Act = () =>
{
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<LungComponent>(args.Target, body))
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<LungComponent>((args.Target, body)))
{
QueueDel(component.Owner);
QueueDel(entity.Owner);
}
_popupSystem.PopupEntity(Loc.GetString("admin-smite-lung-removal-self"), args.Target,

View File

@@ -122,7 +122,7 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
_audio.PlayPvs(ent.Comp.ConnectedSound, ent);
}
//TO DO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
//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 DisconneсtFromAnomaly(Entity<AnomalySynchronizerComponent> ent, AnomalyComponent anomaly)
{

View File

@@ -76,7 +76,7 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem
if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier;
newSol.AddReagent(component.ProducingReagent, reagentProducingAmount);
_solutionContainer.TryAddSolution(component.Solution.Value, newSol); //TO DO - the container is not fully filled.
_solutionContainer.TryAddSolution(component.Solution.Value, newSol); // TODO - the container is not fully filled.
component.AccumulatedFrametime = 0;

View File

@@ -336,7 +336,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
}
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
_role.MindAddRoles(curMind.Value, def.MindComponents);
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
SendBriefing(session, def.Briefing);
}

View File

@@ -157,7 +157,7 @@ public sealed partial class BlockGame
/// <param name="message">The message to broadcase to all players/spectators.</param>
private void SendMessage(BoundUserInterfaceMessage message)
{
_uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message);
_uiSystem.ServerSendUiMessage(_owner, BlockGameUiKey.Key, message);
}
/// <summary>
@@ -167,7 +167,7 @@ public sealed partial class BlockGame
/// <param name="actor">The target recipient.</param>
private void SendMessage(BoundUserInterfaceMessage message, EntityUid actor)
{
_uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message, actor);
_uiSystem.ServerSendUiMessage(_owner, BlockGameUiKey.Key, message, actor);
}
/// <summary>

View File

@@ -31,7 +31,7 @@ public sealed class CharacterInfoSystem : EntitySystem
var entity = args.SenderSession.AttachedEntity.Value;
var objectives = new Dictionary<string, List<ObjectiveInfo>>();
var jobTitle = "No Profession";
var jobTitle = Loc.GetString("character-info-no-profession");
string? briefing = null;
if (_minds.TryGetMind(entity, out var mindId, out var mind))
{

View File

@@ -206,9 +206,9 @@ public sealed class InjectorSystem : SharedInjectorSystem
BreakOnMove = true,
BreakOnWeightlessMove = false,
BreakOnDamage = true,
NeedHand = true,
BreakOnHandChange = true,
MovementThreshold = 0.1f,
NeedHand = injector.Comp.NeedHand,
BreakOnHandChange = injector.Comp.BreakOnHandChange,
MovementThreshold = injector.Comp.MovementThreshold,
});
}

View File

@@ -1,8 +1,7 @@
using Content.Server._CP14.MeleeWeapon;
using Content.Server._CP14.MeleeWeapon.Components;
using Content.Server.Administration.Logs;
using Content.Server.Damage.Components;
using Content.Server.Weapons.Ranged.Systems;
using Content.Shared._CP14.MeleeWeapon.Components;
using Content.Shared.Camera;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
@@ -43,7 +42,7 @@ namespace Content.Server.Damage.Systems
damage *= sharp.Sharpness;
var dmg = _damageable.TryChangeDamage(args.Target, damage, component.IgnoreResistances, origin: args.Component.Thrower);
//CrystallPunk Melee pgrade end
//CrystallPunk Melee upgrade end
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
if (dmg != null && HasComp<MobStateComponent>(args.Target))

View File

@@ -16,7 +16,7 @@ public sealed class DamagedByFlashingSystem : EntitySystem
{
_damageable.TryChangeDamage(ent, ent.Comp.FlashDamage);
//To Do: It would be more logical if different flashes had different power,
//TODO: It would be more logical if different flashes had different power,
//and the damage would be inflicted depending on the strength of the flash.
}
}

View File

@@ -96,7 +96,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
private void AddWipeVerb(EntityUid uid, ToggleableGhostRoleComponent component, GetVerbsEvent<ActivationVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
return;
if (TryComp<MindContainerComponent>(uid, out var mind) && mind.HasMind)

View File

@@ -157,7 +157,7 @@ namespace Content.Server.Kitchen.EntitySystems
var outputContainer = _itemSlotsSystem.GetItemOrNull(uid, SharedReagentGrinder.BeakerSlotId);
_appearanceSystem.SetData(uid, ReagentGrinderVisualState.BeakerAttached, outputContainer.HasValue);
if (reagentGrinder.AutoMode != GrinderAutoMode.Off && !HasComp<ActiveReagentGrinderComponent>(uid))
if (reagentGrinder.AutoMode != GrinderAutoMode.Off && !HasComp<ActiveReagentGrinderComponent>(uid) && this.IsPowered(uid, EntityManager))
{
var program = reagentGrinder.AutoMode == GrinderAutoMode.Grind ? GrinderProgram.Grind : GrinderProgram.Juice;
DoWork(uid, reagentGrinder, program);

View File

@@ -71,9 +71,9 @@ public sealed class LightningSystem : SharedLightningSystem
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
{
//To Do: add support to different priority target tablem for different lightning types
//To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
//To Do: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
//TODO: add support to different priority target tablem for different lightning types
//TODO: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
//TODO: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
// several hashsets every time
var targets = _lookup.GetComponentsInRange<LightningTargetComponent>(_transform.GetMapCoordinates(user), range).ToList();

View File

@@ -26,6 +26,11 @@ public interface IGridSpawnGroup
/// </summary>
public float MinimumDistance { get; }
/// <summary>
/// Maximum distance to spawn away from the station.
/// </summary>
public float MaximumDistance { get; }
/// <inheritdoc />
public ProtoId<DatasetPrototype>? NameDataset { get; }
@@ -67,6 +72,8 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
/// <inheritdoc />
public float MinimumDistance { get; }
public float MaximumDistance { get; }
/// <inheritdoc />
public ProtoId<DatasetPrototype>? NameDataset { get; }
@@ -94,7 +101,11 @@ public sealed class GridSpawnGroup : IGridSpawnGroup
{
public List<ResPath> Paths = new();
/// <inheritdoc />
public float MinimumDistance { get; }
/// <inheritdoc />
public float MaximumDistance { get; }
public ProtoId<DatasetPrototype>? NameDataset { get; }
public int MinCount { get; set; } = 1;
public int MaxCount { get; set; } = 1;

View File

@@ -281,24 +281,24 @@ namespace Content.Server.Shuttles.Systems
{
if (_doorSystem.TryOpen(dockAUid, doorA))
{
doorA.ChangeAirtight = false;
if (TryComp<DoorBoltComponent>(dockAUid, out var airlockA))
{
_doorSystem.SetBoltsDown((dockAUid, airlockA), true);
}
}
doorA.ChangeAirtight = false;
}
if (TryComp(dockBUid, out DoorComponent? doorB))
{
if (_doorSystem.TryOpen(dockBUid, doorB))
{
doorB.ChangeAirtight = false;
if (TryComp<DoorBoltComponent>(dockBUid, out var airlockB))
{
_doorSystem.SetBoltsDown((dockBUid, airlockB), true);
}
}
doorB.ChangeAirtight = false;
}
if (_pathfinding.TryCreatePortal(dockAXform.Coordinates, dockBXform.Coordinates, out var handle))

View File

@@ -10,6 +10,7 @@ using Content.Shared.Shuttles.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -86,9 +87,15 @@ public sealed partial class ShuttleSystem
_mapManager.DeleteMap(mapId);
}
private bool TryDungeonSpawn(EntityUid targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
{
spawned = EntityUid.Invalid;
if (!_gridQuery.Resolve(targetGrid.Owner, ref targetGrid.Comp))
{
return false;
}
var dungeonProtoId = _random.Pick(group.Protos);
if (!_protoManager.TryIndex(dungeonProtoId, out var dungeonProto))
@@ -96,11 +103,13 @@ public sealed partial class ShuttleSystem
return false;
}
var spawnCoords = new EntityCoordinates(targetGrid, Vector2.Zero);
var targetPhysics = _physicsQuery.Comp(targetGrid);
var spawnCoords = new EntityCoordinates(targetGrid, targetPhysics.LocalCenter);
if (group.MinimumDistance > 0f)
{
spawnCoords = spawnCoords.Offset(_random.NextVector2(group.MinimumDistance, group.MinimumDistance * 1.5f));
var distancePadding = MathF.Max(targetGrid.Comp.LocalAABB.Width, targetGrid.Comp.LocalAABB.Height);
spawnCoords = spawnCoords.Offset(_random.NextVector2(distancePadding + group.MinimumDistance, distancePadding + group.MaximumDistance));
}
var spawnMapCoords = _transform.ToMapCoordinates(spawnCoords);

View File

@@ -1,4 +1,5 @@
using Content.Server.Shuttles.Components;
using Content.Shared.CCVar;
using Content.Shared.Shuttles.BUIStates;
using Content.Shared.Shuttles.Components;
using Content.Shared.Shuttles.Events;
@@ -12,6 +13,26 @@ public sealed partial class ShuttleSystem
SubscribeLocalEvent<IFFConsoleComponent, AnchorStateChangedEvent>(OnIFFConsoleAnchor);
SubscribeLocalEvent<IFFConsoleComponent, IFFShowIFFMessage>(OnIFFShow);
SubscribeLocalEvent<IFFConsoleComponent, IFFShowVesselMessage>(OnIFFShowVessel);
SubscribeLocalEvent<GridSplitEvent>(OnGridSplit);
}
private void OnGridSplit(ref GridSplitEvent ev)
{
var splitMass = _cfg.GetCVar(CCVars.HideSplitGridsUnder);
if (splitMass < 0)
return;
foreach (var grid in ev.NewGrids)
{
if (!_physicsQuery.TryGetComponent(grid, out var physics) ||
physics.Mass > splitMass)
{
continue;
}
AddIFFFlag(grid, IFFFlags.HideLabel);
}
}
private void OnIFFShow(EntityUid uid, IFFConsoleComponent component, IFFShowIFFMessage args)

View File

@@ -60,12 +60,16 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly AtmosphereSystem _atmos = default!; //CP14 FTL atmos
private EntityQuery<MapGridComponent> _gridQuery;
public const float TileMassMultiplier = 0.5f;
public override void Initialize()
{
base.Initialize();
_gridQuery = GetEntityQuery<MapGridComponent>();
InitializeFTL();
InitializeGridFills();
InitializeIFF();

View File

@@ -68,6 +68,8 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
_spawnerCallbacks = new Dictionary<SpawnPriorityPreference, Action<PlayerSpawningEvent>>()
{
{ SpawnPriorityPreference.Arrivals, _CP14expedition.HandlePlayerSpawning }, //CP14 expedition system replaced
{ SpawnPriorityPreference.Cryosleep, _CP14expedition.HandlePlayerSpawning }, //CP14 expedition system replaced
/*
{
SpawnPriorityPreference.Cryosleep, ev =>
{
@@ -76,7 +78,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
else
_containerSpawnPointSystem.HandlePlayerSpawning(ev);
}
}
}*/
};
}

View File

@@ -1,97 +0,0 @@
/*
* All right reserved to CrystallPunk.
*
* This file is sublicensed under Custom License Agreement for Stalker14 project (https://github.com/stalker14-project/stalker14) only
*
* See LICENSE.TXT file in the project root for full license information.
* Copyright (c) 2024 TheShuEd (Github)
*/
using System.Numerics;
using Content.Server.Decals;
using Content.Server.GameTicking;
using Content.Server.Parallax;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._CP14.BiomeSpawner;
public sealed class CP14BiomeSpawnerSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private int _seed = 27;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RoundStartAttemptEvent>(OnRoundStartAttempt);
SubscribeLocalEvent<CP14BiomeSpawnerComponent, MapInitEvent>(OnMapInit);
}
private void OnRoundStartAttempt(RoundStartAttemptEvent ev)
{
_seed = _random.Next(100000);
}
private void OnMapInit(Entity<CP14BiomeSpawnerComponent> spawner, ref MapInitEvent args)
{
SpawnBiome(spawner);
QueueDel(spawner);
}
private void SpawnBiome(Entity<CP14BiomeSpawnerComponent> spawner)
{
var biome = _proto.Index(spawner.Comp.Biome);
var parent = _transform.GetParent(spawner);
if (parent == null)
return;
var gridUid = parent.Owner;
if (!TryComp<MapGridComponent>(gridUid, out var map))
return;
var v2i = _transform.GetGridOrMapTilePosition(spawner);
if (!_biome.TryGetTile(v2i, biome.Layers, _seed, map, out var tile))
return;
// Set new tile
_maps.SetTile(gridUid, map, v2i, tile.Value);
// Remove old decals
var oldDecals = _decals.GetDecalsInRange(gridUid, v2i + new Vector2(0.5f, 0.5f));
foreach (var (id, _) in oldDecals)
{
_decals.RemoveDecal(gridUid, id);
}
//Add decals
if (_biome.TryGetDecals(v2i, biome.Layers, _seed, map, out var decals))
{
foreach (var decal in decals)
{
_decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out _);
}
}
//TODO maybe need remove anchored entities here
//Add entities
if (_biome.TryGetEntity(v2i, biome.Layers, tile.Value, _seed, map, out var entityProto))
{
var ent = _entManager.SpawnEntity(entityProto,
new EntityCoordinates(gridUid, v2i + map.TileSizeHalfVector));
}
}
}

View File

@@ -1,16 +1,15 @@
/*
* All right reserved to CrystallPunk.
*
* This file is sublicensed under Custom License Agreement for Stalker14 project (https://github.com/stalker14-project/stalker14) only
* BUT this file is sublicensed under MIT License
*
* See LICENSE.TXT file in the project root for full license information.
* Copyright (c) 2024 TheShuEd (Github)
*/
using Content.Server._CP14.BiomeSpawner.EntitySystems;
using Content.Shared.Parallax.Biomes;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.BiomeSpawner;
namespace Content.Server._CP14.BiomeSpawner.Components;
/// <summary>
/// fills the tile in which it is located with the contents of the biome. Includes: tile, decals and entities

View File

@@ -0,0 +1,92 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
using System.Linq;
using Content.Server._CP14.BiomeSpawner.Components;
using Content.Server._CP14.RoundSeed;
using Content.Server.Decals;
using Content.Server.Parallax;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.BiomeSpawner.EntitySystems;
public sealed class CP14BiomeSpawnerSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly CP14RoundSeedSystem _roundSeed = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14BiomeSpawnerComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(Entity<CP14BiomeSpawnerComponent> ent, ref MapInitEvent args)
{
SpawnBiome(ent);
QueueDel(ent);
}
private void SpawnBiome(Entity<CP14BiomeSpawnerComponent> ent)
{
var biome = _proto.Index(ent.Comp.Biome);
var spawnerTransform = Transform(ent);
if (spawnerTransform.GridUid == null)
return;
var gridUid = spawnerTransform.GridUid.Value;
if (!TryComp<MapGridComponent>(gridUid, out var map))
return;
var seed = _roundSeed.GetSeed();
var vec = _transform.GetGridOrMapTilePosition(ent);
if (!_biome.TryGetTile(vec, biome.Layers, seed, map, out var tile))
return;
// Set new tile
_maps.SetTile(gridUid, map, vec, tile.Value);
var tileCenterVec = vec + map.TileSizeHalfVector;
// Remove old decals
var oldDecals = _decals.GetDecalsInRange(gridUid, tileCenterVec);
foreach (var (id, _) in oldDecals)
{
_decals.RemoveDecal(gridUid, id);
}
//Add decals
if (_biome.TryGetDecals(vec, biome.Layers, seed, map, out var decals))
{
foreach (var decal in decals)
{
_decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out _);
}
}
// Remove entities
var oldEntities = _lookup.GetEntitiesInRange(spawnerTransform.Coordinates, 0.48f);
// TODO: Replace this shit with GetEntitiesInBox2
foreach (var entToRemove in oldEntities.Concat(new[] { ent.Owner })) // Do not remove self
{
QueueDel(entToRemove);
}
if (_biome.TryGetEntity(vec, biome.Layers, tile.Value, seed, map, out var entityProto))
Spawn(entityProto, new EntityCoordinates(gridUid, tileCenterVec));
}
}

View File

@@ -1,11 +1,16 @@
using Content.Server._CP14.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Shared.Random.Helpers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.GameTicking.Rules;
public sealed class CP14ExpeditionObjectivesRule : GameRuleSystem<CP14ExpeditionObjectivesRuleComponent>
{
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
@@ -25,9 +30,38 @@ public sealed class CP14ExpeditionObjectivesRule : GameRuleSystem<CP14Expedition
return;
}
foreach (var objective in expedition.Objectives)
foreach (var (job, groups) in expedition.RoleObjectives)
{
_mind.TryAddObjective(mindId.Value, mind, objective);
if (args.JobId is null || args.JobId != job)
continue;
foreach (var weightGroupProto in groups)
{
if (!_proto.TryIndex(weightGroupProto, out var weightGroup))
continue;
_mind.TryAddObjective(mindId.Value, mind, weightGroup.Pick(_random));
}
}
foreach (var (departmentProto, objectives) in expedition.DepartmentObjectives)
{
if (args.JobId is null)
continue;
if (!_proto.TryIndex(departmentProto, out var department))
continue;
if (!department.Roles.Contains(args.JobId))
continue;
foreach (var weightGroupProto in objectives)
{
if (!_proto.TryIndex(weightGroupProto, out var weightGroup))
continue;
_mind.TryAddObjective(mindId.Value, mind, weightGroup.Pick(_random));
}
}
}
}

View File

@@ -1,4 +1,6 @@
using Content.Server.GameTicking.Rules;
using Content.Shared.Random;
using Content.Shared.Roles;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.GameTicking.Rules.Components;
@@ -10,5 +12,8 @@ namespace Content.Server._CP14.GameTicking.Rules.Components;
public sealed partial class CP14ExpeditionObjectivesRuleComponent : Component
{
[DataField]
public List<EntProtoId> Objectives = new();
public Dictionary<ProtoId<JobPrototype>, List<ProtoId<WeightedRandomPrototype>>> RoleObjectives = new();
[DataField]
public Dictionary<ProtoId<DepartmentPrototype>, List<ProtoId<WeightedRandomPrototype>>> DepartmentObjectives = new();
}

View File

@@ -1,14 +1,10 @@
using System.Linq;
using Content.Server.GameTicking.Events;
using Content.Shared._CP14.LockKey;
using Content.Shared.Containers.ItemSlots;
using Content.Shared._CP14.LockKey.Components;
using Content.Shared.Examine;
using Content.Shared.Lock;
using Content.Shared.Popups;
using Content.Shared.GameTicking;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using CP14KeyComponent = Content.Shared._CP14.LockKey.Components.CP14KeyComponent;
using CP14LockComponent = Content.Shared._CP14.LockKey.Components.CP14LockComponent;
namespace Content.Server._CP14.LockKey;
@@ -16,9 +12,6 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly LockSystem _lock = default!;
private Dictionary<ProtoId<CP14LockCategoryPrototype>, List<int>> _roundKeyData = new();
@@ -28,7 +21,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundEnd);
SubscribeLocalEvent<CP14LockComponent, MapInitEvent>(OnLockInit);
SubscribeLocalEvent<CP14KeyComponent, MapInitEvent>(OnKeyInit);
@@ -37,7 +30,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
}
#region Init
private void OnRoundStart(RoundStartingEvent ev)
private void OnRoundEnd(RoundRestartCleanupEvent ev)
{
_roundKeyData = new();
}
@@ -68,7 +61,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
if (key.Comp.LockShape == null)
return;
var markup = Loc.GetString("cp-lock-examine-key", ("item", MetaData(key).EntityName));
var markup = Loc.GetString("cp14-lock-examine-key", ("item", MetaData(key).EntityName));
markup += " (";
foreach (var item in key.Comp.LockShape)
{

View File

@@ -0,0 +1,93 @@
using System.Numerics;
using Content.Server._CP14.MagicEnergy.Components;
using Content.Shared._CP14.MagicEnergy.Components;
namespace Content.Server._CP14.MagicEnergy;
public partial class CP14MagicEnergySystem
{
private void InitializeDraw()
{
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnDrawMapInit);
SubscribeLocalEvent<CP14RandomAuraNodeComponent, MapInitEvent>(OnRandomRangeMapInit);
}
private void OnRandomRangeMapInit(Entity<CP14RandomAuraNodeComponent> random, ref MapInitEvent args)
{
if (!TryComp<CP14AuraNodeComponent>(random, out var draw))
return;
draw.Energy = _random.NextFloat(random.Comp.MinDraw, random.Comp.MaxDraw);
draw.Range = _random.NextFloat(random.Comp.MinRange, random.Comp.MaxRange);
}
private void OnDrawMapInit(Entity<CP14MagicEnergyDrawComponent> ent, ref MapInitEvent args)
{
ent.Comp.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp.Delay);
}
private void UpdateDraw(float frameTime)
{
UpdateEnergyContainer();
UpdateEnergyCrystalSlot();
UpdateEnergyRadiusDraw();
}
private void UpdateEnergyContainer()
{
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyContainerComponent>();
while (query.MoveNext(out var uid, out var draw, out var magicContainer))
{
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
ChangeEnergy(uid, magicContainer, draw.Energy, safe: draw.Safe);
}
}
private void UpdateEnergyCrystalSlot()
{
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyCrystalSlotComponent>();
while (query.MoveNext(out var uid, out var draw, out var slot))
{
if (!draw.Enable)
continue;
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
if (!_magicSlot.TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp))
continue;
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
}
}
private void UpdateEnergyRadiusDraw()
{
var query = EntityQueryEnumerator<CP14AuraNodeComponent>();
while (query.MoveNext(out var uid, out var draw))
{
if (!draw.Enable)
continue;
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
var containers = _lookup.GetEntitiesInRange<CP14MagicEnergyContainerComponent>(Transform(uid).Coordinates, draw.Range);
foreach (var container in containers)
{
var distance = Vector2.Distance(_transform.GetWorldPosition(uid), _transform.GetWorldPosition(container));
var energyDraw = draw.Energy * (1 - distance / draw.Range);
ChangeEnergy(container, container.Comp, energyDraw, true);
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System.Numerics;
using Content.Server._CP14.MagicEnergy.Components;
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
namespace Content.Server._CP14.MagicEnergy;
public partial class CP14MagicEnergySystem
{
private void InitializeScanner()
{
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, CP14MagicEnergyScanEvent>(OnMagicScanAttempt);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, InventoryRelayedEvent<CP14MagicEnergyScanEvent>>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args));
SubscribeLocalEvent<CP14AuraScannerComponent, UseInHandEvent>(OnAuraScannerUseInHand);
}
private void OnMagicScanAttempt(EntityUid uid, CP14MagicEnergyScannerComponent component, CP14MagicEnergyScanEvent args)
{
args.CanScan = true;
}
private void OnExamined(Entity<CP14MagicEnergyExaminableComponent> ent, ref ExaminedEvent args)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(ent, out var magicContainer))
return;
var scanEvent = new CP14MagicEnergyScanEvent();
RaiseLocalEvent(args.Examiner, scanEvent);
if (!scanEvent.CanScan)
return;
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
}
private void OnAuraScannerUseInHand(Entity<CP14AuraScannerComponent> scanner, ref UseInHandEvent args)
{
FixedPoint2 sumDraw = 0f;
var query = EntityQueryEnumerator<CP14AuraNodeComponent, TransformComponent>();
while (query.MoveNext(out var auraUid, out var node, out var xform))
{
if (xform.MapUid != Transform(scanner).MapUid)
continue;
var distance = Vector2.Distance(_transform.GetWorldPosition(auraUid), _transform.GetWorldPosition(scanner));
if (distance > node.Range)
continue;
sumDraw += node.Energy * (1 - distance / node.Range);
}
_popup.PopupCoordinates(Loc.GetString("cp14-magic-scanner", ("power", sumDraw)), Transform(scanner).Coordinates, args.User);
}
}

View File

@@ -1,152 +1,29 @@
using Content.Server._CP14.MagicEnergy.Components;
using Content.Server.Popups;
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Robust.Server.GameObjects;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.MagicEnergy;
public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly PointLightSystem _light = default!;
[Dependency] private readonly CP14MagicEnergyCrystalSlotSystem _magicSlot = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly PopupSystem _popup = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<CP14MagicEnergyPointLightControllerComponent, CP14MagicEnergyLevelChangeEvent>(OnEnergyChange);
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, CP14MagicEnergyScanEvent>(OnMagicScanAttempt);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, InventoryRelayedEvent<CP14MagicEnergyScanEvent>>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args));
InitializeDraw();
InitializeScanner();
}
private void OnEnergyChange(Entity<CP14MagicEnergyPointLightControllerComponent> ent, ref CP14MagicEnergyLevelChangeEvent args)
{
if (!TryComp<PointLightComponent>(ent, out var light))
return;
var lightEnergy = MathHelper.Lerp(ent.Comp.MinEnergy, ent.Comp.MaxEnergy, (float)(args.NewValue / args.MaxValue));
_light.SetEnergy(ent, lightEnergy, light);
}
private void OnMapInit(Entity<CP14MagicEnergyDrawComponent> ent, ref MapInitEvent args)
{
ent.Comp.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp.Delay);
}
private void OnMagicScanAttempt(EntityUid uid, CP14MagicEnergyScannerComponent component, CP14MagicEnergyScanEvent args)
{
args.CanScan = true;
}
private void OnExamined(Entity<CP14MagicEnergyExaminableComponent> ent, ref ExaminedEvent args)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(ent, out var magicContainer))
return;
var scanEvent = new CP14MagicEnergyScanEvent();
RaiseLocalEvent(args.Examiner, scanEvent);
if (!scanEvent.CanScan)
return;
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyContainerComponent>();
while (query.MoveNext(out var uid, out var draw, out var magicContainer))
{
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
ChangeEnergy(uid, magicContainer, draw.Energy, safe: draw.Safe);
}
var query2 = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyCrystalSlotComponent>();
while (query2.MoveNext(out var uid, out var draw, out var slot))
{
if (!draw.Enable)
continue;
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
if (!_magicSlot.TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp))
continue;
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
}
}
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
{
if (!Resolve(uid, ref component))
return false;
if (energy <= 0)
return true;
// Attempting to absorb more energy than is contained in the carrier will still waste all the energy
if (component.Energy < energy)
{
ChangeEnergy(uid, component, -component.Energy);
return false;
}
ChangeEnergy(uid, component, -energy, safe);
return true;
}
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
{
if (!safe)
{
//Overload
if (component.Energy + energy > component.MaxEnergy)
{
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
{
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
});
}
//Burn out
if (component.Energy + energy < 0)
{
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
{
BurnOutEnergy = -energy - component.Energy
});
}
}
var oldEnergy = component.Energy;
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
component.Energy = newEnergy;
if (oldEnergy != newEnergy)
{
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
{
OldValue = component.Energy,
NewValue = newEnergy,
MaxValue = component.MaxEnergy,
});
}
UpdateDraw(frameTime);
}
}

View File

@@ -0,0 +1,50 @@
using Content.Shared.FixedPoint;
namespace Content.Server._CP14.MagicEnergy.Components;
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
public sealed partial class CP14AuraNodeComponent : Component
{
[DataField]
public bool Enable = true;
[DataField]
public FixedPoint2 Energy = 1f;
[DataField]
public float Range = 10f;
/// <summary>
/// If not safe, restoring or drawing power across boundaries call dangerous events, that may destroy crystals
/// </summary>
[DataField]
public bool Safe = true;
/// <summary>
/// how often objects will try to change magic energy. In Seconds
/// </summary>
[DataField]
public float Delay = 5f;
/// <summary>
/// the time of the next magic energy change
/// </summary>
[DataField]
public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero;
}
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
public sealed partial class CP14RandomAuraNodeComponent : Component
{
[DataField]
public float MinDraw = -2f;
[DataField]
public float MaxDraw = 2f;
[DataField]
public float MinRange = 5f;
[DataField]
public float MaxRange = 10f;
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._CP14.MagicEnergy.Components;
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
public sealed partial class CP14AuraScannerComponent : Component
{
}

View File

@@ -0,0 +1,40 @@
using Content.Server.Chat.Systems;
using Content.Shared._CP14.MagicSpell;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Robust.Server.GameObjects;
namespace Content.Server._CP14.MagicSpell;
public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly TransformSystem _transform = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14VerbalAspectSpeechEvent>(OnSpellSpoken);
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14EndCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
}
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14VerbalAspectSpeechEvent args)
{
if (args.Performer is not null && args.Speech is not null)
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, InGameICChatType.Speak, true);
}
private void OnSpawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StartCastMagicEffectEvent args)
{
var vfx = SpawnAttachedTo(ent.Comp.Proto, Transform(args.Performer).Coordinates);
_transform.SetParent(vfx, args.Performer);
ent.Comp.SpawnedEntity = vfx;
}
private void OnDespawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14EndCastMagicEffectEvent args)
{
QueueDel(ent.Comp.SpawnedEntity);
ent.Comp.SpawnedEntity = null;
}
}

View File

@@ -1,10 +0,0 @@
using Content.Shared.Damage;
namespace Content.Server._CP14.MeleeWeapon.Components;
[RegisterComponent]
public sealed partial class CP14MeleeSelfDamageComponent : Component
{
[DataField(required: true)]
public DamageSpecifier DamageToSelf;
}

View File

@@ -0,0 +1,26 @@
using Content.Server._CP14.Objectives.Systems;
using Robust.Shared.Utility;
namespace Content.Server._CP14.Objectives.Components;
[RegisterComponent, Access(typeof(CP14CurrencyCollectConditionSystem))]
public sealed partial class CP14CurrencyCollectConditionComponent : Component
{
[DataField]
public int Currency = 1000;
/// <summary>
/// Limits the goal to collecting values from a specific category.
/// </summary>
[DataField]
public string? Category;
[DataField(required: true)]
public LocId ObjectiveText;
[DataField(required: true)]
public LocId ObjectiveDescription;
[DataField(required: true)]
public SpriteSpecifier ObjectiveSprite;
}

View File

@@ -0,0 +1,113 @@
using Content.Server._CP14.Objectives.Components;
using Content.Shared._CP14.Currency;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Objectives.Components;
using Content.Shared.Objectives.Systems;
using Robust.Shared.Containers;
namespace Content.Server._CP14.Objectives.Systems;
public sealed class CP14CurrencyCollectConditionSystem : EntitySystem
{
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
[Dependency] private readonly CP14CurrencySystem _currency = default!;
private EntityQuery<ContainerManagerComponent> _containerQuery;
public override void Initialize()
{
base.Initialize();
_containerQuery = GetEntityQuery<ContainerManagerComponent>();
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
}
private void OnAssigned(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveAssignedEvent args)
{
}
private void OnAfterAssign(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
{
_metaData.SetEntityName(condition.Owner, Loc.GetString(condition.Comp.ObjectiveText), args.Meta);
_metaData.SetEntityDescription(condition.Owner, Loc.GetString(condition.Comp.ObjectiveDescription, ("coins", _currency.GetPrettyCurrency(condition.Comp.Currency))), args.Meta);
_objectives.SetIcon(condition.Owner, condition.Comp.ObjectiveSprite);
}
private void OnGetProgress(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveGetProgressEvent args)
{
args.Progress = GetProgress(args.Mind, condition);
}
private float GetProgress(MindComponent mind, CP14CurrencyCollectConditionComponent condition)
{
if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager))
return 0;
var containerStack = new Stack<ContainerManagerComponent>();
var count = 0;
//check pulling object
if (TryComp<PullerComponent>(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition
{
var pulledEntity = pull.Pulling;
if (pulledEntity != null)
{
CheckEntity(pulledEntity.Value, condition, ref containerStack, ref count);
}
}
// recursively check each container for the item
// checks inventory, bag, implants, etc.
do
{
foreach (var container in currentManager.Containers.Values)
{
foreach (var entity in container.ContainedEntities)
{
// check if this is the item
count += CheckCurrency(entity, condition);
// if it is a container check its contents
if (_containerQuery.TryGetComponent(entity, out var containerManager))
containerStack.Push(containerManager);
}
}
} while (containerStack.TryPop(out currentManager));
var result = count / (float) condition.Currency;
result = Math.Clamp(result, 0, 1);
return result;
}
private void CheckEntity(EntityUid entity, CP14CurrencyCollectConditionComponent condition, ref Stack<ContainerManagerComponent> containerStack, ref int counter)
{
// check if this is the item
counter += CheckCurrency(entity, condition);
//we don't check the inventories of sentient entity
if (!TryComp<MindContainerComponent>(entity, out _))
{
// if it is a container check its contents
if (_containerQuery.TryGetComponent(entity, out var containerManager))
containerStack.Push(containerManager);
}
}
private int CheckCurrency(EntityUid entity, CP14CurrencyCollectConditionComponent condition)
{
// check if this is the target
if (!TryComp<CP14CurrencyComponent>(entity, out var target))
return 0;
if (target.Category != condition.Category)
return 0;
return _currency.GetTotalCurrency(entity);
}
}

View File

@@ -0,0 +1,10 @@
using Robust.Shared.Audio;
namespace Content.Server._CP14.PersonalSignature;
[RegisterComponent]
public sealed partial class CP14PersonalSignatureComponent : Component
{
[DataField]
public SoundSpecifier? SignSound;
}

View File

@@ -0,0 +1,79 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Mind;
using Content.Server.Paper;
using Content.Shared.Hands.Components;
using Content.Shared.Paper;
using Content.Shared.Verbs;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Player;
namespace Content.Server._CP14.PersonalSignature;
public sealed class CP14PersonalSignatureSystem : EntitySystem
{
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly MindSystem _mind = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PaperComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
}
private void OnGetVerb(Entity<PaperComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
{
if (!_mind.TryGetMind(args.User, out _, out var mind))
return;
if (mind.CharacterName is null)
return;
if (!CanSign(args.Using, out var signature))
return;
if (HasSign(entity, mind.CharacterName))
return;
args.Verbs.Add(new AlternativeVerb
{
Text = Loc.GetString("cp-sign-verb"),
Act = () =>
{
Sign(entity, mind.CharacterName, signature.SignSound);
},
});
}
private bool CanSign(EntityUid? item, [NotNullWhen(true)] out CP14PersonalSignatureComponent? personalSignature)
{
personalSignature = null;
return item is not null && TryComp(item, out personalSignature);
}
private bool HasSign(Entity<PaperComponent> entity, string sign)
{
foreach (var info in entity.Comp.StampedBy)
{
if (info.StampedName == sign)
return true;
}
return false;
}
private void Sign(Entity<PaperComponent> target, string name, SoundSpecifier? sound)
{
var info = new StampDisplayInfo
{
StampedName = name,
StampedColor = Color.Gray,
};
if (sound is not null)
_audio.PlayEntity(sound, Filter.Pvs(target), target, true);
target.Comp.StampedBy.Add(info);
}
}

View File

@@ -0,0 +1,21 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
namespace Content.Server._CP14.RoundSeed;
/// <summary>
/// This is used for round seed
/// </summary>
[RegisterComponent, Access(typeof(CP14RoundSeedSystem))]
public sealed partial class CP14RoundSeedComponent : Component
{
[ViewVariables]
public static int MaxValue = 10000;
[ViewVariables]
public int Seed;
}

View File

@@ -0,0 +1,53 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server._CP14.RoundSeed;
/// <summary>
/// Provides a round seed for another systems
/// </summary>
public sealed class CP14RoundSeedSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14RoundSeedComponent, ComponentStartup>(OnComponentStartup);
}
private void OnComponentStartup(Entity<CP14RoundSeedComponent> ent, ref ComponentStartup args)
{
ent.Comp.Seed = _random.Next(CP14RoundSeedComponent.MaxValue);
}
private int SetupSeed()
{
return AddComp<CP14RoundSeedComponent>(Spawn(null, MapCoordinates.Nullspace)).Seed;
}
/// <summary>
/// Returns the round seed if assigned, otherwise assigns the round seed itself.
/// </summary>
/// <returns>seed of the round</returns>
public int GetSeed()
{
var query = EntityQuery<CP14RoundSeedComponent>();
foreach (var comp in query)
{
return comp.Seed;
}
var seed = SetupSeed();
Log.Warning($"Missing RoundSeed. Seed set to {seed}");
return seed;
}
}

View File

@@ -29,21 +29,31 @@ public sealed class CP14ExpeditionSystem : EntitySystem
/// </summary>
public float ArrivalTime { get; private set; }
/// <summary>
/// If enabled then spawns players on an expedition ship.
/// </summary>
public bool Enabled { get; private set; }
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, StationPostInitEvent>(OnPostInitSetupExpeditionShip);
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, FTLCompletedEvent>(OnArrivalsDocked);
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, FTLCompletedEvent>(OnExpeditionShipLanded);
ArrivalTime = _cfgManager.GetCVar(CCVars.CP14ExpeditionArrivalTime);
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionArrivalTime, time => ArrivalTime = time, true);
}
Enabled = _cfgManager.GetCVar(CCVars.CP14ExpeditionShip);
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionArrivalTime, time => ArrivalTime = time, true);
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionShip, value => Enabled = value, true);
}
private void OnPostInitSetupExpeditionShip(Entity<CP14StationExpeditionTargetComponent> station, ref StationPostInitEvent args)
{
if (!Enabled)
return;
if (!Deleted(station.Comp.Shuttle))
return;
@@ -76,7 +86,7 @@ public sealed class CP14ExpeditionSystem : EntitySystem
}
}
private void OnArrivalsDocked(Entity<CP14StationExpeditionTargetComponent> ent, ref FTLCompletedEvent args)
private void OnExpeditionShipLanded(Entity<CP14StationExpeditionTargetComponent> ent, ref FTLCompletedEvent args)
{
//Some announsement logic?
}
@@ -97,6 +107,9 @@ public sealed class CP14ExpeditionSystem : EntitySystem
public void HandlePlayerSpawning(PlayerSpawningEvent ev)
{
if (!Enabled)
return;
if (ev.SpawnResult != null)
return;
@@ -114,8 +127,10 @@ public sealed class CP14ExpeditionSystem : EntitySystem
var possiblePositions = new List<EntityCoordinates>();
while (points.MoveNext(out var uid, out var spawnPoint, out var xform))
{
if (ev.Job != null && spawnPoint.Job != ev.Job.Prototype)
continue;
if (spawnPoint.SpawnType != SpawnPointType.LateJoin || xform.GridUid != gridUid)
if (xform.GridUid != gridUid)
continue;
possiblePositions.Add(xform.Coordinates);

View File

@@ -1,16 +1,12 @@
using System.Numerics;
using Content.Server._CP14.Alchemy;
using Content.Server._CP14.MeleeWeapon;
using Content.Server._CP14.MeleeWeapon.EntitySystems;
using Content.Server.Popups;
using Content.Shared._CP14.MeleeWeapon.EntitySystems;
using Content.Shared._CP14.Skills;
using Content.Shared._CP14.Skills.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;

View File

@@ -3,7 +3,7 @@ using Robust.Shared.Utility;
namespace Content.Server._CP14.StationDungeonMap;
/// <summary>
/// Initializes a procedurally generated world with points of interest
/// Loads additional maps from the list at the start of the round.
/// </summary>
[RegisterComponent, Access(typeof(CP14StationAdditionalMapSystem))]
public sealed partial class CP14StationAdditionalMapComponent : Component

View File

@@ -0,0 +1,33 @@
using Content.Shared._CP14.Workbench;
namespace Content.Server._CP14.Workbench;
public sealed partial class CP14WorkbenchSystem
{
private void OnCraft(Entity<CP14WorkbenchComponent> entity, ref CP14WorkbenchUiCraftMessage args)
{
if (!entity.Comp.Recipes.Contains(args.Recipe))
return;
if (!_proto.TryIndex(args.Recipe, out var prototype))
return;
StartCraft(entity, args.Actor, prototype);
}
private void UpdateUIRecipes(Entity<CP14WorkbenchComponent> entity)
{
var placedEntities = _lookup.GetEntitiesInRange(Transform(entity).Coordinates, WorkbenchRadius);
var recipes = new List<CP14WorkbenchUiRecipesEntry>();
foreach (var recipeId in entity.Comp.Recipes)
{
var recipe = _proto.Index(recipeId);
var entry = new CP14WorkbenchUiRecipesEntry(recipeId, CanCraftRecipe(recipe, placedEntities));
recipes.Add(entry);
}
_userInterface.SetUiState(entity.Owner, CP14WorkbenchUiKey.Key, new CP14WorkbenchUiRecipesState(recipes));
}
}

View File

@@ -1,26 +1,32 @@
using Content.Server.DoAfter;
using Content.Server.Popups;
using Content.Server.Stack;
using Content.Shared._CP14.Workbench;
using Content.Shared._CP14.Workbench.Prototypes;
using Content.Shared.DoAfter;
using Content.Shared.Stacks;
using Content.Shared.UserInterface;
using Content.Shared.Verbs;
using Robust.Shared.Audio.Systems;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Workbench;
public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedStackSystem _stack = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly StackSystem _stack = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
private EntityQuery<MetaDataComponent> _metaQuery;
private EntityQuery<StackComponent> _stackQuery;
// Why not in component? Why?
private const float WorkbenchRadius = 0.5f;
public override void Initialize()
@@ -30,10 +36,18 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
_metaQuery = GetEntityQuery<MetaDataComponent>();
_stackQuery = GetEntityQuery<StackComponent>();
SubscribeLocalEvent<CP14WorkbenchComponent, BeforeActivatableUIOpenEvent>(OnBeforeUIOpen);
SubscribeLocalEvent<CP14WorkbenchComponent, CP14WorkbenchUiCraftMessage>(OnCraft);
SubscribeLocalEvent<CP14WorkbenchComponent, GetVerbsEvent<InteractionVerb>>(OnInteractionVerb);
SubscribeLocalEvent<CP14WorkbenchComponent, CP14CraftDoAfterEvent>(OnCraftFinished);
}
private void OnBeforeUIOpen(Entity<CP14WorkbenchComponent> ent, ref BeforeActivatableUIOpenEvent args)
{
UpdateUIRecipes(ent);
}
private void OnInteractionVerb(Entity<CP14WorkbenchComponent> ent, ref GetVerbsEvent<InteractionVerb> args)
{
if (!args.CanAccess || !args.CanInteract || args.Hands is null)
@@ -64,6 +78,7 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
}
}
// TODO: Replace Del to QueueDel when it's will be works with events
private void OnCraftFinished(Entity<CP14WorkbenchComponent> ent, ref CP14CraftDoAfterEvent args)
{
if (args.Cancelled || args.Handled)
@@ -89,7 +104,7 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
if (placedProto != null && placedProto == requiredIngredient.Key && requiredCount > 0)
{
requiredCount--;
QueueDel(placedEntity);
Del(placedEntity);
}
}
}
@@ -106,14 +121,18 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
continue;
var count = (int)MathF.Min(requiredCount, stack.Count);
_stack.SetCount(placedEntity, stack.Count - count, stack);
if (stack.Count - count <= 0)
Del(placedEntity);
else
_stack.SetCount(placedEntity, stack.Count - count, stack);
requiredCount -= count;
}
}
Spawn(_proto.Index(args.Recipe).Result, Transform(ent).Coordinates);
UpdateUIRecipes(ent);
args.Handled = true;
}

View File

@@ -183,6 +183,30 @@ public partial class SharedBodySystem
return list;
}
/// <summary>
/// Returns a list of Entity<<see cref="T"/>, <see cref="OrganComponent"/>>
/// for each organ of the body
/// </summary>
/// <typeparam name="T">The component that we want to return</typeparam>
/// <param name="entity">The body to check the organs of</param>
public List<Entity<T, OrganComponent>> GetBodyOrganEntityComps<T>(
Entity<BodyComponent?> entity)
where T : IComponent
{
if (!Resolve(entity, ref entity.Comp))
return new List<Entity<T, OrganComponent>>();
var query = GetEntityQuery<T>();
var list = new List<Entity<T, OrganComponent>>(3);
foreach (var organ in GetBodyOrgans(entity.Owner, entity.Comp))
{
if (query.TryGetComponent(organ.Id, out var comp))
list.Add((organ.Id, comp, organ.Component));
}
return list;
}
/// <summary>
/// Tries to get a list of ValueTuples of <see cref="T"/> and OrganComponent on each organs
/// in the given body.

View File

@@ -11,11 +11,17 @@ namespace Content.Shared.CCVar
public sealed class CCVars : CVars
{
#region CP14
/// <summary>
/// how long does it take to fly an expedition ship to an expedition point?
/// </summary>
public static readonly CVarDef<float> CP14ExpeditionArrivalTime =
CVarDef.Create("cp14.arrival_time", 60f, CVar.SERVERONLY);
CVarDef.Create("cp14.arrival_time", 180f, CVar.SERVERONLY);
/// <summary>
/// is the expedition ship's system enabled?
/// </summary>
public static readonly CVarDef<bool> CP14ExpeditionShip =
CVarDef.Create("cp14.arrivals_ship", true, CVar.SERVERONLY);
#endregion
/*
* Server
@@ -511,7 +517,7 @@ namespace Content.Shared.CCVar
/// The dataset prototype to use when selecting a random tip.
/// </summary>
public static readonly CVarDef<string> TipsDataset =
CVarDef.Create("tips.dataset", "Tips");
CVarDef.Create("tips.dataset", "CP14Tips");
/// <summary>
/// The number of seconds between each tip being displayed when the round is not actively going
@@ -1473,7 +1479,7 @@ namespace Content.Shared.CCVar
/// Whether the arrivals shuttle is enabled.
/// </summary>
public static readonly CVarDef<bool> ArrivalsShuttles =
CVarDef.Create("shuttle.arrivals", true, CVar.SERVERONLY);
CVarDef.Create("shuttle.arrivals", false, CVar.SERVERONLY); //CP14 arrivals disabled
/// <summary>
/// The map to use for the arrivals station.
@@ -1505,6 +1511,13 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> GodmodeArrivals =
CVarDef.Create("shuttle.godmode_arrivals", false, CVar.SERVERONLY);
/// <summary>
/// If a grid is split then hide any smaller ones under this mass (kg) from the map.
/// This is useful to avoid split grids spamming out labels.
/// </summary>
public static readonly CVarDef<int> HideSplitGridsUnder =
CVarDef.Create("shuttle.hide_split_grids_under", 30, CVar.SERVERONLY);
/// <summary>
/// Whether to automatically spawn escape shuttles.
/// </summary>
@@ -1593,7 +1606,7 @@ namespace Content.Shared.CCVar
/// Whether the emergency shuttle is enabled or should the round just end.
/// </summary>
public static readonly CVarDef<bool> EmergencyShuttleEnabled =
CVarDef.Create("shuttle.emergency", true, CVar.SERVERONLY);
CVarDef.Create("shuttle.emergency", false, CVar.SERVERONLY); //CP14 Emergency disabled
/// <summary>
/// The percentage of time passed from the initial call to when the shuttle can no longer be recalled.

View File

@@ -87,6 +87,22 @@ public sealed partial class InjectorComponent : Component
[AutoNetworkedField]
[DataField]
public InjectorToggleMode ToggleState = InjectorToggleMode.Draw;
#region Arguments for injection doafter
/// <inheritdoc cref=DoAfterArgs.NeedHand>
[DataField]
public bool NeedHand = true;
/// <inheritdoc cref=DoAfterArgs.BreakOnHandChange>
[DataField]
public bool BreakOnHandChange = true;
/// <inheritdoc cref=DoAfterArgs.MovementThreshold>
[DataField]
public float MovementThreshold = 0.1f;
#endregion
}
/// <summary>

View File

@@ -58,7 +58,7 @@ namespace Content.Shared.Cuffs
{
base.Initialize();
SubscribeLocalEvent<HandCountChangedEvent>(OnHandCountChanged);
SubscribeLocalEvent<CuffableComponent, HandCountChangedEvent>(OnHandCountChanged);
SubscribeLocalEvent<UncuffAttemptEvent>(OnUncuffAttempt);
SubscribeLocalEvent<CuffableComponent, EntRemovedFromContainerMessage>(OnCuffsRemovedFromContainer);
@@ -380,33 +380,24 @@ namespace Content.Shared.Cuffs
/// <summary>
/// Check the current amount of hands the owner has, and if there's less hands than active cuffs we remove some cuffs.
/// </summary>
private void OnHandCountChanged(HandCountChangedEvent message)
private void OnHandCountChanged(Entity<CuffableComponent> ent, ref HandCountChangedEvent message)
{
var owner = message.Sender;
if (!TryComp(owner, out CuffableComponent? cuffable) ||
!cuffable.Initialized)
{
return;
}
var dirty = false;
var handCount = CompOrNull<HandsComponent>(owner)?.Count ?? 0;
var handCount = CompOrNull<HandsComponent>(ent.Owner)?.Count ?? 0;
while (cuffable.CuffedHandCount > handCount && cuffable.CuffedHandCount > 0)
while (ent.Comp.CuffedHandCount > handCount && ent.Comp.CuffedHandCount > 0)
{
dirty = true;
var container = cuffable.Container;
var entity = container.ContainedEntities[^1];
var handcuffContainer = ent.Comp.Container;
var handcuffEntity = handcuffContainer.ContainedEntities[^1];
_container.Remove(entity, container);
_transform.SetWorldPosition(entity, _transform.GetWorldPosition(owner));
_transform.PlaceNextTo(handcuffEntity, ent.Owner);
}
if (dirty)
{
UpdateCuffState(owner, cuffable);
UpdateCuffState(ent.Owner, ent.Comp);
}
}

View File

@@ -21,6 +21,7 @@ using Robust.Shared.Physics.Systems;
using Robust.Shared.Timing;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Network;
using Robust.Shared.Map.Components;
namespace Content.Shared.Doors.Systems;
@@ -40,6 +41,8 @@ public abstract partial class SharedDoorSystem : EntitySystem
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
[Dependency] private readonly PryingSystem _pryingSystem = default!;
[Dependency] protected readonly SharedPopupSystem Popup = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[ValidatePrototypeId<TagPrototype>]
public const string DoorBumpTag = "DoorBumpOpener";
@@ -546,29 +549,37 @@ public abstract partial class SharedDoorSystem : EntitySystem
if (!Resolve(uid, ref physics))
yield break;
var xform = Transform(uid);
// Getting the world bounds from the gridUid allows us to use the version of
// GetCollidingEntities that returns Entity<PhysicsComponent>
if (!TryComp<MapGridComponent>(xform.GridUid, out var mapGridComp))
yield break;
var tileRef = _mapSystem.GetTileRef(xform.GridUid.Value, mapGridComp, xform.Coordinates);
var doorWorldBounds = _entityLookup.GetWorldBounds(tileRef);
// TODO SLOTH fix electro's code.
// ReSharper disable once InconsistentNaming
var doorAABB = _entityLookup.GetWorldAABB(uid);
foreach (var otherPhysics in PhysicsSystem.GetCollidingEntities(Transform(uid).MapID, doorAABB))
foreach (var otherPhysics in PhysicsSystem.GetCollidingEntities(Transform(uid).MapID, doorWorldBounds))
{
if (otherPhysics == physics)
if (otherPhysics.Comp == physics)
continue;
//TODO: Make only shutters ignore these objects upon colliding instead of all airlocks
// Excludes Glasslayer for windows, GlassAirlockLayer for windoors, TableLayer for tables
if (!otherPhysics.CanCollide || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassAirlockLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.TableLayer)
if (!otherPhysics.Comp.CanCollide || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassAirlockLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.TableLayer)
continue;
//If the colliding entity is a slippable item ignore it by the airlock
if (otherPhysics.CollisionLayer == (int)CollisionGroup.SlipLayer && otherPhysics.CollisionMask == (int)CollisionGroup.ItemMask)
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.SlipLayer && otherPhysics.Comp.CollisionMask == (int) CollisionGroup.ItemMask)
continue;
//For when doors need to close over conveyor belts
if (otherPhysics.CollisionLayer == (int) CollisionGroup.ConveyorMask)
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.ConveyorMask)
continue;
if ((physics.CollisionMask & otherPhysics.CollisionLayer) == 0 && (otherPhysics.CollisionMask & physics.CollisionLayer) == 0)
if ((physics.CollisionMask & otherPhysics.Comp.CollisionLayer) == 0 && (otherPhysics.Comp.CollisionMask & physics.CollisionLayer) == 0)
continue;
if (_entityLookup.GetWorldAABB(otherPhysics.Owner).IntersectPercentage(doorAABB) < IntersectPercentage)

View File

@@ -18,6 +18,7 @@ namespace Content.Shared.Examine
{
public abstract partial class ExamineSystemShared : EntitySystem
{
[Dependency] private readonly OccluderSystem _occluder = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
@@ -182,12 +183,9 @@ namespace Content.Shared.Examine
length = MaxRaycastRange;
}
var occluderSystem = Get<OccluderSystem>();
IoCManager.Resolve(ref entMan);
var ray = new Ray(origin.Position, dir.Normalized());
var rayResults = occluderSystem
.IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false).ToList();
var rayResults = _occluder
.IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false);
if (rayResults.Count == 0) return true;
@@ -195,13 +193,13 @@ namespace Content.Shared.Examine
foreach (var result in rayResults)
{
if (!entMan.TryGetComponent(result.HitEntity, out OccluderComponent? o))
if (!TryComp(result.HitEntity, out OccluderComponent? o))
{
continue;
}
var bBox = o.BoundingBox;
bBox = bBox.Translated(entMan.GetComponent<TransformComponent>(result.HitEntity).WorldPosition);
bBox = bBox.Translated(_transform.GetWorldPosition(result.HitEntity));
if (bBox.Contains(origin.Position) || bBox.Contains(other.Position))
{
@@ -216,7 +214,6 @@ namespace Content.Shared.Examine
public bool InRangeUnOccluded(EntityUid origin, EntityUid other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
{
var entMan = IoCManager.Resolve<IEntityManager>();
var originPos = _transform.GetMapCoordinates(origin);
var otherPos = _transform.GetMapCoordinates(other);
@@ -225,16 +222,14 @@ namespace Content.Shared.Examine
public bool InRangeUnOccluded(EntityUid origin, EntityCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
{
var entMan = IoCManager.Resolve<IEntityManager>();
var originPos = _transform.GetMapCoordinates(origin);
var otherPos = other.ToMap(entMan, _transform);
var otherPos = _transform.ToMapCoordinates(other);
return InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker);
}
public bool InRangeUnOccluded(EntityUid origin, MapCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
{
var entMan = IoCManager.Resolve<IEntityManager>();
var originPos = _transform.GetMapCoordinates(origin);
return InRangeUnOccluded(originPos, other, range, predicate, ignoreInsideBlocker);
@@ -250,11 +245,12 @@ namespace Content.Shared.Examine
}
var hasDescription = false;
var metadata = MetaData(entity);
//Add an entity description if one is declared
if (!string.IsNullOrEmpty(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription))
if (!string.IsNullOrEmpty(metadata.EntityDescription))
{
message.AddText(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription);
message.AddText(metadata.EntityDescription);
hasDescription = true;
}

View File

@@ -7,12 +7,13 @@ namespace Content.Shared.Humanoid
{
public static bool HasSexMorph(HumanoidVisualLayers layer)
{
return layer switch
{
HumanoidVisualLayers.Chest => true,
HumanoidVisualLayers.Head => true,
_ => false
};
return true; //Support female body
//return layer switch
//{
// HumanoidVisualLayers.Chest => true,
// HumanoidVisualLayers.Head => true,
// _ => false
//};
}
public static string GetSexMorph(HumanoidVisualLayers layer, Sex sex, string id)

View File

@@ -26,9 +26,8 @@ namespace Content.Shared.Localizations
public void Initialize()
{
var culture = new CultureInfo(Culture);
// Uncomment for Ru localization
_loc.LoadCulture(culture);
// Uncomment for Ru localization
var fallbackCulture = new CultureInfo("en-US");
_loc.LoadCulture(fallbackCulture);
_loc.SetFallbackCluture(fallbackCulture);

View File

@@ -92,6 +92,13 @@ public sealed partial class LockComponent : Component
[ByRefEvent]
public record struct LockToggleAttemptEvent(EntityUid User, bool Silent = false, bool Cancelled = false);
/// <summary>
/// Event raised on the user when a toggle is attempted.
/// Can be cancelled to prevent it.
/// </summary>
[ByRefEvent]
public record struct UserLockToggleAttemptEvent(EntityUid Target, bool Silent = false, bool Cancelled = false);
/// <summary>
/// Event raised on a lock after it has been toggled.
/// </summary>

View File

@@ -109,17 +109,14 @@ public sealed class LockSystem : EntitySystem
//CrystallPunk Lock System Adapt Start
if (lockComp.LockSlotId != null && _lockCp14.TryGetLockFromSlot(uid, out var lockEnt))
{
args.PushText(Loc.GetString("cp-lock-examine-lock-slot", ("lock", MetaData(lockEnt.Value).EntityName)));
args.PushText(Loc.GetString("cp14-lock-examine-lock-slot", ("lock", MetaData(lockEnt.Value).EntityName)));
args.PushMarkup(Loc.GetString(lockComp.Locked
? "lock-comp-on-examined-is-locked"
: "lock-comp-on-examined-is-unlocked",
("entityName", Identity.Name(uid, EntityManager))));
if (lockEnt.Value.Comp.LockpickeddFailMarkup)
args.PushMarkup(Loc.GetString("cp-lock-examine-lock-lockpicked", ("lock", MetaData(lockEnt.Value).EntityName)));
} else
{
args.PushText(Loc.GetString("cp-lock-examine-lock-null"));
args.PushMarkup(Loc.GetString("cp14-lock-examine-lock-lockpicked", ("lock", MetaData(lockEnt.Value).EntityName)));
}
//CrystallPunk Lock System Adapt End
}
@@ -158,7 +155,7 @@ public sealed class LockSystem : EntitySystem
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success",
("entityName", Identity.Name(uid, EntityManager))), uid, user);
_audio.PlayPredicted(lockComp.LockSound, uid, user);
_audio.PlayPvs(lockComp.LockSound, uid);
lockComp.Locked = true;
_appearanceSystem.SetData(uid, LockVisuals.Locked, true);
@@ -189,7 +186,7 @@ public sealed class LockSystem : EntitySystem
("entityName", Identity.Name(uid, EntityManager))), uid, user.Value);
}
_audio.PlayPredicted(lockComp.UnlockSound, uid, user);
_audio.PlayPvs(lockComp.UnlockSound, uid);
lockComp.Locked = false;
_appearanceSystem.SetData(uid, LockVisuals.Locked, false);
@@ -259,7 +256,12 @@ public sealed class LockSystem : EntitySystem
var ev = new LockToggleAttemptEvent(user, quiet);
RaiseLocalEvent(uid, ref ev, true);
return !ev.Cancelled;
if (ev.Cancelled)
return false;
var userEv = new UserLockToggleAttemptEvent(uid, quiet);
RaiseLocalEvent(user, ref userEv, true);
return !userEv.Cancelled;
}
// TODO: this should be a helper on AccessReaderSystem since so many systems copy paste it
@@ -304,7 +306,7 @@ public sealed class LockSystem : EntitySystem
if (!component.Locked || !component.BreakOnEmag)
return;
_audio.PlayPredicted(component.UnlockSound, uid, args.UserUid);
_audio.PlayPvs(component.UnlockSound, uid);
component.Locked = false;
_appearanceSystem.SetData(uid, LockVisuals.Locked, false);
@@ -408,4 +410,3 @@ public sealed class LockSystem : EntitySystem
_activatableUI.CloseAll(uid);
}
}

View File

@@ -0,0 +1,18 @@
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;
namespace Content.Shared.Lock;
/// <summary>
/// Adds whitelist and blacklist for this mob to lock things.
/// The whitelist and blacklist are checked against the object being locked, not the mob.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(LockingWhitelistSystem))]
public sealed partial class LockingWhitelistComponent : Component
{
[DataField]
public EntityWhitelist? Whitelist;
[DataField]
public EntityWhitelist? Blacklist;
}

View File

@@ -0,0 +1,28 @@
using Content.Shared.Popups;
using Content.Shared.Whitelist;
namespace Content.Shared.Lock;
public sealed class LockingWhitelistSystem : EntitySystem
{
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LockingWhitelistComponent, UserLockToggleAttemptEvent>(OnUserLockToggleAttempt);
}
private void OnUserLockToggleAttempt(Entity<LockingWhitelistComponent> ent, ref UserLockToggleAttemptEvent args)
{
if (_whitelistSystem.CheckBoth(args.Target, ent.Comp.Blacklist, ent.Comp.Whitelist))
return;
if (!args.Silent)
_popupSystem.PopupClient(Loc.GetString("locking-whitelist-component-lock-toggle-deny"), ent.Owner);
args.Cancelled = true;
}
}

View File

@@ -1,4 +1,5 @@
using Content.Shared.Whitelist;
using Content.Shared._CP14.ItemPlacerParenting;
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;
namespace Content.Shared.Placeable;
@@ -7,7 +8,7 @@ namespace Content.Shared.Placeable;
/// Detects items placed on it that match a whitelist.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(ItemPlacerSystem))]
[Access(typeof(ItemPlacerSystem), typeof(CP14ItemPlacerAutoParentSystem))]
public sealed partial class ItemPlacerComponent : Component
{
/// <summary>

View File

@@ -1,7 +1,9 @@
namespace Content.Shared.Slippery
using Robust.Shared.GameStates;
namespace Content.Shared.Slippery;
[RegisterComponent, NetworkedComponent]
public sealed partial class NoSlipComponent : Component
{
[RegisterComponent]
public sealed partial class NoSlipComponent : Component
{
}
}

View File

@@ -45,7 +45,7 @@ public sealed class SwapTeleporterSystem : EntitySystem
private void OnInteract(Entity<SwapTeleporterComponent> ent, ref AfterInteractEvent args)
{
var (uid, comp) = ent;
if (args.Target == null)
if (args.Target == null || !args.CanReach)
return;
var target = args.Target.Value;

View File

@@ -15,4 +15,7 @@ public sealed partial class GunRequiresWieldComponent : Component
[DataField, AutoNetworkedField]
public TimeSpan PopupCooldown = TimeSpan.FromSeconds(1);
[DataField]
public LocId? WieldRequiresExamineMessage = "gunrequireswield-component-examine";
}

View File

@@ -23,6 +23,23 @@ public sealed class EntityWhitelistSystem : EntitySystem
return uid != null && IsValid(list, uid.Value);
}
/// <summary>
/// Checks whether a given entity is allowed by a whitelist and not blocked by a blacklist.
/// If a blacklist is provided and it matches then this returns false.
/// If a whitelist is provided and it does not match then this returns false.
/// If either list is null it does not get checked.
/// </summary>
public bool CheckBoth([NotNullWhen(true)] EntityUid? uid, EntityWhitelist? blacklist = null, EntityWhitelist? whitelist = null)
{
if (uid == null)
return false;
if (blacklist != null && IsValid(blacklist, uid))
return false;
return whitelist == null || IsValid(whitelist, uid);
}
/// <summary>
/// Checks whether a given entity satisfies a whitelist.
/// </summary>

View File

@@ -47,6 +47,7 @@ public sealed class WieldableSystem : EntitySystem
SubscribeLocalEvent<WieldableComponent, HandDeselectedEvent>(OnDeselectWieldable);
SubscribeLocalEvent<MeleeRequiresWieldComponent, AttemptMeleeEvent>(OnMeleeAttempt);
SubscribeLocalEvent<GunRequiresWieldComponent, ExaminedEvent>(OnExamineRequires);
SubscribeLocalEvent<GunRequiresWieldComponent, ShotAttemptedEvent>(OnShootAttempt);
SubscribeLocalEvent<GunWieldBonusComponent, ItemWieldedEvent>(OnGunWielded);
SubscribeLocalEvent<GunWieldBonusComponent, ItemUnwieldedEvent>(OnGunUnwielded);
@@ -116,8 +117,17 @@ public sealed class WieldableSystem : EntitySystem
}
}
private void OnExamineRequires(Entity<GunRequiresWieldComponent> entity, ref ExaminedEvent args)
{
if(entity.Comp.WieldRequiresExamineMessage != null)
args.PushText(Loc.GetString(entity.Comp.WieldRequiresExamineMessage));
}
private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args)
{
if (HasComp<GunRequiresWieldComponent>(uid))
return;
if (component.WieldBonusExamineMessage != null)
args.PushText(Loc.GetString(component.WieldBonusExamineMessage));
}

View File

@@ -0,0 +1,18 @@
namespace Content.Shared._CP14.Currency;
/// <summary>
/// Reflects the market value of an item, to guide players through the economy.
/// </summary>
[RegisterComponent, Access(typeof(CP14CurrencySystem))]
public sealed partial class CP14CurrencyComponent : Component
{
[DataField]
public int Currency = 1;
/// <summary>
/// allows you to categorize different valuable items in order to, for example, give goals for buying weapons, or earning money specifically.
/// </summary>
[DataField]
public string? Category;
}

View File

@@ -0,0 +1,62 @@
using Content.Shared.Examine;
using Content.Shared.Stacks;
namespace Content.Shared._CP14.Currency;
public sealed partial class CP14CurrencySystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14CurrencyComponent, ExaminedEvent>(OnExamine);
}
private void OnExamine(Entity<CP14CurrencyComponent> currency, ref ExaminedEvent args)
{
var total = GetTotalCurrency(currency, currency.Comp);
var push = Loc.GetString("cp14-currency-examine-title");
push += GetPrettyCurrency(total);
args.PushMarkup(push);
}
public string GetPrettyCurrency(int currency)
{
var total = currency;
if (total <= 0)
return string.Empty;
var gp = total / 100;
total %= 100;
var sp = total / 10;
total %= 10;
var cp = total;
var push = string.Empty;
if (gp > 0) push += " " + Loc.GetString("cp14-currency-examine-gp", ("coin", gp));
if (sp > 0) push += " " + Loc.GetString("cp14-currency-examine-sp", ("coin", sp));
if (cp > 0) push += " " + Loc.GetString("cp14-currency-examine-cp", ("coin", cp));
return push;
}
public int GetTotalCurrency(EntityUid uid, CP14CurrencyComponent? currency = null)
{
if (!Resolve(uid, ref currency))
return 0;
var total = currency.Currency;
if (TryComp<StackComponent>(uid, out var stack))
{
total *= stack.Count;
}
return total;
}
}

View File

@@ -0,0 +1,9 @@
namespace Content.Shared._CP14.ItemPlacerParenting;
/// <summary>
///
/// </summary>
[RegisterComponent, Access(typeof(CP14ItemPlacerAutoParentSystem))]
public sealed partial class CP14ItemPlacerAutoParentComponent : Component
{
}

View File

@@ -0,0 +1,65 @@
using Content.Shared.Movement.Pulling.Events;
using Content.Shared.Placeable;
using Content.Shared.Tag;
using Content.Shared.Throwing;
using Robust.Shared.Physics.Events;
namespace Content.Shared._CP14.ItemPlacerParenting;
/// <summary>
///
/// </summary>
public sealed class CP14ItemPlacerAutoParentSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14ItemPlacerAutoParentComponent, ItemPlacedEvent>(OnItemPlaced);
SubscribeLocalEvent<CP14ItemPlacerAutoParentComponent, ThrownEvent>(OnThrown);
SubscribeLocalEvent<CP14ItemPlacerAutoParentComponent, EndCollideEvent>(OnEndCollide);
}
private void OnEndCollide(Entity<CP14ItemPlacerAutoParentComponent> ent, ref EndCollideEvent args)
{
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
Detach(args.OtherEntity, ent);
}
private void Detach(EntityUid item, EntityUid parent)
{
if (Transform(item).ParentUid == parent)
_transform.SetParent(item, Transform(parent).ParentUid);
}
private void OnThrown(Entity<CP14ItemPlacerAutoParentComponent> ent, ref ThrownEvent args)
{
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
foreach (var placed in itemPlacer.PlacedEntities)
{
Detach(placed, ent);
}
}
private void OnItemPlaced(Entity<CP14ItemPlacerAutoParentComponent> ent, ref ItemPlacedEvent args)
{
if (HasComp<CP14ItemPlacerParentedComponent>(ent))
return;
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
_transform.SetParent(args.OtherEntity, ent);
AddComp<CP14ItemPlacerParentedComponent>(ent);
}
private void Detach(EntityUid target)
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Content.Shared._CP14.ItemPlacerParenting;
/// <summary>
///
/// </summary>
[RegisterComponent, Access(typeof(CP14ItemPlacerAutoParentSystem))]
public sealed partial class CP14ItemPlacerParentedComponent : Component
{
}

View File

@@ -28,7 +28,6 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
private const int DepthComplexity = 2; //TODO - fix this constant duplication from KeyholeGenerationSystem.cs
public override void Initialize()
{
base.Initialize();
@@ -54,7 +53,6 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
if (!TryComp<StorageComponent>(keyring, out var storageComp))
return;
if (TryComp<LockComponent>(args.Target, out var lockComp) &&
TryGetLockFromSlot(args.Target.Value, out var lockEnt))
{
@@ -71,7 +69,7 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
args.Handled = true;
return;
}
_popup.PopupEntity(Loc.GetString("cp-lock-keyring-use-nofit"), args.Target.Value, args.User);
_popup.PopupEntity(Loc.GetString("cp14-lock-keyring-use-nofit"), args.Target.Value, args.User);
}
}
@@ -117,10 +115,11 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
{
TryHackDoorElement(user, target, lockpick, lockItemComp, lockComp, height);
},
Text = Loc.GetString("cp-lock-verb-lockpick-use-text") + $" {height}",
Message = Loc.GetString("cp-lock-verb-lockpick-use-message"),
Text = Loc.GetString("cp14-lock-verb-lockpick-use-text") + $" {height}",
Message = Loc.GetString("cp14-lock-verb-lockpick-use-message"),
Category = VerbCategory.Lockpick,
Priority = height,
CloseMenu = false,
};
args.Verbs.Add(verb);
@@ -141,19 +140,19 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
if (lockComp.Locked)
{
_lock.TryUnlock(target, user, lockComp);
_popup.PopupEntity(Loc.GetString("cp-lock-unlock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-unlock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
lockEnt.LockpickStatus = 0;
return true;
}
else
{
_lock.TryLock(target, user, lockComp);
_popup.PopupEntity(Loc.GetString("cp-lock-lock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-lock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
lockEnt.LockpickStatus = 0;
return true;
}
}
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-success"), target, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-success"), target, user);
return true;
}
else //Fail
@@ -164,16 +163,16 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
lockpick.Comp.Health--;
if (lockpick.Comp.Health > 0)
{
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed-damage", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-failed-damage", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
} else
{
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed-break", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-failed-break", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
QueueDel(lockpick);
}
}
else
{
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-failed", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
}
lockEnt.LockpickeddFailMarkup = true;
lockEnt.LockpickStatus = 0;
@@ -205,8 +204,8 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
TryUseKeyOnLock(user, target, key, new Entity<CP14LockComponent>(target, lockItemComp));
},
IconEntity = GetNetEntity(key),
Text = Loc.GetString(lockComp.Locked ? "cp-lock-verb-use-key-text-open" : "cp-lock-verb-use-key-text-close", ("item", MetaData(args.Target).EntityName)),
Message = Loc.GetString("cp-lock-verb-use-key-message", ("item", MetaData(args.Target).EntityName))
Text = Loc.GetString(lockComp.Locked ? "cp14-lock-verb-use-key-text-open" : "cp14-lock-verb-use-key-text-close", ("item", MetaData(args.Target).EntityName)),
Message = Loc.GetString("cp14-lock-verb-use-key-message", ("item", MetaData(args.Target).EntityName)),
};
args.Verbs.Add(verb);
@@ -220,14 +219,10 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
if (args.Container.ID != lockSlot.Comp.LockSlotId)
return;
if (!TryComp<CP14LockComponent>(args.EntityUid, out var lockComp))
{
args.Cancel();
if (TryComp<CP14LockComponent>(args.EntityUid, out var lockComp))
return;
}
if (lockComp == null)
return;
args.Cancel();
//if (lockComp.Locked)
//{
@@ -309,18 +304,18 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
if (lockComp.Locked)
{
if(_lock.TryUnlock(target, user))
_popup.PopupEntity(Loc.GetString("cp-lock-unlock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-unlock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
}
else
{
if (_lock.TryLock(target, user))
_popup.PopupEntity(Loc.GetString("cp-lock-lock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-lock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
}
return true;
}
else
{
_popup.PopupEntity(Loc.GetString("cp-lock-key-use-nofit"), lockEnt, user);
_popup.PopupEntity(Loc.GetString("cp14-lock-key-use-nofit"), lockEnt, user);
}
return false;
}

View File

@@ -0,0 +1,16 @@
namespace Content.Shared._CP14.MagicAttuning;
/// <summary>
/// Reflects the fact that this subject can be focused on (Magical attune as a mechanic from DnD.)
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicAttuningSystem))]
public sealed partial class CP14MagicAttuningItemComponent : Component
{
/// <summary>
/// how long it takes to focus on that object
/// </summary>
[DataField]
public TimeSpan FocusTime = TimeSpan.FromSeconds(5f);
public Entity<CP14MagicAttuningMindComponent>? Link = null;
}

View File

@@ -0,0 +1,22 @@
namespace Content.Shared._CP14.MagicAttuning;
/// <summary>
/// A mind that can focus on objects
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicAttuningSystem))]
public sealed partial class CP14MagicAttuningMindComponent : Component
{
[DataField]
public int MaxAttuning = 3;
/// <summary>
/// The entities that this being is focused on
/// </summary>
[DataField]
public List<EntityUid> AttunedTo = new();
/// <summary>
/// cheat: if added to an entity with MindContainer, automatically copied to the mind, removing it from the body. This is to make it easy to add the component to prototype creatures.
/// </summary>
[DataField]
public bool AutoCopyToMind = false;
}

View File

@@ -0,0 +1,238 @@
using Content.Shared.DoAfter;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.MagicAttuning;
/// <summary>
/// This system controls the customization to magic items by the players.
/// </summary>
public sealed partial class CP14SharedMagicAttuningSystem : EntitySystem
{
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14MagicAttuningItemComponent, GetVerbsEvent<InteractionVerb>>(OnInteractionVerb);
SubscribeLocalEvent<CP14MagicAttuningMindComponent, CP14MagicAttuneDoAfterEvent>(OnAttuneDoAfter);
SubscribeLocalEvent<CP14MagicAttuningMindComponent, MindAddedMessage>(OnMindAdded);
}
private void OnMindAdded(Entity<CP14MagicAttuningMindComponent> ent, ref MindAddedMessage args)
{
if (!ent.Comp.AutoCopyToMind)
return;
if (HasComp<MindComponent>(ent))
return;
if (!_mind.TryGetMind(ent, out var mindId, out var mind))
return;
if (!HasComp<CP14MagicAttuningMindComponent>(mindId))
{
var attuneMind = AddComp<CP14MagicAttuningMindComponent>(mindId);
attuneMind.MaxAttuning = ent.Comp.MaxAttuning;
}
}
public bool IsAttunedTo(EntityUid mind, EntityUid item)
{
if (!TryComp<CP14MagicAttuningItemComponent>(item, out var attuningItem))
return false;
if (!TryComp<CP14MagicAttuningMindComponent>(mind, out var attuningMind))
return false;
return attuningMind.AttunedTo.Contains(item);
}
private void OnInteractionVerb(Entity<CP14MagicAttuningItemComponent> attuningItem, ref GetVerbsEvent<InteractionVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
if (!_mind.TryGetMind(args.User, out var mindId, out var mind))
return;
if (!TryComp<CP14MagicAttuningMindComponent>(mindId, out var attumingMind))
return;
var user = args.User;
if (attumingMind.AttunedTo.Contains(args.Target))
{
args.Verbs.Add(new()
{
Act = () =>
{
RemoveAttune((mindId, attumingMind), attuningItem);
},
Text = Loc.GetString("cp14-magic-deattuning-verb-text"),
Message = Loc.GetString("cp14-magic-attuning-verb-message"),
});
}
else
{
args.Verbs.Add(new()
{
Act = () =>
{
TryStartAttune(user, attuningItem);
},
Text = Loc.GetString("cp14-magic-attuning-verb-text"),
Message = Loc.GetString("cp14-magic-attuning-verb-message"),
});
}
}
public bool TryStartAttune(EntityUid user, Entity<CP14MagicAttuningItemComponent> item)
{
if (!_mind.TryGetMind(user, out var mindId, out var mind))
return false;
if (!TryComp<CP14MagicAttuningMindComponent>(mindId, out var attuningMind))
return false;
if (attuningMind.MaxAttuning <= 0)
return false;
//if there's an overabundance of ties, we report that the oldest one is torn.
if (attuningMind.AttunedTo.Count >= attuningMind.MaxAttuning)
{
var oldestAttune = attuningMind.AttunedTo[0];
_popup.PopupEntity(Loc.GetString("cp14-magic-attune-oldest-forgot", ("item", MetaData(oldestAttune).EntityName)), user, user);
}
//we notify the current owner of the item that someone is cutting ties.
if (item.Comp.Link is not null &&
item.Comp.Link.Value.Owner != mindId &&
TryComp<MindComponent>(item.Comp.Link.Value.Owner, out var ownerMind) &&
ownerMind.OwnedEntity is not null)
{
_popup.PopupEntity(Loc.GetString("cp14-magic-attune-oldest-forgot", ("item", MetaData(item).EntityName)), ownerMind.OwnedEntity.Value, ownerMind.OwnedEntity.Value);
}
var doAfterArgs = new DoAfterArgs(EntityManager,
user,
item.Comp.FocusTime,
new CP14MagicAttuneDoAfterEvent(),
mindId,
item)
{
BreakOnDamage = true,
BreakOnMove = true,
DistanceThreshold = 2f,
BlockDuplicate = true,
};
_doAfter.TryStartDoAfter(doAfterArgs);
return true;
}
private void OnAttuneDoAfter(Entity<CP14MagicAttuningMindComponent> ent, ref CP14MagicAttuneDoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Target is null)
return;
if (ent.Comp.AttunedTo.Count >= ent.Comp.MaxAttuning)
{
var oldestAttune = ent.Comp.AttunedTo[0];
RemoveAttune(ent, oldestAttune);
}
AddAttune(ent, args.Target.Value);
}
private void RemoveAttune(Entity<CP14MagicAttuningMindComponent> attuningMind, EntityUid item)
{
if (!attuningMind.Comp.AttunedTo.Contains(item))
return;
attuningMind.Comp.AttunedTo.Remove(item);
if (!TryComp<CP14MagicAttuningItemComponent>(item, out var attuningItem))
return;
if (!TryComp<MindComponent>(attuningMind, out var mind))
return;
attuningItem.Link = null;
var ev = new RemovedAttuneFromMindEvent(attuningMind, mind.OwnedEntity, item);
RaiseLocalEvent(attuningMind, ev);
RaiseLocalEvent(item, ev);
if (mind.OwnedEntity is not null)
{
_popup.PopupEntity(Loc.GetString("cp14-magic-attune-oldest-forgot-end", ("item", MetaData(item).EntityName)), mind.OwnedEntity.Value, mind.OwnedEntity.Value);
}
}
private void AddAttune(Entity<CP14MagicAttuningMindComponent> attuningMind, EntityUid item)
{
if (attuningMind.Comp.AttunedTo.Contains(item))
return;
if (!TryComp<CP14MagicAttuningItemComponent>(item, out var attuningItem))
return;
if (!TryComp<MindComponent>(attuningMind, out var mind))
return;
if (attuningItem.Link is not null)
RemoveAttune(attuningItem.Link.Value, item);
attuningMind.Comp.AttunedTo.Add(item);
attuningItem.Link = attuningMind;
var ev = new AddedAttuneToMindEvent(attuningMind, mind.OwnedEntity, item);
RaiseLocalEvent(attuningMind, ev);
RaiseLocalEvent(item, ev);
}
}
[Serializable, NetSerializable]
public sealed partial class CP14MagicAttuneDoAfterEvent : SimpleDoAfterEvent
{
}
/// <summary>
/// is evoked on both the item and the mind when a new connection between them appears.
/// </summary>
public sealed class AddedAttuneToMindEvent : EntityEventArgs
{
public readonly EntityUid Mind;
public readonly EntityUid? User;
public readonly EntityUid Item;
public AddedAttuneToMindEvent(EntityUid mind, EntityUid? user, EntityUid item)
{
Mind = mind;
User = user;
Item = item;
}
}
/// <summary>
/// is evoked on both the item and the mind when the connection is broken
/// </summary>
public sealed class RemovedAttuneFromMindEvent : EntityEventArgs
{
public readonly EntityUid Mind;
public readonly EntityUid? User;
public readonly EntityUid Item;
public RemovedAttuneFromMindEvent(EntityUid mind, EntityUid? user, EntityUid item)
{
Mind = mind;
User = user;
Item = item;
}
}

View File

@@ -1,4 +1,6 @@
using Content.Shared.Alert;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.MagicEnergy.Components;
@@ -13,4 +15,7 @@ public sealed partial class CP14MagicEnergyContainerComponent : Component
[DataField]
public FixedPoint2 MaxEnergy = 100f;
[DataField]
public ProtoId<AlertPrototype>? MagicAlert = null;
}

View File

@@ -1,16 +0,0 @@
using Content.Shared.Inventory;
namespace Content.Shared._CP14.MagicEnergy.Components;
/// <summary>
/// Controls the strength of the PointLight component, depending on the amount of mana in the object
/// </summary>
[RegisterComponent, Access(typeof(SharedCP14MagicEnergySystem))]
public sealed partial class CP14MagicEnergyPointLightControllerComponent : Component
{
[DataField]
public float MaxEnergy = 1f;
[DataField]
public float MinEnergy = 0f;
}

View File

@@ -1,15 +1,37 @@
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared.Examine;
using Content.Shared.Alert;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Content.Shared.Rounding;
namespace Content.Shared._CP14.MagicEnergy;
public partial class SharedCP14MagicEnergySystem : EntitySystem
{
[Dependency] private readonly AlertsSystem _alerts = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14MagicEnergyContainerComponent, ComponentStartup>(OnComponentStartup);
SubscribeLocalEvent<CP14MagicEnergyContainerComponent, ComponentShutdown>(OnComponentShutdown);
}
private void OnComponentStartup(Entity<CP14MagicEnergyContainerComponent> ent, ref ComponentStartup args)
{
UpdateMagicAlert(ent);
}
private void OnComponentShutdown(Entity<CP14MagicEnergyContainerComponent> ent, ref ComponentShutdown args)
{
if (ent.Comp.MagicAlert == null)
return;
_alerts.ClearAlert(ent, ent.Comp.MagicAlert.Value);
}
public string GetEnergyExaminedText(EntityUid uid, CP14MagicEnergyContainerComponent ent)
{
var power = (int)((ent.Energy / ent.MaxEnergy) * 100);
var power = (int)(ent.Energy / ent.MaxEnergy * 100);
var color = "#3fc488";
if (power < 66)
@@ -22,6 +44,92 @@ public partial class SharedCP14MagicEnergySystem : EntitySystem
("power", power),
("color", color));
}
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
{
if (!safe)
{
//Overload
if (component.Energy + energy > component.MaxEnergy)
{
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
{
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
});
}
//Burn out
if (component.Energy + energy < 0)
{
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
{
BurnOutEnergy = -energy - component.Energy
});
}
}
var oldEnergy = component.Energy;
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
component.Energy = newEnergy;
if (oldEnergy != newEnergy)
{
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
{
OldValue = component.Energy,
NewValue = newEnergy,
MaxValue = component.MaxEnergy,
});
}
UpdateMagicAlert((uid, component));
}
public bool HasEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
{
if (!Resolve(uid, ref component))
return false;
if (safe == false)
return true;
return component.Energy > energy;
}
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
{
if (!Resolve(uid, ref component))
return false;
if (energy <= 0)
return true;
// Attempting to absorb more energy than is contained in the container available only in non-safe methods (with container destruction)
if (component.Energy < energy)
{
if (safe)
{
return false;
}
else
{
ChangeEnergy(uid, component, -energy, safe);
return true;
}
}
ChangeEnergy(uid, component, -energy, safe);
return true;
}
private void UpdateMagicAlert(Entity<CP14MagicEnergyContainerComponent> ent)
{
if (ent.Comp.MagicAlert == null)
return;
var level = ContentHelpers.RoundToLevels(MathF.Max(0f, (float) ent.Comp.Energy), (float) ent.Comp.MaxEnergy, 10);
_alerts.ShowAlert(ent, ent.Comp.MagicAlert.Value, (short)level);
}
}
/// <summary>

View File

@@ -0,0 +1,317 @@
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared._CP14.MagicSpell.Spells;
using Content.Shared.DoAfter;
using Content.Shared.Hands.Components;
using Content.Shared.Popups;
using Content.Shared.Speech.Muting;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
namespace Content.Shared._CP14.MagicSpell;
/// <summary>
/// This system handles the basic mechanics of spell use, such as doAfter, event invocation, and energy spending.
/// </summary>
public partial class CP14SharedMagicSystem : EntitySystem
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly SharedGunSystem _gunSystem = default!;
[Dependency] private readonly SharedCP14MagicEnergySystem _magicEnergy = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14MagicEffectComponent, CP14BeforeCastMagicEffectEvent>(OnBeforeCastMagicEffect);
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
SubscribeLocalEvent<CP14DelayedEntityTargetActionEvent>(OnEntityTargetAction);
SubscribeLocalEvent<CP14DelayedWorldTargetActionEvent>(OnWorldTargetAction);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedInstantActionDoAfterEvent>(OnDelayedInstantActionDoAfter);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityTargetActionDoAfterEvent>(OnDelayedEntityTargetDoAfter);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedWorldTargetActionDoAfterEvent>(OnDelayedWorldTargetDoAfter);
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, CP14BeforeCastMagicEffectEvent>(OnSomaticAspectBeforeCast);
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14BeforeCastMagicEffectEvent>(OnVerbalAspectBeforeCast);
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14AfterCastMagicEffectEvent>(OnVerbalAspectAfterCast);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14AfterCastMagicEffectEvent>(OnAfterCastMagicEffect);
}
private void OnBeforeCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var magicContainer))
{
args.Cancel();
return;
}
if (!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, ent.Comp.Safe))
{
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana"));
args.Cancel();
}
else if(!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, true) && _net.IsServer)
{
_popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution);
}
}
private void OnInstantAction(CP14DelayedInstantActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!TryCastSpell(args.Action, args.Performer))
return;
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedInstantActionDoAfterEvent(), args.Action)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
Hidden = delayedEffect.Hidden,
BlockDuplicate = true,
DistanceThreshold = 100f,
};
_doAfter.TryStartDoAfter(doAfterEventArgs);
//Telegraphy effects
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
{
foreach (var effect in magicEffect.TelegraphyEffects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Performer, Transform(args.Performer).Coordinates));
}
}
}
private void OnWorldTargetAction(CP14DelayedWorldTargetActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!TryCastSpell(args.Action, args.Performer))
return;
var doAfter = new CP14DelayedWorldTargetActionDoAfterEvent()
{
Target = EntityManager.GetNetCoordinates(args.Target)
};
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, doAfter, args.Action)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
Hidden = delayedEffect.Hidden,
BlockDuplicate = true,
DistanceThreshold = 100f,
};
_doAfter.TryStartDoAfter(doAfterEventArgs);
//Telegraphy effects
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
{
foreach (var effect in magicEffect.TelegraphyEffects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, null, args.Target));
}
}
}
private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!TryCastSpell(args.Action, args.Performer))
return;
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedEntityTargetActionDoAfterEvent(), args.Action, args.Target)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
Hidden = delayedEffect.Hidden,
BlockDuplicate = true,
DistanceThreshold = 100f,
};
_doAfter.TryStartDoAfter(doAfterEventArgs);
//Telegraphy effects
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
{
foreach (var effect in magicEffect.TelegraphyEffects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Target, null));
}
}
}
private void OnDelayedWorldTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedWorldTargetActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent();
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || !_net.IsServer)
return;
foreach (var effect in ent.Comp.Effects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, null, GetCoordinates(args.Target)));
}
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
RaiseLocalEvent(ent, ref ev);
}
private void OnDelayedEntityTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedEntityTargetActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent();
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || !_net.IsServer)
return;
foreach (var effect in ent.Comp.Effects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, args.Target, null));
}
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
RaiseLocalEvent(ent, ref ev);
}
private void OnDelayedInstantActionDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedInstantActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent();
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || !_net.IsServer)
return;
foreach (var effect in ent.Comp.Effects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, args.User, Transform(args.User).Coordinates));
}
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
RaiseLocalEvent(ent, ref ev);
}
private void OnSomaticAspectBeforeCast(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
{
if (TryComp<HandsComponent>(args.Performer, out var hands) || hands is not null)
{
var freeHand = 0;
foreach (var hand in hands.Hands)
{
if (hand.Value.IsEmpty)
freeHand++;
}
if (freeHand >= ent.Comp.FreeHandRequired)
return;
}
args.PushReason(Loc.GetString("cp14-magic-spell-need-somatic-component"));
args.Cancel();
}
private void OnVerbalAspectBeforeCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
{
if (HasComp<MutedComponent>(args.Performer))
{
args.PushReason(Loc.GetString("cp14-magic-spell-need-verbal-component"));
args.Cancel();
}
else
{
if (!args.Cancelled)
{
var ev = new CP14VerbalAspectSpeechEvent
{
Performer = args.Performer,
Speech = ent.Comp.StartSpeech,
};
RaiseLocalEvent(ent, ref ev);
}
}
}
private void OnVerbalAspectAfterCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
{
if (_net.IsClient)
return;
var ev = new CP14VerbalAspectSpeechEvent
{
Performer = args.Performer,
Speech = ent.Comp.EndSpeech,
};
RaiseLocalEvent(ent, ref ev);
}
private bool TryCastSpell(EntityUid spell, EntityUid performer)
{
var ev = new CP14BeforeCastMagicEffectEvent
{
Performer = performer,
};
RaiseLocalEvent(spell, ref ev);
if (ev.Reason != string.Empty && _net.IsServer)
{
_popup.PopupEntity(ev.Reason, performer, performer);
}
if (!ev.Cancelled)
{
var evStart = new CP14StartCastMagicEffectEvent()
{
Performer = performer,
};
RaiseLocalEvent(spell, ref evStart);
}
return !ev.Cancelled;
}
private void OnAfterCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
{
if (_net.IsClient)
return;
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Performer))
return;
_magicEnergy.TryConsumeEnergy(args.Performer.Value, ent.Comp.ManaCost, safe: ent.Comp.Safe);
}
}

View File

@@ -0,0 +1,16 @@
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.MagicSpell.Components;
/// <summary>
/// Creates a temporary entity that exists while the spell is cast, and disappears at the end. For visual special effects.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
public sealed partial class CP14MagicEffectCastingVisualComponent : Component
{
[DataField]
public EntityUid? SpawnedEntity;
[DataField(required: true)]
public EntProtoId Proto = default!;
}

View File

@@ -0,0 +1,26 @@
using Content.Shared._CP14.MagicSpell.Spells;
using Content.Shared.FixedPoint;
namespace Content.Shared._CP14.MagicSpell.Components;
/// <summary>
/// Restricts the use of this action, by spending mana or user requirements.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
public sealed partial class CP14MagicEffectComponent : Component
{
[DataField]
public FixedPoint2 ManaCost = 0f;
[DataField]
public bool Safe = false;
/// <summary>
/// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds.
/// </summary>
[DataField]
public List<CP14SpellEffect> TelegraphyEffects = new();
[DataField]
public List<CP14SpellEffect> Effects = new();
}

View File

@@ -0,0 +1,11 @@
namespace Content.Shared._CP14.MagicSpell.Components;
/// <summary>
/// Requires the user to have at least one free hand to use this spell
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
public sealed partial class CP14MagicEffectSomaticAspectComponent : Component
{
[DataField]
public int FreeHandRequired = 1;
}

View File

@@ -0,0 +1,25 @@
namespace Content.Shared._CP14.MagicSpell.Components;
/// <summary>
/// Requires the user to be able to speak in order to use this spell. Also forces the user to use certain phrases at the beginning and end of a spell cast
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
public sealed partial class CP14MagicEffectVerbalAspectComponent : Component
{
[DataField]
public string StartSpeech = string.Empty;
[DataField]
public string EndSpeech = string.Empty;
}
/// <summary>
/// patch to send an event to the server for saying a phrase out loud
/// </summary>
[ByRefEvent]
public sealed class CP14VerbalAspectSpeechEvent : EntityEventArgs
{
public EntityUid? Performer { get; init; }
public string? Speech { get; init; }
}

View File

@@ -0,0 +1,41 @@
namespace Content.Shared._CP14.MagicSpell.Events;
[ByRefEvent]
public sealed class CP14BeforeCastMagicEffectEvent : CancellableEntityEventArgs
{
/// <summary>
/// The Performer of the event, to check if they meet the requirements.
/// </summary>
public EntityUid Performer { get; init; }
public string Reason = string.Empty;
public void PushReason(string reason)
{
Reason += $"{reason}\n";
}
}
[ByRefEvent]
public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
{
public EntityUid? Performer { get; init; }
}
/// <summary>
/// is invoked if all conditions are met and the spell has begun to be cast
/// </summary>
[ByRefEvent]
public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs
{
public EntityUid Performer { get; init; }
}
/// <summary>
/// is invoked on the spell itself when the spell process has been completed or interrupted
/// </summary>
[ByRefEvent]
public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs
{
}

View File

@@ -0,0 +1,73 @@
using Content.Shared.Actions;
using Content.Shared.DoAfter;
using Robust.Shared.Map;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.MagicSpell.Events;
//World target
public sealed partial class CP14DelayedWorldTargetActionEvent : WorldTargetActionEvent, ICP14DelayedMagicEffect
{
[DataField]
public float Delay { get; private set; } = 1f;
[DataField]
public bool BreakOnMove { get; private set; } = true;
[DataField]
public bool BreakOnDamage { get; private set; } = true;
[DataField]
public bool Hidden { get; private set; } = false;
}
[Serializable, NetSerializable]
public sealed partial class CP14DelayedWorldTargetActionDoAfterEvent : DoAfterEvent
{
[DataField]
public NetCoordinates Target;
public override DoAfterEvent Clone() => this;
}
//Entity Target
public sealed partial class CP14DelayedEntityTargetActionEvent : EntityTargetActionEvent, ICP14DelayedMagicEffect
{
[DataField]
public float Delay { get; private set; } = 1f;
[DataField]
public bool BreakOnMove { get; private set; } = true;
[DataField]
public bool BreakOnDamage { get; private set; } = true;
[DataField]
public bool Hidden { get; private set; } = false;
}
[Serializable, NetSerializable]
public sealed partial class CP14DelayedEntityTargetActionDoAfterEvent : SimpleDoAfterEvent
{
}
//Instant
public sealed partial class CP14DelayedInstantActionEvent : InstantActionEvent, ICP14DelayedMagicEffect
{
[DataField]
public float Delay { get; private set; } = 1f;
[DataField]
public bool BreakOnMove { get; private set; } = true;
[DataField]
public bool BreakOnDamage { get; private set; } = true;
[DataField]
public bool Hidden { get; private set; } = false;
}
[Serializable, NetSerializable]
public sealed partial class CP14DelayedInstantActionDoAfterEvent : SimpleDoAfterEvent
{
}

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