From 6a9f53ad275668914cc05288f28256421a46a47c Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 27 Sep 2023 19:42:11 -0400 Subject: [PATCH 01/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e9c08f3ad62..be19d91cb4a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: keronshb - changes: - - {message: Captains will now start with their gloves and carapace again, type: Tweak} - id: 4405 - time: '2023-08-01T21:10:36.0000000+00:00' - author: EmoGarbage404 changes: - {message: 'Fixed messages related to the round not being sent (round starting, @@ -2976,3 +2971,9 @@ Entries: - {message: What moths consider as food is now more consistent., type: Tweak} id: 4904 time: '2023-09-27T16:50:59.0000000+00:00' +- author: DrSmugleaf + changes: + - {message: Fixed getting moved briefly when closing a crematorium that you are + standing over., type: Fix} + id: 4905 + time: '2023-09-27T23:41:07.0000000+00:00' From 4e9083e7238e570cc965c2787cc1f6e73ecda880 Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Thu, 28 Sep 2023 06:05:50 +0200 Subject: [PATCH 02/98] Make NPC names proper nouns & fix some genders (#20534) * Proper names & genders * Uppercase proper names * Make Smile female --- .../Prototypes/Entities/Mobs/NPCs/pets.yml | 17 +++++++++++++++-- .../Prototypes/Entities/Mobs/NPCs/regalrat.yml | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index bb46955dcb6..e8f1f8253b0 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -97,6 +97,7 @@ task: SimpleHostileCompound - type: Grammar attributes: + proper: true gender: female - type: Tag tags: @@ -114,6 +115,7 @@ - PetsNT - type: Grammar attributes: + proper: true gender: male - type: Tag tags: @@ -153,6 +155,7 @@ components: - type: Grammar attributes: + proper: true gender: male - type: Tag tags: @@ -160,7 +163,7 @@ - VimPilot - type: entity - name: bingus + name: Bingus parent: SimpleMobBase id: MobBingus description: Bingus my beloved... @@ -212,6 +215,7 @@ path: /Audio/Animals/cat_meow.ogg - type: Grammar attributes: + proper: true gender: epicene - type: Tag tags: @@ -219,7 +223,7 @@ - VimPilot - type: entity - name: mcgriff + name: McGriff parent: SimpleMobBase id: MobMcGriff description: This dog can tell something smells around here, and that something is CRIME! @@ -431,6 +435,7 @@ path: /Audio/Animals/pig_oink.ogg - type: Grammar attributes: + proper: true gender: male - type: Tag tags: @@ -686,6 +691,10 @@ makeSentient: true name: ghost-role-information-smile-name description: ghost-role-information-smile-description + - type: Grammar + attributes: + proper: true + gender: female - type: entity name: Pun Pun @@ -715,3 +724,7 @@ - VimPilot - type: Loadout prototypes: [ MobMonkeyGear ] + - type: Grammar + attributes: + proper: true + gender: male diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index 120389304b4..69e20a51da9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -112,6 +112,9 @@ - type: GuideHelp guides: - MinorAntagonists + - type: Grammar + attributes: + gender: male - type: entity id: MobRatKingBuff From 1c422250c366503bbe08136ea30f1a1774f56cc5 Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Thu, 28 Sep 2023 06:06:13 +0200 Subject: [PATCH 03/98] fix bingus wrinkly head (#20531) --- .../Locale/en-US/interaction/interaction-popup-component.ftl | 1 + Resources/Prototypes/Entities/Mobs/NPCs/pets.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl index 67d727dc532..02cbd973647 100644 --- a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl +++ b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl @@ -5,6 +5,7 @@ petting-success-generic = You pet {THE($target)} on {POSS-ADJ($target)} head. petting-success-soft-floofy = You pet {THE($target)} on {POSS-ADJ($target)} soft floofy head. +petting-success-bingus = You pet {THE($target)} on {POSS-ADJ($target)} wrinkly little head. petting-success-bird = You pet {THE($target)} on {POSS-ADJ($target)} cute feathery head. petting-success-cat = You pet {THE($target)} on {POSS-ADJ($target)} fuzzy little head. petting-success-corrupted-corgi = In an act of hubris, you pet {THE($target)} on {POSS-ADJ($target)} cursed little head. diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index e8f1f8253b0..7846dd66fae 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -209,7 +209,7 @@ amount: 2 - type: InteractionPopup successChance: 0.9 - interactSuccessString: petting-success-cat + interactSuccessString: petting-success-bingus interactFailureString: petting-failure-generic interactSuccessSound: path: /Audio/Animals/cat_meow.ogg From 508cfda0f433c16fb522c399353a293f2831d4a1 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Thu, 28 Sep 2023 05:07:08 +0100 Subject: [PATCH 04/98] rouny meat and steak (#20526) * lost friendship flavor * add rouny steak * rouny special meat * rouny meat textures --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Locale/en-US/flavors/flavor-profiles.ftl | 1 + .../Prototypes/Entities/Mobs/NPCs/xeno.yml | 5 ++ .../Entities/Objects/Consumable/Food/meat.yml | 56 ++++++++++++++++++ Resources/Prototypes/Flavors/flavors.yml | 7 ++- .../Construction/Graphs/food/steak.yml | 13 ++++ .../Consumable/Food/meat.rsi/meta.json | 8 ++- .../Consumable/Food/meat.rsi/rouny-cooked.png | Bin 0 -> 654 bytes .../Consumable/Food/meat.rsi/rouny.png | Bin 0 -> 628 bytes 8 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 Resources/Textures/Objects/Consumable/Food/meat.rsi/rouny-cooked.png create mode 100644 Resources/Textures/Objects/Consumable/Food/meat.rsi/rouny.png diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl index 145e2aa51f0..8ecf4cb13e7 100644 --- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl @@ -148,6 +148,7 @@ flavor-complex-parents = like someone's parents flavor-complex-plastic = like plastic flavor-complex-glue = like glue flavor-complex-spaceshroom-cooked = like space umami +flavor-complex-lost-friendship = like lost friendship # Drink-specific flavors. diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index 1c81d57e69e..47ea55278fb 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -305,6 +305,11 @@ drawdepth: Mobs sprite: Mobs/Aliens/Xenos/rouny.rsi offset: 0,0.6 + - type: Butcherable + butcheringType: Spike + spawned: + - id: FoodMeatRouny + amount: 3 - type: entity name: Spitter diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 44f2b668e4d..1c003df38e6 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -494,6 +494,34 @@ count: 3 slice: FoodMeatXenoCutlet +- type: entity + name: raw rouny meat + # not raw since rouny best + parent: FoodMeatBase + id: FoodMeatRouny + description: A slab of meat from an innocent red friend. + components: + - type: FlavorProfile + flavors: + - meaty + - acid + - lostfriendship + - type: Tag + tags: + - Raw + - type: Sprite + state: rouny + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: SulfuricAcid + Quantity: 20 + - type: Construction + graph: RounySteak + node: start + defaultTarget: rouny steak + - type: entity name: killer tomato meat parent: FoodMeatBase @@ -848,6 +876,34 @@ graph: GoliathSteak node: goliath steak +- type: entity + name: rouny steak + parent: FoodMeatBase + id: FoodMeatRounyCooked + description: Some kill to survive. You on the other hand, kill for fun. + components: + - type: FlavorProfile + flavors: + - meaty + - lostfriendship + - type: Tag + tags: + - Cooked + - type: Sprite + layers: + - state: rouny-cooked + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: Nutriment + Quantity: 10 + - ReagentId: Protein + Quantity: 10 + - type: Construction + graph: RounySteak + node: rouny steak + - type: entity name: lizard steak parent: FoodMeatBase diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index 2b8e2b0e2f0..fc3b0ba5771 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -837,4 +837,9 @@ - type: flavor id: spaceshroomcooked flavorType: Complex - description: flavor-complex-spaceshroom-cooked \ No newline at end of file + description: flavor-complex-spaceshroom-cooked + +- type: flavor + id: lostfriendship + flavorType: Complex + description: flavor-complex-lost-friendship diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/food/steak.yml b/Resources/Prototypes/Recipes/Construction/Graphs/food/steak.yml index 76159ec5ac4..74854084f53 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/food/steak.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/food/steak.yml @@ -117,3 +117,16 @@ - node: goliath steak entity: FoodMeatGoliathCooked + +# rouny steak +- type: constructionGraph + id: RounySteak + start: start + graph: + - node: start + edges: + - to: rouny steak + steps: + - minTemperature: 445 #rouny + - node: rouny steak + entity: FoodMeatRounyCooked diff --git a/Resources/Textures/Objects/Consumable/Food/meat.rsi/meta.json b/Resources/Textures/Objects/Consumable/Food/meat.rsi/meta.json index 2bbe89d1f9f..f1aa4d3446d 100644 --- a/Resources/Textures/Objects/Consumable/Food/meat.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Food/meat.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation and modified by Swept and potato1234x at https://github.com/tgstation/tgstation/commit/40d75cc340c63582fb66ce15bf75a36115f6bdaa", + "copyright": "Taken from tgstation and modified by Swept, potato1234x and deltanedas at https://github.com/tgstation/tgstation/commit/40d75cc340c63582fb66ce15bf75a36115f6bdaa", "size": { "x": 32, "y": 32 @@ -188,6 +188,12 @@ }, { "name": "dragon_veins" + }, + { + "name": "rouny" + }, + { + "name": "rouny-cooked" } ] } diff --git a/Resources/Textures/Objects/Consumable/Food/meat.rsi/rouny-cooked.png b/Resources/Textures/Objects/Consumable/Food/meat.rsi/rouny-cooked.png new file mode 100644 index 0000000000000000000000000000000000000000..cba050d693c63459fe5d208383cf9cde057d2fdb GIT binary patch literal 654 zcmV;90&)F`P)$`wePiwn9j{W3BALe^W(esJDm9j?4hidGh3!1moFNTV8F8&Tk^EM z(1Dvi1{jKKralu6hiJM!@35(Q>sP&+-)p$KR+FX%wszr3O*e|dG7X{iqON#bxL3=> zSA`FSeTEDue5Le6m7f)-tNgCmh(>0?u6laXb)2YUEo0<_M}@t)Y)Si@M}3JinO~Tf z>Xto-NrWH)JR~TwMwTLesd>q)v2X0xH%CD{n!I(&7~)8i5wB0wl5|Zj z?85mL^grlvBmOHnWZP3Ics+&g81&pg=W;cxzjIFRA-W;I=o2sDyE(_@rR^vV51 z)MK90D2GZGWngfmUc%fGFf%O1trZG|yF(bKwY3kjZB7h*&hizO__;iO?63E32Di?A zeYFUgA@+nsg0+B-$j1N{!RQlJ$4f*k0Zi7KC^~~$(6eP7|DWHw$4o0I0h!*9LOfWv zpl625Bk?MLY;XoLJ!SpqJ>cD8=9;0*(ZUjDgP|;=7NN$`wePiwn9j{W3BALe^W(esJDm9j?4hidGh3!1moFNTV8F8&Tk^EM z(1Dvi1{jKKralu6hiJM!@35(Q>sP&+-)p$KR+FX%wszr3O*e|dG7X{iqON#bxL3=> zSA`FSeTEDue5Le6m7f)-tNgCmh(>0?u6laXb)2YUEo0<_M}@t)Y)Si@M}3JinO~Tf z>Xto-NrWH)JR~TwMwTLesd>q)v2X0xH%CD{n!I(&7~)8i5wB0wl5|Zj z?85mL^grlvBmOHnWZP3Ics+&g81&pg=W;cxzjIFRA-W;I=o-Jec?~632_SISp z0hZtvNDmkTEL^xGSOdu^k2chFiR^&JXas2Xo{Bq}^u^>EZ@mQx)=OATrFG&tpnZa# zaM2v_fN;adGzmR}$qdl@3os0I*-9q^G%am?O4?u(fCQ*GJwu^TXu4hmsYady#3yI~ O0000 Date: Thu, 28 Sep 2023 00:07:17 -0400 Subject: [PATCH 05/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index be19d91cb4a..0ca3c9c8407 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,19 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - {message: 'Fixed messages related to the round not being sent (round starting, - round restarting, etc.)', type: Fix} - id: 4406 - time: '2023-08-01T21:11:50.0000000+00:00' -- author: PrPleGoo - changes: - - {message: added an overlay for the security hud that displays job icons, type: Add} - - {message: Added some buttons to the Agent ID interface to set the icon on the - ID card., type: Add} - - {message: Changed the id card computer to also set the icon on the ID when picking - a job prototype from the presets., type: Tweak} - id: 4407 - time: '2023-08-01T21:17:03.0000000+00:00' - author: metalgearsloth changes: - {message: Added xeno spitters to salvage., type: Add} @@ -2977,3 +2962,14 @@ Entries: standing over., type: Fix} id: 4905 time: '2023-09-27T23:41:07.0000000+00:00' +- author: Psychpsyo + changes: + - {message: 'You can now pet Runtime instead of petting >the< Runtime. Also, Smile + is now a girl.', type: Fix} + id: 4906 + time: '2023-09-28T04:05:50.0000000+00:00' +- author: Psychpsyo + changes: + - {message: Bingus is no longer fuzzy., type: Fix} + id: 4907 + time: '2023-09-28T04:06:13.0000000+00:00' From b22fc1153056bf7efd1771956016a1e47e503018 Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Thu, 28 Sep 2023 06:09:44 +0200 Subject: [PATCH 06/98] Wearable Wet Floor Sign and 'Janitorial Suicide Vest' (#20311) * Explosive wet floor sign & janitorial suicide vest * fix attributions * Remove name & desc from explosive wet floor sign * Make wet floor sign chameleonable --- .../Components/OnUseTimerTriggerComponent.cs | 6 +++ .../EntitySystems/TriggerSystem.OnUse.cs | 37 +++++++++++++----- .../Audio/Items/Janitor/floor_sign_beep.ogg | Bin 0 -> 4950 bytes .../en-US/weapons/grenades/timer-trigger.ftl | 2 + .../Objects/Specific/Janitorial/janitor.yml | 29 ++++++++------ .../Janitorial/wet_floor_sign.rsi/caution.png | Bin 234 -> 0 bytes .../equipped-OUTERCLOTHING.png | Bin 0 -> 415 bytes .../Janitorial/wet_floor_sign.rsi/icon.png | Bin 0 -> 251 bytes .../wet_floor_sign.rsi/inhand-left.png | Bin 347 -> 329 bytes .../wet_floor_sign.rsi/inhand-right.png | Bin 366 -> 329 bytes .../Janitorial/wet_floor_sign.rsi/meta.json | 8 +++- 11 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 Resources/Audio/Items/Janitor/floor_sign_beep.ogg delete mode 100644 Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/caution.png create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/icon.png diff --git a/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs b/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs index 008bbbe284b..f2e94239a03 100644 --- a/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs +++ b/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs @@ -29,6 +29,12 @@ public sealed partial class OnUseTimerTriggerComponent : Component [DataField("beepInterval")] public float BeepInterval = 1; + /// + /// Whether the timer should instead be activated through a verb in the right-click menu + /// + [DataField("useVerbInstead")] + public bool UseVerbInstead = false; + /// /// Should timer be started when it was stuck to another entity. /// Used for C4 charges and similar behaviour. diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs index 1a3323b1ce2..fb1f72eb445 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs @@ -48,6 +48,32 @@ private void OnGetAltVerbs(EntityUid uid, OnUseTimerTriggerComponent component, if (!args.CanInteract || !args.CanAccess) return; + if (component.UseVerbInstead) + { + args.Verbs.Add(new AlternativeVerb() + { + Text = Loc.GetString("verb-start-detonation"), + Act = () => HandleTimerTrigger( + uid, + args.User, + component.Delay, + component.BeepInterval, + component.InitialBeepDelay, + component.BeepSound + ), + Priority = 2 + }); + } + + if (component.AllowToggleStartOnStick) + { + args.Verbs.Add(new AlternativeVerb() + { + Text = Loc.GetString("verb-toggle-start-on-stick"), + Act = () => ToggleStartOnStick(uid, args.User, component) + }); + } + if (component.DelayOptions == null || component.DelayOptions.Count == 1) return; @@ -86,15 +112,6 @@ private void OnGetAltVerbs(EntityUid uid, OnUseTimerTriggerComponent component, }, }); } - - if (component.AllowToggleStartOnStick) - { - args.Verbs.Add(new AlternativeVerb() - { - Text = Loc.GetString("verb-toggle-start-on-stick"), - Act = () => ToggleStartOnStick(uid, args.User, component) - }); - } } private void CycleDelay(OnUseTimerTriggerComponent component, EntityUid user) @@ -140,7 +157,7 @@ private void ToggleStartOnStick(EntityUid grenade, EntityUid user, OnUseTimerTri private void OnTimerUse(EntityUid uid, OnUseTimerTriggerComponent component, UseInHandEvent args) { - if (args.Handled || HasComp(uid)) + if (args.Handled || HasComp(uid) || component.UseVerbInstead) return; HandleTimerTrigger( diff --git a/Resources/Audio/Items/Janitor/floor_sign_beep.ogg b/Resources/Audio/Items/Janitor/floor_sign_beep.ogg new file mode 100644 index 0000000000000000000000000000000000000000..25f68be1c388dcdc9c417746f5fb2fe7a0c27beb GIT binary patch literal 4950 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 literal 0 HcmV?d00001 diff --git a/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl b/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl index 76861c8b4fe..77e2dd938d6 100644 --- a/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl +++ b/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl @@ -7,6 +7,8 @@ examine-trigger-timer = The timer is set to {$time} seconds. popup-trigger-timer-set = Timer set to {$time} seconds. +verb-start-detonation = Start detonation + verb-toggle-start-on-stick = Toggle auto-activation popup-start-on-stick-off = The device will no longer activate automatically when planted popup-start-on-stick-on = The device will now activate automatically when planted diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index 13bd6d16650..3ae89e0d1c0 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -196,33 +196,30 @@ - type: entity name: wet floor sign id: WetFloorSign - parent: BaseItem + parent: ClothingOuterBase description: Caution! Wet Floor! components: - type: Sprite sprite: Objects/Specific/Janitorial/wet_floor_sign.rsi - state: caution - type: Item sprite: Objects/Specific/Janitorial/wet_floor_sign.rsi size: 15 + - type: Armor + modifiers: + coefficients: + Blunt: 0.95 + Slash: 0.95 - type: Tag tags: - WetFloorSign + - WhitelistChameleon - type: entity - name: wet floor sign suffix: Explosive - description: Caution! Wet Floor! - parent: BaseItem + parent: WetFloorSign id: WetFloorSignMineExplosive components: - - type: Sprite - sprite: Objects/Specific/Janitorial/wet_floor_sign.rsi - state: caution - - type: Item - sprite: Objects/Specific/Janitorial/wet_floor_sign.rsi - size: 15 - type: StepTrigger intersectRatio: 0.2 requiredTriggeredSpeed: 0 @@ -254,6 +251,16 @@ totalIntensity: 60 # about a ~3 tile radius canCreateVacuum: false - type: DeleteOnTrigger + - type: OnUseTimerTrigger + useVerbInstead: true + beepInterval: .25 + beepSound: /Audio/Items/Janitor/floor_sign_beep.ogg + params: + volume: 1 + examinable: false + - type: Tag + tags: # ignore "WhitelistChameleon" tag + - WetFloorSign - type: entity name: janitorial trolley diff --git a/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/caution.png b/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/caution.png deleted file mode 100644 index fdd5c1d2cbbbe9684848a0f00a916594b857842e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 234 zcmVcrlDmg3=O0Fc9|NiHux`7X3Ce(o18_6JJ;Q^jnE9CjFVPayB|L+D39gkejeJ?AQ&3jGak44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~O1^9%xE||`6<^aQ={|sG~3_3bGKw*i@l5`-&RubeF{2v4uHt%1uA1K0E z;1OBOz`%D1gc(IOyc&QOuz0#ShD5l(oz}?LWWeKcoALku)7#dy+%9A7oguN=`%c*V z8lO!fDZc}R4H(x&GcL+noW-`(PAsZx6@TFOMRn{IuUHIz=_Uw9K4EeAGrK(C)Gc<0 zEA9+|31_AXotw~^Gg^Wl{c)C37E?CX2y;nhR@OsAxjyaF*`h( z@V;38ow9?H0Fe6pMtW8QXMyhlmL2a{BaVMn)LQh)oRMXPdCcp7ng?y)pOtv=ugUbx zn~e!Z*)MiHw%y>fhHdNhbxIAFWskhNAkOepyN}VsChhXS-6h=ZjEpQ(YWFcEJUGs< z)#JSqFT;aZe;e2fcCO#N*n`>gTdD5>d4_Fo8IQPlrSsePS_1=#!PC{xWt~$(69D$i BqW%B? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/icon.png b/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..204e8b8813f1535fdb9e1f7a1a1d380d63c606ed GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCim11AIbU7ffgP^PfRSN9W7|pb&%nA?9u%#aa^N7yKUx7=CZ#3kC{s7I;J! zGcfQS24TkI`72U@f+?OZjv*HQZ!a9=YB1nozHsx~|NW7h!aR0fs%DY&=d3Z)WEi+?^nJK#)O<=aqfMY6XM+ n$@8D{JbPf4w&BEgg-0wu#raevg-!(m?PKtC^>bP0l+XkK%VbrT literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/inhand-left.png index aa3d9fc9c14305c8351f12b5b8e2d8f169c51440..ed1e8946e7c2fee658d9809091e2fc75de989e08 100644 GIT binary patch delta 313 zcmcc3bdqU;WIZzj1H;_yjcNS%G~10G|-o z1=AV+{AbY7(K&MfD8wLth`Ad`v6ck+1^)*EhTq%xf`I~@1s;*b3=DjSL74G){)!Z! z;3iKO$B+p3x6>|i9X8-_oqX*7|7R<|)<1O9l`xZ#p2wd1?yzSDcj1NETNbc7aYrfq zS()HrvE|;K^8ySj6NJuMIv&vO<73&QDju!IIDuP4WCufqK+JUEH;f+?ZkXHHA51c9 zd1`p_b_#UaCyyG88JA_x8Ux92v*sh;Dzw))7;gH=;2 zildFz3#GHa4z(*_vbT!Ax%$oxYs2-ijK6YXGEyu`h5=k$wm=8KdeeUWnAevsF@FQr8~XFJt_f=?8L^5F z0O0=avXv~$B8H4};002ovPDHLkV1k%!lJ)=q diff --git a/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/inhand-right.png index 286dec22cd18ee027898194451cfc531f3449254..355d215fcd7cf13eddc7539386a45d99aea9d687 100644 GIT binary patch delta 313 zcmaFIbdqU;WIZzj1H;_yjcNS%G~10G|-o z1=AV+{AbY7(K&MfD8wLth`Ad`v6ck+1^)*EhTq%xf`I~@1s;*b3=DjSL74G){)!Z! z;3iKO$B+p3x6>|i9X8-_O@92pzS#6w{k09faW@l|R>D(wbPMmPyWM`sgW{zb^7ou)zUV#dl4)-kj%laQi(qeQ))`$w}am z+KXS|RyrMp!Y^j_F>O3@vEL445ZJtG&NqwN+na@1jNS=(Hwm*|V&11>k{hvotazOVpc)I$ztaD0e0s!D+ Bcsc+8 delta 350 zcmV-k0ipiM0`3Bk8Gi-<0063Kaozv`0X0cPK~#90?bh^L_Ra%DgFzX$Y%y}s#bs$ w`^-R2RRPXn$)~Cc5c$l2r}!N}-yJwhTeehXKsXChM*si-07*qoM6N<$f&+J?`2YX_ diff --git a/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/meta.json b/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/meta.json index bc202f443a9..75c381313e4 100644 --- a/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Janitorial/wet_floor_sign.rsi/meta.json @@ -1,14 +1,18 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/f8f4aeda930fcd0805ca4cc76d9bc9412a5b3428", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/da42afcbaeaa04e5ba288ade027c011efb3ef0ab, modified by Skarlet and Psychpsyo", "size": { "x": 32, "y": 32 }, "states": [ { - "name": "caution" + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 }, { "name": "inhand-left", From 245819a74c30524738e0805afd2c5fb82c077bc4 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 00:10:52 -0400 Subject: [PATCH 07/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0ca3c9c8407..f2c87d9c02a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - {message: Added xeno spitters to salvage., type: Add} - - {message: Fix dragon carps not looking like their dragon., type: Fix} - - {message: Fix dragon carp NPCs not following the dragon and not idling on spawn., - type: Fix} - - {message: Fix NPCs not shutting down properly upon player takeover., type: Fix} - id: 4408 - time: '2023-08-02T00:48:57.0000000+00:00' - author: Slava0135 changes: - {message: Hitting entities with thrown items that deal damage now provide more @@ -2973,3 +2964,10 @@ Entries: - {message: Bingus is no longer fuzzy., type: Fix} id: 4907 time: '2023-09-28T04:06:13.0000000+00:00' +- author: Psychpsyo + changes: + - {message: The wet floor sign can now be worn as an outer clothing. This now gives + syndicate janitors access to a suicide vest in form the wet floor sign mine., + type: Add} + id: 4908 + time: '2023-09-28T04:09:45.0000000+00:00' From ad40c55ad3b7056b1934a595475d5c7731becaa9 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:27:35 +1000 Subject: [PATCH 08/98] Minor slippery stuff (#20535) --- Content.Shared/Slippery/SlipperySystem.cs | 8 -------- Content.Shared/StatusEffect/StatusEffectsSystem.cs | 3 ++- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Content.Shared/Slippery/SlipperySystem.cs b/Content.Shared/Slippery/SlipperySystem.cs index 41bfe03c4c3..a89291aea49 100644 --- a/Content.Shared/Slippery/SlipperySystem.cs +++ b/Content.Shared/Slippery/SlipperySystem.cs @@ -103,14 +103,6 @@ private void TrySlip(EntityUid uid, SlipperyComponent component, EntityUid other _adminLogger.Add(LogType.Slip, LogImpact.Low, $"{ToPrettyString(other):mob} slipped on collision with {ToPrettyString(uid):entity}"); } - - public void CopyConstruct(EntityUid destUid, SlipperyComponent srcSlip) - { - var destEvaporation = EntityManager.EnsureComponent(destUid); - destEvaporation.SlipSound = srcSlip.SlipSound; - destEvaporation.ParalyzeTime = srcSlip.ParalyzeTime; - destEvaporation.LaunchForwardsMultiplier = srcSlip.LaunchForwardsMultiplier; - } } ///

diff --git a/Content.Shared/StatusEffect/StatusEffectsSystem.cs b/Content.Shared/StatusEffect/StatusEffectsSystem.cs index 70822a05f44..bedc5a824ce 100644 --- a/Content.Shared/StatusEffect/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffect/StatusEffectsSystem.cs @@ -61,7 +61,8 @@ private void OnHandleState(EntityUid uid, StatusEffectsComponent component, ref if (args.Current is not StatusEffectsComponentState state) return; - component.AllowedEffects = new(state.AllowedEffects); + component.AllowedEffects.Clear(); + component.AllowedEffects.AddRange(state.AllowedEffects); // Remove non-existent effects. foreach (var effect in component.ActiveEffects.Keys) From a7eb3a6db24b098826e553a376bf93f099bd97f5 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:29:28 +1000 Subject: [PATCH 09/98] Update submodule to 162.2.0 (#20570) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 8f6b189d293..e75c1659f6d 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 8f6b189d293dc03fc8a33d83340bb2ce66c5c233 +Subproject commit e75c1659f6dbdebfe65bb604bd33ddd7dae9fdd8 From b0253fcd7548febf55308cfdbfa519e9fb5df85b Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Thu, 28 Sep 2023 06:48:50 -0400 Subject: [PATCH 10/98] Predicted armor (#20560) --- Content.Client/Armor/ArmorSystem.cs | 9 ++ Content.Server/Armor/ArmorComponent.cs | 11 -- Content.Server/Armor/ArmorSystem.cs | 129 +++--------------- .../EntitySystems/ExplosionSystem.cs | 1 + Content.Shared/Armor/ArmorComponent.cs | 25 ++++ Content.Shared/Armor/SharedArmorSystem.cs | 78 +++++++++++ .../Entities/Objects/Vehicles/buckleable.yml | 6 +- 7 files changed, 135 insertions(+), 124 deletions(-) create mode 100644 Content.Client/Armor/ArmorSystem.cs delete mode 100644 Content.Server/Armor/ArmorComponent.cs create mode 100644 Content.Shared/Armor/ArmorComponent.cs create mode 100644 Content.Shared/Armor/SharedArmorSystem.cs diff --git a/Content.Client/Armor/ArmorSystem.cs b/Content.Client/Armor/ArmorSystem.cs new file mode 100644 index 00000000000..a4116d2f7a3 --- /dev/null +++ b/Content.Client/Armor/ArmorSystem.cs @@ -0,0 +1,9 @@ +using Content.Shared.Armor; + +namespace Content.Client.Armor; + +/// +public sealed class ArmorSystem : SharedArmorSystem +{ + +} diff --git a/Content.Server/Armor/ArmorComponent.cs b/Content.Server/Armor/ArmorComponent.cs deleted file mode 100644 index 09be3bf2401..00000000000 --- a/Content.Server/Armor/ArmorComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Shared.Damage; - -namespace Content.Server.Armor -{ - [RegisterComponent] - public sealed partial class ArmorComponent : Component - { - [DataField("modifiers", required: true)] - public DamageModifierSet Modifiers = default!; - } -} diff --git a/Content.Server/Armor/ArmorSystem.cs b/Content.Server/Armor/ArmorSystem.cs index dc02b06667e..dc4b3c7935f 100644 --- a/Content.Server/Armor/ArmorSystem.cs +++ b/Content.Server/Armor/ArmorSystem.cs @@ -1,125 +1,34 @@ -using Content.Shared.Damage; -using Content.Server.Examine; -using Content.Shared.Verbs; -using Robust.Shared.Utility; using Content.Server.Cargo.Systems; +using Content.Shared.Armor; using Robust.Shared.Prototypes; using Content.Shared.Damage.Prototypes; -using Content.Shared.Inventory; -using Content.Shared.Silicons.Borgs; -namespace Content.Server.Armor -{ - public sealed class ArmorSystem : EntitySystem - { - const double CoefDefaultPrice = 2; // default price of 1% protection against any type of damage - const double FlatDefaultPrice = 10; //default price of 1 damage protection against a certain type of damage - - [Dependency] private readonly ExamineSystem _examine = default!; - [Dependency] private readonly IPrototypeManager _protoManager = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent>(OnDamageModify); - SubscribeLocalEvent>(OnBorgDamageModify); - SubscribeLocalEvent>(OnArmorVerbExamine); - SubscribeLocalEvent(GetArmorPrice); - } - - private void GetArmorPrice(EntityUid uid, ArmorComponent component, ref PriceCalculationEvent args) - { - if (component.Modifiers == null) - return; - - double price = 0; - - foreach (var modifier in component.Modifiers.Coefficients) - { - _protoManager.TryIndex(modifier.Key, out DamageTypePrototype? damageType); - - if (damageType != null) - { - price += damageType.ArmorPriceCoefficient * 100 * (1 - modifier.Value); - } - else - { - price += CoefDefaultPrice * 100 * (1 - modifier.Value); - } - } - foreach (var modifier in component.Modifiers.FlatReduction) - { - _protoManager.TryIndex(modifier.Key, out DamageTypePrototype? damageType); +namespace Content.Server.Armor; - if (damageType != null) - { - price += damageType.ArmorPriceFlat * modifier.Value; - } - else - { - price += FlatDefaultPrice * modifier.Value; - } - } - args.Price += price; - } +/// +public sealed class ArmorSystem : SharedArmorSystem +{ + [Dependency] private readonly IPrototypeManager _protoManager = default!; - private void OnDamageModify(EntityUid uid, ArmorComponent component, InventoryRelayedEvent args) - { - args.Args.Damage = DamageSpecifier.ApplyModifierSet(args.Args.Damage, component.Modifiers); - } + public override void Initialize() + { + base.Initialize(); - private void OnBorgDamageModify(EntityUid uid, ArmorComponent component, ref BorgModuleRelayedEvent args) - { - args.Args.Damage = DamageSpecifier.ApplyModifierSet(args.Args.Damage, component.Modifiers); - } + SubscribeLocalEvent(GetArmorPrice); + } - private void OnArmorVerbExamine(EntityUid uid, ArmorComponent component, GetVerbsEvent args) + private void GetArmorPrice(EntityUid uid, ArmorComponent component, ref PriceCalculationEvent args) + { + foreach (var modifier in component.Modifiers.Coefficients) { - if (!args.CanInteract || !args.CanAccess) - return; - - var armorModifiers = component.Modifiers; - - if (armorModifiers == null) - return; - - var examineMarkup = GetArmorExamine(armorModifiers); - - var ev = new ArmorExamineEvent(examineMarkup); - RaiseLocalEvent(uid, ref ev); - - _examine.AddDetailedExamineVerb(args, component, examineMarkup, Loc.GetString("armor-examinable-verb-text"), "/Textures/Interface/VerbIcons/dot.svg.192dpi.png", Loc.GetString("armor-examinable-verb-message")); + var damageType = _protoManager.Index(modifier.Key); + args.Price += damageType.ArmorPriceCoefficient * 100 * (1 - modifier.Value); } - private FormattedMessage GetArmorExamine(DamageModifierSet armorModifiers) + foreach (var modifier in component.Modifiers.FlatReduction) { - var msg = new FormattedMessage(); - - msg.AddMarkup(Loc.GetString("armor-examine")); - - foreach (var coefficientArmor in armorModifiers.Coefficients) - { - msg.PushNewline(); - msg.AddMarkup(Loc.GetString("armor-coefficient-value", - ("type", coefficientArmor.Key), - ("value", MathF.Round((1f - coefficientArmor.Value) * 100,1)) - )); - } - - foreach (var flatArmor in armorModifiers.FlatReduction) - { - msg.PushNewline(); - msg.AddMarkup(Loc.GetString("armor-reduction-value", - ("type", flatArmor.Key), - ("value", flatArmor.Value) - )); - } - - return msg; + var damageType = _protoManager.Index(modifier.Key); + args.Price += damageType.ArmorPriceFlat * modifier.Value; } } } - -[ByRefEvent] -public record struct ArmorExamineEvent(FormattedMessage Msg); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index 06c95383fcb..aa007c61c05 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Explosion.Components; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NPC.Pathfinding; +using Content.Shared.Armor; using Content.Shared.Camera; using Content.Shared.CCVar; using Content.Shared.Damage; diff --git a/Content.Shared/Armor/ArmorComponent.cs b/Content.Shared/Armor/ArmorComponent.cs new file mode 100644 index 00000000000..a1bb75923f7 --- /dev/null +++ b/Content.Shared/Armor/ArmorComponent.cs @@ -0,0 +1,25 @@ +using Content.Shared.Damage; +using Robust.Shared.GameStates; +using Robust.Shared.Utility; + +namespace Content.Shared.Armor; + +/// +/// Used for clothing that reduces damage when worn. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedArmorSystem))] +public sealed partial class ArmorComponent : Component +{ + /// + /// The damage reduction + /// + [DataField(required: true)] + public DamageModifierSet Modifiers = default!; +} + +/// +/// Event raised on an armor entity to get additional examine text relating to its armor. +/// +/// +[ByRefEvent] +public record struct ArmorExamineEvent(FormattedMessage Msg); diff --git a/Content.Shared/Armor/SharedArmorSystem.cs b/Content.Shared/Armor/SharedArmorSystem.cs new file mode 100644 index 00000000000..89141fcbd3d --- /dev/null +++ b/Content.Shared/Armor/SharedArmorSystem.cs @@ -0,0 +1,78 @@ +using Content.Shared.Damage; +using Content.Shared.Examine; +using Content.Shared.Inventory; +using Content.Shared.Silicons.Borgs; +using Content.Shared.Verbs; +using Robust.Shared.Utility; + +namespace Content.Shared.Armor; + +/// +/// This handles logic relating to +/// +public abstract class SharedArmorSystem : EntitySystem +{ + [Dependency] private readonly ExamineSystemShared _examine = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnDamageModify); + SubscribeLocalEvent>(OnBorgDamageModify); + SubscribeLocalEvent>(OnArmorVerbExamine); + } + + private void OnDamageModify(EntityUid uid, ArmorComponent component, InventoryRelayedEvent args) + { + args.Args.Damage = DamageSpecifier.ApplyModifierSet(args.Args.Damage, component.Modifiers); + } + + private void OnBorgDamageModify(EntityUid uid, ArmorComponent component, ref BorgModuleRelayedEvent args) + { + args.Args.Damage = DamageSpecifier.ApplyModifierSet(args.Args.Damage, component.Modifiers); + } + + private void OnArmorVerbExamine(EntityUid uid, ArmorComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var examineMarkup = GetArmorExamine(component.Modifiers); + + var ev = new ArmorExamineEvent(examineMarkup); + RaiseLocalEvent(uid, ref ev); + + _examine.AddDetailedExamineVerb(args, component, examineMarkup, + Loc.GetString("armor-examinable-verb-text"), "/Textures/Interface/VerbIcons/dot.svg.192dpi.png", + Loc.GetString("armor-examinable-verb-message")); + } + + private FormattedMessage GetArmorExamine(DamageModifierSet armorModifiers) + { + var msg = new FormattedMessage(); + + msg.AddMarkup(Loc.GetString("armor-examine")); + + foreach (var coefficientArmor in armorModifiers.Coefficients) + { + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("armor-coefficient-value", + ("type", coefficientArmor.Key), + ("value", MathF.Round((1f - coefficientArmor.Value) * 100,1)) + )); + } + + foreach (var flatArmor in armorModifiers.FlatReduction) + { + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("armor-reduction-value", + ("type", flatArmor.Key), + ("value", flatArmor.Value) + )); + } + + return msg; + } +} diff --git a/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml b/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml index d807bcc5a9f..4a8fa0da5cb 100644 --- a/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml +++ b/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml @@ -39,7 +39,7 @@ sound: path: /Audio/Effects/metalbreak.ogg - !type:ExplodeBehavior - + - type: entity parent: BaseVehicle id: BaseVehicleRideable @@ -198,7 +198,7 @@ baseSprintSpeed: 6 - type: Armor modifiers: - coeffecients: + coefficients: Blunt: 0.8 Slash: 0.6 Piercing: 0.85 @@ -289,7 +289,7 @@ maxBuckleDistance: 1 - type: Armor modifiers: - coeffecients: + coefficients: Blunt: 0.8 Slash: 0.6 Piercing: 0.85 From eecff4a7a2e0201ba37f29b67114436385055dd9 Mon Sep 17 00:00:00 2001 From: ravage <142820619+ravage123321@users.noreply.github.com> Date: Thu, 28 Sep 2023 13:49:17 +0300 Subject: [PATCH 11/98] clean up some lines in smile the slime prototype (#20552) --- Resources/Prototypes/Entities/Mobs/NPCs/pets.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index 7846dd66fae..1efa767af1b 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -619,8 +619,6 @@ description: This masterpiece has gone through thousands of experiments. But it is the sweetest creature in the world. Smile Slime! components: - type: Sprite - drawdepth: Mobs - sprite: Mobs/Aliens/slimes.rsi layers: - map: [ "enum.DamageStateVisualLayers.Base" ] state: rainbow_baby_slime @@ -650,22 +648,14 @@ Dead: Base: rainbow_baby_slime_dead - type: Butcherable - butcheringType: Knife spawned: - id: FoodMeatSlime amount: 1 - id: MaterialSmileExtract amount: 1 - type: Damageable - damageContainer: Biological damageModifierSet: SlimePet - type: Bloodstream - bloodMaxVolume: 150 - bloodReagent: Slime - bloodlossDamage: - types: - Bloodloss: - 1 bloodlossHealDamage: types: Bloodloss: @@ -674,11 +664,6 @@ heatDamageThreshold: 800 coldDamageThreshold: 0 - type: MeleeWeapon - hidden: true - soundHit: - path: /Audio/Weapons/punch3.ogg - angle: 0 - animation: WeaponArcPunch damage: types: Blunt: 1 @@ -688,7 +673,6 @@ - type: MobPrice price: 3000 # it is a truly valuable creature - type: GhostRole - makeSentient: true name: ghost-role-information-smile-name description: ghost-role-information-smile-description - type: Grammar From b1c33b785643e8ee264f05c6b3078c95869b6a3e Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 28 Sep 2023 12:49:49 +0200 Subject: [PATCH 12/98] Revert "Use full file path for temp replays (#19002)" (#20545) --- Content.Server/GameTicking/GameTicker.Replays.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Content.Server/GameTicking/GameTicker.Replays.cs b/Content.Server/GameTicking/GameTicker.Replays.cs index 42e2de02287..03cf748d09d 100644 --- a/Content.Server/GameTicking/GameTicker.Replays.cs +++ b/Content.Server/GameTicking/GameTicker.Replays.cs @@ -43,7 +43,9 @@ private void ReplayStartRound() { var baseReplayPath = new ResPath(_cfg.GetCVar(CVars.ReplayDirectory)).ToRootedPath(); moveToPath = baseReplayPath / finalPath; - recordPath = new ResPath(tempDir) / finalPath; + + var fileName = finalPath.Filename; + recordPath = new ResPath(tempDir) / fileName; _sawmillReplays.Debug($"Replay will record in temporary position: {recordPath}"); } From fe4ade9ba30b7b3994b4a91337ed4bf4caffe2bd Mon Sep 17 00:00:00 2001 From: LEVELcat <68501903+LEVELcat@users.noreply.github.com> Date: Thu, 28 Sep 2023 13:52:05 +0300 Subject: [PATCH 13/98] Add EyesGlasses into ClothesMate (#20523) --- .../Catalog/VendingMachines/Inventories/clothesmate.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml index e263903ef50..554989b5cee 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml @@ -58,6 +58,7 @@ ClothingHeadFishCap: 2 ClothingHeadRastaHat: 2 ClothingBeltStorageWaistbag: 3 + ClothingEyesGlasses: 6 contrabandInventory: ClothingUniformJumpsuitTacticool: 1 ClothingUniformJumpskirtTacticool: 1 From 60d5c7c1fbc7e290723bf47dbfba6a70ce3054c1 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 06:53:09 -0400 Subject: [PATCH 14/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f2c87d9c02a..c20993bf998 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Slava0135 - changes: - - {message: Hitting entities with thrown items that deal damage now provide more - feedback (sound and visual effect)., type: Add} - - {message: Thrown items that damage other entities now land after first hit., type: Tweak} - id: 4409 - time: '2023-08-02T09:30:04.0000000+00:00' - author: Slava0135 changes: - {message: added visual effect on collision for damage on high speed entities, @@ -2971,3 +2964,8 @@ Entries: type: Add} id: 4908 time: '2023-09-28T04:09:45.0000000+00:00' +- author: LEVELcat + changes: + - {message: Eyeglass are now available from the ClothesMate., type: Add} + id: 4909 + time: '2023-09-28T10:52:05.0000000+00:00' From 2f7e43ffa838b35d2292260f580bf6e452c8c7b7 Mon Sep 17 00:00:00 2001 From: Repo <47093363+Titian3@users.noreply.github.com> Date: Thu, 28 Sep 2023 23:53:53 +1300 Subject: [PATCH 15/98] Fix Punpun crew monitor sensor (#20484) --- .../Access/Components/PresetIdCardComponent.cs | 3 +++ Content.Server/Access/Systems/PresetIdCardSystem.cs | 9 +++++++++ .../Entities/Clothing/Uniforms/jumpsuits.yml | 4 ++++ .../Entities/Objects/Misc/identification_cards.yml | 13 +++++++++++++ .../Prototypes/Roles/Jobs/Fun/misc_startinggear.yml | 2 +- 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Content.Server/Access/Components/PresetIdCardComponent.cs b/Content.Server/Access/Components/PresetIdCardComponent.cs index 89850866d65..a2842d7815f 100644 --- a/Content.Server/Access/Components/PresetIdCardComponent.cs +++ b/Content.Server/Access/Components/PresetIdCardComponent.cs @@ -5,5 +5,8 @@ public sealed partial class PresetIdCardComponent : Component { [DataField("job")] public string? JobName; + + [DataField("name")] + public string? IdName; } } diff --git a/Content.Server/Access/Systems/PresetIdCardSystem.cs b/Content.Server/Access/Systems/PresetIdCardSystem.cs index 271e16cbf93..96a38278b5b 100644 --- a/Content.Server/Access/Systems/PresetIdCardSystem.cs +++ b/Content.Server/Access/Systems/PresetIdCardSystem.cs @@ -37,6 +37,7 @@ private void PlayerJobsAssigned(RulePlayerJobsAssignedEvent ev) return; SetupIdAccess(uid, card, true); + SetupIdName(uid, card); } } @@ -53,6 +54,14 @@ private void OnMapInit(EntityUid uid, PresetIdCardComponent id, MapInitEvent arg extended = Comp(station.Value).ExtendedAccess; SetupIdAccess(uid, id, extended); + SetupIdName(uid, id); + } + + private void SetupIdName(EntityUid uid, PresetIdCardComponent id) + { + if (id.IdName == null) + return; + _cardSystem.TryChangeFullName(uid, id.IdName); } private void SetupIdAccess(EntityUid uid, PresetIdCardComponent id, bool extended) diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 0a603bc509b..da08036fb05 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -48,6 +48,10 @@ sprite: Clothing/Uniforms/Jumpsuit/punpun.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/punpun.rsi + - type: SuitSensor + controlsLocked: false + randomMode: false + mode: SensorCords - type: entity parent: ClothingUniformBase diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index df2cb002982..68e2f335ec4 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -294,6 +294,19 @@ - type: PresetIdCard job: Bartender +- type: entity + parent: IDCardStandard + id: PunPunIDCard + name: pun pun ID card + components: + - type: Sprite + layers: + - state: default + - state: idbartender + - type: PresetIdCard + job: Bartender + name: Pun Pun + - type: entity parent: IDCardStandard id: ChefIDCard diff --git a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml index 03597dc64e9..a66881089c3 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml @@ -282,7 +282,7 @@ head: ClothingHeadHatTophat ears: ClothingHeadsetService jumpsuit: ClothingUniformJumpsuitJacketMonkey - id: BartenderIDCard + id: PunPunIDCard # Passenger but without the ID, bag, or headset From be86fd8e6b9e0cfb45d625a51b646c73f02e8605 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 06:54:58 -0400 Subject: [PATCH 16/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c20993bf998..ba68c124913 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: Slava0135 - changes: - - {message: added visual effect on collision for damage on high speed entities, - type: Add} - id: 4410 - time: '2023-08-02T09:32:44.0000000+00:00' - author: deltanedas changes: - {message: 'Added the gateway, currently for admins to teleport you to funny places.', @@ -2969,3 +2963,8 @@ Entries: - {message: Eyeglass are now available from the ClothesMate., type: Add} id: 4909 time: '2023-09-28T10:52:05.0000000+00:00' +- author: Repo + changes: + - {message: Pun Pun now showing on crew monitoring., type: Fix} + id: 4910 + time: '2023-09-28T10:53:54.0000000+00:00' From b288d3362255d9e5245085af433738ee4043447d Mon Sep 17 00:00:00 2001 From: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:34:21 +0000 Subject: [PATCH 17/98] EasyPry airlocks for arrivals. Now also prying refactor I guess (#19394) Co-authored-by: metalgearsloth --- Content.Client/Doors/AirlockSystem.cs | 8 + Content.Server/Doors/Systems/AirlockSystem.cs | 20 +-- Content.Server/Doors/Systems/DoorSystem.cs | 123 ++++--------- .../Doors/Systems/FirelockSystem.cs | 7 +- .../Systems/NPCSteeringSystem.Obstacles.cs | 2 +- .../NPC/Systems/NPCSteeringSystem.cs | 6 +- .../Zombies/ZombieSystem.Transform.cs | 14 +- .../Doors/Components/DoorComponent.cs | 6 +- Content.Shared/Doors/DoorEvents.cs | 31 ---- .../Doors/Systems/SharedDoorBoltSystem.cs | 11 +- .../Doors/Systems/SharedDoorSystem.cs | 48 ++++-- .../Components/PryUnpoweredComponent.cs | 11 ++ .../Prying/Components/PryingComponent.cs | 82 +++++++++ Content.Shared/Prying/Systems/PryingSystem.cs | 162 ++++++++++++++++++ .../Systems/SharedToolSystem.MultipleTool.cs | 18 +- .../Entities/Debugging/spanisharmyknife.yml | 1 + .../Prototypes/Entities/Mobs/NPCs/xeno.yml | 5 + .../Entities/Objects/Tools/cowtools.yml | 3 +- .../Entities/Objects/Tools/jaws_of_life.yml | 8 +- .../Entities/Objects/Tools/tools.yml | 1 + .../Objects/Weapons/Melee/armblade.yml | 1 + .../Objects/Weapons/Melee/fireaxe.yml | 1 + .../Entities/Objects/Weapons/Melee/mining.yml | 1 + .../Structures/Doors/Airlocks/easy_pry.yml | 63 +++++++ 24 files changed, 463 insertions(+), 170 deletions(-) create mode 100644 Content.Shared/Prying/Components/PryUnpoweredComponent.cs create mode 100644 Content.Shared/Prying/Components/PryingComponent.cs create mode 100644 Content.Shared/Prying/Systems/PryingSystem.cs create mode 100644 Resources/Prototypes/Entities/Structures/Doors/Airlocks/easy_pry.yml diff --git a/Content.Client/Doors/AirlockSystem.cs b/Content.Client/Doors/AirlockSystem.cs index 18b9eae5f34..cc68d090394 100644 --- a/Content.Client/Doors/AirlockSystem.cs +++ b/Content.Client/Doors/AirlockSystem.cs @@ -1,6 +1,7 @@ using Content.Client.Wires.Visualizers; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; +using Content.Shared.Prying.Components; using Robust.Client.Animations; using Robust.Client.GameObjects; @@ -15,6 +16,13 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnComponentStartup); SubscribeLocalEvent(OnAppearanceChange); + SubscribeLocalEvent(OnAirlockPryAttempt); + } + + private void OnAirlockPryAttempt(EntityUid uid, AirlockComponent component, ref BeforePryEvent args) + { + // TODO: Temporary until airlocks predicted. + args.Cancelled = true; } private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args) diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs index bb75fc7d476..0ea2755ab66 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -1,7 +1,6 @@ using Content.Server.DeviceLinking.Events; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; -using Content.Shared.Tools.Components; using Content.Server.Wires; using Content.Shared.Doors; using Content.Shared.Doors.Components; @@ -9,6 +8,7 @@ using Content.Shared.Interaction; using Robust.Server.GameObjects; using Content.Shared.Wires; +using Content.Shared.Prying.Components; using Robust.Shared.Prototypes; namespace Content.Server.Doors.Systems; @@ -31,9 +31,9 @@ public override void Initialize() SubscribeLocalEvent(OnStateChanged); SubscribeLocalEvent(OnBeforeDoorOpened); SubscribeLocalEvent(OnBeforeDoorDenied); - SubscribeLocalEvent(OnActivate, before: new [] {typeof(DoorSystem)}); - SubscribeLocalEvent(OnGetPryMod); - SubscribeLocalEvent(OnDoorPry); + SubscribeLocalEvent(OnActivate, before: new[] { typeof(DoorSystem) }); + SubscribeLocalEvent(OnGetPryMod); + SubscribeLocalEvent(OnBeforePry); } @@ -169,20 +169,18 @@ private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWor } } - private void OnGetPryMod(EntityUid uid, AirlockComponent component, DoorGetPryTimeModifierEvent args) + private void OnGetPryMod(EntityUid uid, AirlockComponent component, ref GetPryTimeModifierEvent args) { if (_power.IsPowered(uid)) args.PryTimeModifier *= component.PoweredPryModifier; } - private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args) + private void OnBeforePry(EntityUid uid, AirlockComponent component, ref BeforePryEvent args) { - if (this.IsPowered(uid, EntityManager)) + if (this.IsPowered(uid, EntityManager) && !args.PryPowered) { - if (HasComp(args.Tool)) - return; - Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User); - args.Cancel(); + Popup.PopupClient(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User); + args.Cancelled = true; } } diff --git a/Content.Server/Doors/Systems/DoorSystem.cs b/Content.Server/Doors/Systems/DoorSystem.cs index f9918dfb0a6..aa4de6b86bb 100644 --- a/Content.Server/Doors/Systems/DoorSystem.cs +++ b/Content.Server/Doors/Systems/DoorSystem.cs @@ -1,15 +1,12 @@ using Content.Server.Access; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; -using Content.Server.Construction; using Content.Shared.Database; using Content.Shared.Doors; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; using Content.Shared.Emag.Systems; using Content.Shared.Interaction; -using Content.Shared.Tools.Components; -using Content.Shared.Verbs; using Robust.Shared.Audio; using Content.Server.Administration.Logs; using Content.Server.Power.EntitySystems; @@ -17,6 +14,8 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Content.Shared.DoAfter; +using Content.Shared.Prying.Systems; +using Content.Shared.Prying.Components; using Content.Shared.Tools.Systems; namespace Content.Server.Doors.Systems; @@ -27,20 +26,19 @@ public sealed class DoorSystem : SharedDoorSystem [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly AirtightSystem _airtightSystem = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly PryingSystem _pryingSystem = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInteractUsing, after: new[] { typeof(ConstructionSystem) }); - // Mob prying doors - SubscribeLocalEvent>(OnDoorAltVerb); - - SubscribeLocalEvent(OnPryFinished); + SubscribeLocalEvent(OnBeforeDoorPry); SubscribeLocalEvent(OnWeldAttempt); SubscribeLocalEvent(OnWeldChanged); SubscribeLocalEvent(OnEmagged); + SubscribeLocalEvent(OnAfterPry); } protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args) @@ -49,7 +47,9 @@ protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateIn if (args.Handled || !door.ClickOpen) return; - TryToggleDoor(uid, door, args.User); + if (!TryToggleDoor(uid, door, args.User)) + _pryingSystem.TryPry(uid, args.User, out _); + args.Handled = true; } @@ -108,24 +108,7 @@ protected override void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, Audio.PlayPvs(soundSpecifier, uid, audioParams); } -#region DoAfters - /// - /// Weld or pry open a door. - /// - private void OnInteractUsing(EntityUid uid, DoorComponent door, InteractUsingEvent args) - { - if (args.Handled) - return; - - if (!TryComp(args.Used, out ToolComponent? tool)) - return; - - if (tool.Qualities.Contains(door.PryingQuality)) - { - args.Handled = TryPryDoor(uid, args.Used, args.User, door, out _); - } - } - + #region DoAfters private void OnWeldAttempt(EntityUid uid, DoorComponent component, WeldableAttemptEvent args) { if (component.CurrentlyCrushing.Count > 0) @@ -147,69 +130,12 @@ private void OnWeldChanged(EntityUid uid, DoorComponent component, ref WeldableC SetState(uid, DoorState.Closed, component); } - private void OnDoorAltVerb(EntityUid uid, DoorComponent component, GetVerbsEvent args) + private void OnBeforeDoorPry(EntityUid id, DoorComponent door, ref BeforePryEvent args) { - if (!args.CanInteract || !args.CanAccess) - return; - - if (!TryComp(args.User, out var tool) || !tool.Qualities.Contains(component.PryingQuality)) - return; - - args.Verbs.Add(new AlternativeVerb() - { - Text = Loc.GetString("door-pry"), - Impact = LogImpact.Low, - Act = () => TryPryDoor(uid, args.User, args.User, component, out _, force: true), - }); + if (door.State == DoorState.Welded || !door.CanPry) + args.Cancelled = true; } - - - /// - /// Pry open a door. This does not check if the user is holding the required tool. - /// - public bool TryPryDoor(EntityUid target, EntityUid tool, EntityUid user, DoorComponent door, out DoAfterId? id, bool force = false) - { - id = null; - - if (door.State == DoorState.Welded) - return false; - - if (!force) - { - var canEv = new BeforeDoorPryEvent(user, tool); - RaiseLocalEvent(target, canEv, false); - - if (!door.CanPry || canEv.Cancelled) - // mark handled, as airlock component will cancel after generating a pop-up & you don't want to pry a tile - // under a windoor. - return true; - } - - var modEv = new DoorGetPryTimeModifierEvent(user); - RaiseLocalEvent(target, modEv, false); - - _adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is using {ToPrettyString(tool)} to pry {ToPrettyString(target)} while it is {door.State}"); // TODO move to generic tool use logging in a way that includes door state - _toolSystem.UseTool(tool, user, target, TimeSpan.FromSeconds(modEv.PryTimeModifier * door.PryTime), new[] {door.PryingQuality}, new DoorPryDoAfterEvent(), out id); - return true; // we might not actually succeeded, but a do-after has started - } - - private void OnPryFinished(EntityUid uid, DoorComponent door, DoAfterEvent args) - { - if (args.Cancelled) - return; - - if (door.State == DoorState.Closed) - { - _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} open"); // TODO move to generic tool use logging in a way that includes door state - StartOpening(uid, door); - } - else if (door.State == DoorState.Open) - { - _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} closed"); // TODO move to generic tool use logging in a way that includes door state - StartClosing(uid, door); - } - } -#endregion + #endregion /// @@ -233,7 +159,7 @@ protected override void HandleCollide(EntityUid uid, DoorComponent door, ref Sta } private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args) { - if(TryComp(uid, out var airlockComponent)) + if (TryComp(uid, out var airlockComponent)) { if (_bolts.IsBolted(uid) || !this.IsPowered(uid, EntityManager)) return; @@ -259,10 +185,27 @@ public override void StartOpening(EntityUid uid, DoorComponent? door = null, Ent if (door.OpenSound != null) PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted); - if(lastState == DoorState.Emagging && TryComp(uid, out var doorBoltComponent)) + if (lastState == DoorState.Emagging && TryComp(uid, out var doorBoltComponent)) _bolts.SetBoltsWithAudio(uid, doorBoltComponent, !doorBoltComponent.BoltsDown); } + /// + /// Open or close a door after it has been successfuly pried. + /// + private void OnAfterPry(EntityUid uid, DoorComponent door, ref PriedEvent args) + { + if (door.State == DoorState.Closed) + { + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} open"); + StartOpening(uid, door, args.User); + } + else if (door.State == DoorState.Open) + { + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} closed"); + StartClosing(uid, door, args.User); + } + } + protected override void CheckDoorBump(DoorComponent component, PhysicsComponent body) { var uid = body.Owner; diff --git a/Content.Server/Doors/Systems/FirelockSystem.cs b/Content.Server/Doors/Systems/FirelockSystem.cs index 7147aa4f24c..e2f25c63ab4 100644 --- a/Content.Server/Doors/Systems/FirelockSystem.cs +++ b/Content.Server/Doors/Systems/FirelockSystem.cs @@ -18,6 +18,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Map.Components; using Robust.Shared.Player; +using Content.Shared.Prying.Components; namespace Content.Server.Doors.Systems { @@ -38,7 +39,7 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnBeforeDoorOpened); - SubscribeLocalEvent(OnDoorGetPryTimeModifier); + SubscribeLocalEvent(OnDoorGetPryTimeModifier); SubscribeLocalEvent(OnUpdateState); SubscribeLocalEvent(OnBeforeDoorAutoclose); @@ -144,7 +145,7 @@ private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, Befo args.Cancel(); } - private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, DoorGetPryTimeModifierEvent args) + private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, ref GetPryTimeModifierEvent args) { var state = CheckPressureAndFire(uid, component); @@ -261,7 +262,7 @@ public bool IsHoldingPressureOrFire(EntityUid uid, FirelockComponent firelock) List directions = new(4); for (var i = 0; i < Atmospherics.Directions; i++) { - var dir = (AtmosDirection) (1 << i); + var dir = (AtmosDirection)(1 << i); if (airtight.AirBlockedDirection.HasFlag(dir)) { directions.Add(dir); diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs index 1d9c19de027..87deec9ea9d 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs @@ -113,7 +113,7 @@ private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponen // TODO: Use the verb. if (door.State != DoorState.Opening) - _doors.TryPryDoor(ent, uid, uid, door, out id, force: true); + _pryingSystem.TryPry(ent, uid, out id, uid); component.DoAfterId = id; return SteeringObstacleStatus.Continuing; diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index cbc2ba6d2c4..0fa28f6af79 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -31,6 +31,7 @@ using Robust.Shared.Threading; using Robust.Shared.Timing; using Robust.Shared.Utility; +using Content.Shared.Prying.Systems; namespace Content.Server.NPC.Systems; @@ -63,6 +64,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedCombatModeSystem _combat = default!; + [Dependency] private readonly PryingSystem _pryingSystem = default!; private EntityQuery _fixturesQuery; private EntityQuery _modifierQuery; @@ -148,7 +150,7 @@ public override void Shutdown() private void OnDebugRequest(RequestNPCSteeringDebugEvent msg, EntitySessionEventArgs args) { - if (!_admin.IsAdmin((IPlayerSession) args.SenderSession)) + if (!_admin.IsAdmin((IPlayerSession)args.SenderSession)) return; if (msg.Enabled) @@ -440,7 +442,7 @@ private async void RequestPath(EntityUid uid, NPCSteeringComponent steering, Tra if (targetPoly != null && steering.Coordinates.Position.Equals(Vector2.Zero) && TryComp(uid, out var physics) && - _interaction.InRangeUnobstructed(uid, steering.Coordinates.EntityId, range: 30f, (CollisionGroup) physics.CollisionMask)) + _interaction.InRangeUnobstructed(uid, steering.Coordinates.EntityId, range: 30f, (CollisionGroup)physics.CollisionMask)) { steering.CurrentPath.Clear(); steering.CurrentPath.Enqueue(targetPoly); diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 5da7c6e8cd7..19e80132208 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -32,6 +32,7 @@ using Content.Shared.Weapons.Melee; using Content.Shared.Zombies; using Robust.Shared.Audio; +using Content.Shared.Prying.Components; namespace Content.Server.Zombies { @@ -162,11 +163,12 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) melee.Damage = dspec; // humanoid zombies get to pry open doors and shit - var tool = EnsureComp(target); - tool.SpeedModifier = 0.75f; - tool.Qualities = new ("Prying"); - tool.UseSound = new SoundPathSpecifier("/Audio/Items/crowbar.ogg"); - Dirty(tool); + var pryComp = EnsureComp(target); + pryComp.SpeedModifier = 0.75f; + pryComp.PryPowered = true; + pryComp.Force = true; + + Dirty(target, pryComp); } Dirty(melee); @@ -232,7 +234,7 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) else { var htn = EnsureComp(target); - htn.RootTask = new HTNCompoundTask() {Task = "SimpleHostileCompound"}; + htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" }; htn.Blackboard.SetValue(NPCBlackboard.Owner, target); _npc.WakeNPC(target, htn); } diff --git a/Content.Shared/Doors/Components/DoorComponent.cs b/Content.Shared/Doors/Components/DoorComponent.cs index 567afa07701..7cfcba8c5b6 100644 --- a/Content.Shared/Doors/Components/DoorComponent.cs +++ b/Content.Shared/Doors/Components/DoorComponent.cs @@ -249,7 +249,7 @@ private float? SecondsUntilStateChange } var curTime = IoCManager.Resolve().CurTime; - return (float) (NextStateChange.Value - curTime).TotalSeconds; + return (float)(NextStateChange.Value - curTime).TotalSeconds; } set { @@ -299,10 +299,10 @@ private float? SecondsUntilStateChange public bool ClickOpen = true; [DataField("openDrawDepth", customTypeSerializer: typeof(ConstantSerializer))] - public int OpenDrawDepth = (int) DrawDepth.DrawDepth.Doors; + public int OpenDrawDepth = (int)DrawDepth.DrawDepth.Doors; [DataField("closedDrawDepth", customTypeSerializer: typeof(ConstantSerializer))] - public int ClosedDrawDepth = (int) DrawDepth.DrawDepth.Doors; + public int ClosedDrawDepth = (int)DrawDepth.DrawDepth.Doors; } [Serializable, NetSerializable] diff --git a/Content.Shared/Doors/DoorEvents.cs b/Content.Shared/Doors/DoorEvents.cs index 5b0ca71ede7..08a2c8b18b1 100644 --- a/Content.Shared/Doors/DoorEvents.cs +++ b/Content.Shared/Doors/DoorEvents.cs @@ -62,35 +62,4 @@ public sealed class BeforeDoorDeniedEvent : CancellableEntityEventArgs public sealed class BeforeDoorAutoCloseEvent : CancellableEntityEventArgs { } - - /// - /// Raised to determine how long the door's pry time should be modified by. - /// Multiply PryTimeModifier by the desired amount. - /// - public sealed class DoorGetPryTimeModifierEvent : EntityEventArgs - { - public readonly EntityUid User; - public float PryTimeModifier = 1.0f; - - public DoorGetPryTimeModifierEvent(EntityUid user) - { - User = user; - } - } - - /// - /// Raised when an attempt to pry open the door is made. - /// Cancel to stop the door from being pried open. - /// - public sealed class BeforeDoorPryEvent : CancellableEntityEventArgs - { - public readonly EntityUid User; - public readonly EntityUid Tool; - - public BeforeDoorPryEvent(EntityUid user, EntityUid tool) - { - User = user; - Tool = tool; - } - } } diff --git a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs index e8be596b060..1deb6e3f7c0 100644 --- a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Doors.Components; using Content.Shared.Popups; +using Content.Shared.Prying.Components; namespace Content.Shared.Doors.Systems; @@ -16,16 +17,16 @@ public override void Initialize() SubscribeLocalEvent(OnBeforeDoorOpened); SubscribeLocalEvent(OnBeforeDoorClosed); SubscribeLocalEvent(OnBeforeDoorDenied); - SubscribeLocalEvent(OnDoorPry); + SubscribeLocalEvent(OnDoorPry); } - private void OnDoorPry(EntityUid uid, DoorBoltComponent component, BeforeDoorPryEvent args) + private void OnDoorPry(EntityUid uid, DoorBoltComponent component, ref BeforePryEvent args) { - if (component.BoltsDown) + if (component.BoltsDown && !args.Force) { - Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User); - args.Cancel(); + Popup.PopupClient(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User); + args.Cancelled = true; } } diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index 3fc912deba9..e5515171496 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -16,6 +16,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Serialization; using Robust.Shared.Timing; +using Content.Shared.Prying.Components; namespace Content.Shared.Doors.Systems; @@ -23,14 +24,14 @@ public abstract partial class SharedDoorSystem : EntitySystem { [Dependency] protected readonly IGameTiming GameTiming = default!; [Dependency] protected readonly SharedPhysicsSystem PhysicsSystem = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly SharedStunSystem _stunSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] protected readonly TagSystem Tags = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; - [Dependency] private readonly EntityLookupSystem _entityLookup = default!; + [Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!; - [Dependency] private readonly OccluderSystem _occluder = default!; - [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; + [Dependency] private readonly OccluderSystem _occluder = default!; + [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; /// /// A body must have an intersection percentage larger than this in order to be considered as colliding with a @@ -61,6 +62,8 @@ public override void Initialize() SubscribeLocalEvent(HandleCollide); SubscribeLocalEvent(PreventCollision); + SubscribeLocalEvent(OnPryTimeModifier); + } protected virtual void OnComponentInit(EntityUid uid, DoorComponent door, ComponentInit args) @@ -182,6 +185,11 @@ protected virtual void OnActivate(EntityUid uid, DoorComponent door, ActivateInW args.Handled = true; } + private void OnPryTimeModifier(EntityUid uid, DoorComponent door, ref GetPryTimeModifierEvent args) + { + args.BaseTime = door.PryTime; + } + /// /// Update the door state/visuals and play an access denied sound when a user without access interacts with the /// door. @@ -206,6 +214,7 @@ public void Deny(EntityUid uid, DoorComponent? door = null, EntityUid? user = nu PlaySound(uid, door.DenySound, AudioParams.Default.WithVolume(-3), user, predicted); } + public bool TryToggleDoor(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) { if (!Resolve(uid, ref door)) @@ -246,7 +255,7 @@ public bool CanOpen(EntityUid uid, DoorComponent? door = null, EntityUid? user = if (door.State == DoorState.Welded) return false; - var ev = new BeforeDoorOpenedEvent(){User=user}; + var ev = new BeforeDoorOpenedEvent() { User = user }; RaiseLocalEvent(uid, ev, false); if (ev.Cancelled) return false; @@ -261,6 +270,14 @@ public bool CanOpen(EntityUid uid, DoorComponent? door = null, EntityUid? user = return true; } + /// + /// Immediately start opening a door + /// + /// The uid of the door + /// The doorcomponent of the door + /// The user (if any) opening the door + /// Whether the interaction would have been + /// predicted. See comments in the PlaySound method on the Server system for details public virtual void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) { if (!Resolve(uid, ref door)) @@ -309,6 +326,14 @@ public bool TryClose(EntityUid uid, DoorComponent? door = null, EntityUid? user return true; } + /// + /// Immediately start closing a door + /// + /// The uid of the door + /// The doorcomponent of the door + /// The user (if any) opening the door + /// Whether the interaction would have been + /// predicted. See comments in the PlaySound method on the Server system for details public bool CanClose(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool quiet = true) { if (!Resolve(uid, ref door)) @@ -444,11 +469,11 @@ public IEnumerable GetColliding(EntityUid uid, PhysicsComponent? phys //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.CanCollide || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassAirlockLayer || otherPhysics.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.CollisionLayer == (int)CollisionGroup.SlipLayer && otherPhysics.CollisionMask == (int)CollisionGroup.ItemMask) continue; if ((physics.CollisionMask & otherPhysics.CollisionLayer) == 0 && (otherPhysics.CollisionMask & physics.CollisionLayer) == 0) @@ -598,7 +623,7 @@ public override void Update(float frameTime) } } - protected virtual void CheckDoorBump(DoorComponent component, PhysicsComponent body) {} + protected virtual void CheckDoorBump(DoorComponent component, PhysicsComponent body) { } /// /// Makes a door proceed to the next state (if applicable). @@ -659,9 +684,4 @@ private void NextState(DoorComponent door, TimeSpan time) #endregion protected abstract void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted); - - [Serializable, NetSerializable] - protected sealed partial class DoorPryDoAfterEvent : SimpleDoAfterEvent - { - } } diff --git a/Content.Shared/Prying/Components/PryUnpoweredComponent.cs b/Content.Shared/Prying/Components/PryUnpoweredComponent.cs new file mode 100644 index 00000000000..f0e61dc9685 --- /dev/null +++ b/Content.Shared/Prying/Components/PryUnpoweredComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Prying.Components; + +/// +/// Applied to entities that can be pried open without tools while unpowered +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class PryUnpoweredComponent : Component +{ +} diff --git a/Content.Shared/Prying/Components/PryingComponent.cs b/Content.Shared/Prying/Components/PryingComponent.cs new file mode 100644 index 00000000000..4442481dce1 --- /dev/null +++ b/Content.Shared/Prying/Components/PryingComponent.cs @@ -0,0 +1,82 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Prying.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class PryingComponent : Component +{ + /// + /// Whether the entity can pry open powered doors + /// + [DataField("pryPowered")] + public bool PryPowered = false; + + /// + /// Whether the tool can bypass certain restrictions when prying. + /// For example door bolts. + /// + [DataField("force")] + public bool Force = false; + /// + /// Modifier on the prying time. + /// Lower values result in more time. + /// + [DataField("speedModifier")] + public float SpeedModifier = 1.0f; + + /// + /// What sound to play when prying is finished. + /// + [DataField("useSound")] + public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/crowbar.ogg"); + + /// + /// Whether the entity can currently pry things. + /// + [DataField("enabled")] + public bool Enabled = true; +} + +/// +/// Raised directed on an entity before prying it. +/// Cancel to stop the entity from being pried open. +/// +[ByRefEvent] +public record struct BeforePryEvent(EntityUid User, bool PryPowered, bool Force) +{ + public readonly EntityUid User = User; + + public readonly bool PryPowered = PryPowered; + + public readonly bool Force = Force; + + public bool Cancelled; +} + +/// +/// Raised directed on an entity that has been pried. +/// +[ByRefEvent] +public readonly record struct PriedEvent(EntityUid User) +{ + public readonly EntityUid User = User; +} + +/// +/// Raised to determine how long the door's pry time should be modified by. +/// Multiply PryTimeModifier by the desired amount. +/// +[ByRefEvent] +public record struct GetPryTimeModifierEvent +{ + public readonly EntityUid User; + public float PryTimeModifier = 1.0f; + public float BaseTime = 5.0f; + + public GetPryTimeModifierEvent(EntityUid user) + { + User = user; + } +} + diff --git a/Content.Shared/Prying/Systems/PryingSystem.cs b/Content.Shared/Prying/Systems/PryingSystem.cs new file mode 100644 index 00000000000..3bb3a9bc9b0 --- /dev/null +++ b/Content.Shared/Prying/Systems/PryingSystem.cs @@ -0,0 +1,162 @@ +using Content.Shared.Prying.Components; +using Content.Shared.Verbs; +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Doors.Components; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Interaction; +using PryUnpoweredComponent = Content.Shared.Prying.Components.PryUnpoweredComponent; + +namespace Content.Shared.Prying.Systems; + +/// +/// Handles prying of entities (e.g. doors) +/// +public sealed class PryingSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + // Mob prying doors + SubscribeLocalEvent>(OnDoorAltVerb); + SubscribeLocalEvent(OnDoAfter); + SubscribeLocalEvent(TryPryDoor); + } + + private void TryPryDoor(EntityUid uid, DoorComponent comp, InteractUsingEvent args) + { + if (args.Handled) + return; + + args.Handled = TryPry(uid, args.User, out _, args.Used); + } + + private void OnDoorAltVerb(EntityUid uid, DoorComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + if (!TryComp(args.User, out var tool)) + return; + + args.Verbs.Add(new AlternativeVerb() + { + Text = Loc.GetString("door-pry"), + Impact = LogImpact.Low, + Act = () => TryPry(uid, args.User, out _, args.User), + }); + } + + /// + /// Attempt to pry an entity. + /// + public bool TryPry(EntityUid target, EntityUid user, out DoAfterId? id, EntityUid tool) + { + id = null; + + PryingComponent? comp = null; + if (!Resolve(tool, ref comp, false)) + return false; + + if (!comp.Enabled) + return false; + + if (!CanPry(target, user, comp)) + { + // If we have reached this point we want the event that caused this + // to be marked as handled as a popup would be generated on failure. + return true; + } + + StartPry(target, user, tool, comp.SpeedModifier, out id); + + return true; + } + + /// + /// Try to pry an entity. + /// + public bool TryPry(EntityUid target, EntityUid user, out DoAfterId? id) + { + id = null; + + if (!CanPry(target, user)) + // If we have reached this point we want the event that caused this + // to be marked as handled as a popup would be generated on failure. + return true; + + return StartPry(target, user, null, 1.0f, out id); + } + + private bool CanPry(EntityUid target, EntityUid user, PryingComponent? comp = null) + { + BeforePryEvent canev; + + if (comp != null) + { + canev = new BeforePryEvent(user, comp.PryPowered, comp.Force); + } + else + { + if (!TryComp(target, out _)) + return false; + canev = new BeforePryEvent(user, false, false); + } + + RaiseLocalEvent(target, ref canev); + + if (canev.Cancelled) + return false; + return true; + } + + private bool StartPry(EntityUid target, EntityUid user, EntityUid? tool, float toolModifier, [NotNullWhen(true)] out DoAfterId? id) + { + var modEv = new GetPryTimeModifierEvent(user); + + RaiseLocalEvent(target, ref modEv); + var doAfterArgs = new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(modEv.BaseTime * modEv.PryTimeModifier / toolModifier), new DoorPryDoAfterEvent(), target, target, tool) + { + BreakOnDamage = true, + BreakOnUserMove = true, + }; + + if (tool != null) + { + _adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is using {ToPrettyString(tool.Value)} to pry {ToPrettyString(target)}"); + } + else + { + _adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is prying {ToPrettyString(target)}"); + } + return _doAfterSystem.TryStartDoAfter(doAfterArgs, out id); + } + + private void OnDoAfter(EntityUid uid, DoorComponent door, DoorPryDoAfterEvent args) + { + if (args.Cancelled) + return; + if (args.Target is null) + return; + + PryingComponent? comp = null; + + if (args.Used != null && Resolve(args.Used.Value, ref comp)) + _audioSystem.PlayPredicted(comp.UseSound, args.Used.Value, args.User); + + var ev = new PriedEvent(args.User); + RaiseLocalEvent(uid, ref ev); + } +} + +[Serializable, NetSerializable] +public sealed partial class DoorPryDoAfterEvent : SimpleDoAfterEvent +{ +} diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs b/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs index b198f6d779c..d528c1be7dd 100644 --- a/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs +++ b/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs @@ -2,6 +2,7 @@ using Content.Shared.Interaction; using Content.Shared.Tools.Components; using Robust.Shared.GameStates; +using Content.Shared.Prying.Components; namespace Content.Shared.Tools; @@ -27,7 +28,7 @@ private void OnMultipleToolHandleState(EntityUid uid, MultipleToolComponent comp private void OnMultipleToolStartup(EntityUid uid, MultipleToolComponent multiple, ComponentStartup args) { // Only set the multiple tool if we have a tool component. - if(EntityManager.TryGetComponent(uid, out ToolComponent? tool)) + if (EntityManager.TryGetComponent(uid, out ToolComponent? tool)) SetMultipleTool(uid, multiple, tool); } @@ -52,7 +53,7 @@ public bool CycleMultipleTool(EntityUid uid, MultipleToolComponent? multiple = n if (multiple.Entries.Length == 0) return false; - multiple.CurrentEntry = (uint) ((multiple.CurrentEntry + 1) % multiple.Entries.Length); + multiple.CurrentEntry = (uint)((multiple.CurrentEntry + 1) % multiple.Entries.Length); SetMultipleTool(uid, multiple, playSound: true, user: user); return true; @@ -79,6 +80,19 @@ public virtual void SetMultipleTool(EntityUid uid, tool.UseSound = current.Sound; tool.Qualities = current.Behavior; + // TODO: Replace this with a better solution later + if (TryComp(uid, out var pcomp)) + { + if (current.Behavior.Contains("Prying")) + { + pcomp.Enabled = true; + } + else + { + pcomp.Enabled = false; + } + } + if (playSound && current.ChangeSound != null) _audioSystem.PlayPredicted(current.ChangeSound, uid, user); diff --git a/Resources/Prototypes/Entities/Debugging/spanisharmyknife.yml b/Resources/Prototypes/Entities/Debugging/spanisharmyknife.yml index 66e2b35ad81..94464f2535d 100644 --- a/Resources/Prototypes/Entities/Debugging/spanisharmyknife.yml +++ b/Resources/Prototypes/Entities/Debugging/spanisharmyknife.yml @@ -24,6 +24,7 @@ - type: Tool qualities: - Prying + - type: Prying - type: MultipleTool statusShowBehavior: true entries: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index 47ea55278fb..9831d20e27a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -25,6 +25,11 @@ speed: 1.5 qualities: - Prying + - type: Prying + pryPowered: !type:Bool + true + force: !type:Bool + true useSound: path: /Audio/Items/crowbar.ogg - type: Reactive diff --git a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml index d500ef141c3..24eb0b02b24 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: haycutters parent: BaseItem id: Haycutters @@ -98,6 +98,7 @@ path: /Audio/Items/crowbar.ogg speed: 0.05 - type: TilePrying + - type: Prying - type: entity name: mooltitool diff --git a/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml b/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml index a7f74a542f4..36f96f61af8 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jaws_of_life.yml @@ -24,6 +24,12 @@ - Prying speed: 1.5 useSound: /Audio/Items/jaws_pry.ogg + - type: Prying + pryPowered: !type:Bool + true + force: !type:Bool + true + useSound: /Audio/Items/jaws_pry.ogg - type: ToolForcePowered - type: MultipleTool statusShowBehavior: true @@ -77,4 +83,4 @@ - type: MeleeWeapon damage: types: - Blunt: 14 \ No newline at end of file + Blunt: 14 diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index 3d58b2b079d..82bef616de4 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -155,6 +155,7 @@ Steel: 100 - type: StaticPrice price: 22 + - type: Prying - type: entity parent: Crowbar diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml index cb6f8627450..764683183d9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml @@ -20,3 +20,4 @@ - type: Tool qualities: - Prying + - type: Prying diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml index 9e747328f94..fcc2129a51f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml @@ -38,6 +38,7 @@ - Prying - type: TilePrying advanced: true + - type: Prying - type: entity id: FireAxeFlaming diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml index d182d9a00e9..3073ed7ab53 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml @@ -61,6 +61,7 @@ - type: Tool qualities: - Prying + - type: Prying - type: entity name: crusher dagger diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/easy_pry.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/easy_pry.yml new file mode 100644 index 00000000000..04a58eebe07 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/easy_pry.yml @@ -0,0 +1,63 @@ +- type: entity + parent: AirlockExternal + id: AirlockExternalEasyPry + suffix: External, EasyPry + description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockExternalGlass + id: AirlockExternalGlassEasyPry + suffix: External, Glass, EasyPry + description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockGlassShuttle + id: AirlockGlassShuttleEasyPry + suffix: EasyPry, Docking + description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockShuttle + id: AirlockShuttleEasyPry + suffix: EasyPry, Docking + description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockExternalLocked + id: AirlockExternalEasyPryLocked + suffix: External, EasyPry, Locked + description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockExternalGlassLocked + id: AirlockExternalGlassEasyPryLocked + suffix: External, Glass, EasyPry, Locked + description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockExternalGlassShuttleLocked + id: AirlockGlassShuttleEasyPryLocked + suffix: EasyPry, Docking, Locked + description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered + +- type: entity + parent: AirlockExternalShuttleLocked + id: AirlockShuttleEasyPryLocked + suffix: EasyPry, Docking, Locked + description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN" + components: + - type: PryUnpowered From 9160e8893bf5acd9dd5a6f4698579771ea90d15f Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 07:35:26 -0400 Subject: [PATCH 18/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ba68c124913..c15e4150cb5 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: deltanedas - changes: - - {message: 'Added the gateway, currently for admins to teleport you to funny places.', - type: Add} - id: 4411 - time: '2023-08-02T09:47:18.0000000+00:00' - author: Nimfar11 changes: - {message: Adds a magazine for the C20R to the uplink for 3 TC., type: Add} @@ -2968,3 +2962,9 @@ Entries: - {message: Pun Pun now showing on crew monitoring., type: Fix} id: 4910 time: '2023-09-28T10:53:54.0000000+00:00' +- author: nikthechampiongr + changes: + - {message: Mappers can now place airlocks that can be pried open while unpowered + without tools., type: Add} + id: 4911 + time: '2023-09-28T11:34:22.0000000+00:00' From 95fcd7def05244749d140a92de83e01665992833 Mon Sep 17 00:00:00 2001 From: Doru991 <75124791+Doru991@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:00:18 +0300 Subject: [PATCH 19/98] Make arcades hackable again (#20555) --- .../Recipes/Construction/Graphs/machines/computer.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/machines/computer.yml b/Resources/Prototypes/Recipes/Construction/Graphs/machines/computer.yml index c0736c4973e..6bbbd4f2fff 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/machines/computer.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/machines/computer.yml @@ -124,6 +124,8 @@ entity: !type:BoardNodeEntity { container: board } edges: - to: monitorUnsecured + conditions: + - !type:AllWiresCut {} steps: - tool: Screwing From 3ca23a781b54235a4554639b6bd295a8cbb34146 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 10:01:23 -0400 Subject: [PATCH 20/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c15e4150cb5..ffb5997c8dd 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Nimfar11 - changes: - - {message: Adds a magazine for the C20R to the uplink for 3 TC., type: Add} - id: 4412 - time: '2023-08-02T10:03:39.0000000+00:00' - author: Nimfar changes: - {message: 'Adds a new theft target for the Syndicate, Emergency Security Orders @@ -2968,3 +2963,8 @@ Entries: without tools., type: Add} id: 4911 time: '2023-09-28T11:34:22.0000000+00:00' +- author: Doru991 + changes: + - {message: Arcade machine maintenance panels can be opened again., type: Fix} + id: 4912 + time: '2023-09-28T14:00:19.0000000+00:00' From 4afb83e7ac2cfbe64b260a0f667f1e39fb6492c5 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:05:42 -0400 Subject: [PATCH 21/98] Health alert tweaks (#20557) --- .../Mobs/Systems/MobThresholdSystem.cs | 94 +++++++++++------- .../Alerts/human_alive.rsi/health0.png | Bin 2153 -> 2177 bytes .../Alerts/human_alive.rsi/health1.png | Bin 2155 -> 2267 bytes .../Alerts/human_alive.rsi/health2.png | Bin 2152 -> 2249 bytes .../Alerts/human_alive.rsi/health3.png | Bin 2207 -> 2331 bytes .../Alerts/human_alive.rsi/health4.png | Bin 2269 -> 2401 bytes 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs index 1cb32543ebb..f34240d8fe3 100644 --- a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs +++ b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs @@ -5,7 +5,6 @@ using Content.Shared.FixedPoint; using Content.Shared.Mobs.Components; using Robust.Shared.GameStates; -using Robust.Shared.Utility; namespace Content.Shared.Mobs.Systems; @@ -52,6 +51,38 @@ private void OnHandleState(EntityUid uid, MobThresholdsComponent component, ref #region Public API + /// + /// Gets the next available state for a mob. + /// + /// Target entity + /// Supplied MobState + /// The following MobState. Can be null if there isn't one. + /// Threshold Component Owned by the target + /// True if the next mob state exists + public bool TryGetNextState( + EntityUid target, + MobState mobState, + [NotNullWhen(true)] out MobState? nextState, + MobThresholdsComponent? thresholdsComponent = null) + { + nextState = null; + if (!Resolve(target, ref thresholdsComponent)) + return false; + + MobState? min = null; + foreach (var state in thresholdsComponent.Thresholds.Values) + { + if (state <= mobState) + continue; + + if (min == null || state < min) + min = state; + } + + nextState = min; + return nextState != null; + } + /// /// Get the Damage Threshold for the appropriate state if it exists /// @@ -261,7 +292,7 @@ public void SetMobStateThreshold(EntityUid target, FixedPoint2 damage, MobState threshold.Thresholds.Remove(damageThreshold); } threshold.Thresholds[damage] = mobState; - Dirty(threshold); + Dirty(target, threshold); VerifyThresholds(target, threshold); } @@ -291,7 +322,7 @@ public void SetAllowRevives(EntityUid uid, bool val, MobThresholdsComponent? com if (!Resolve(uid, ref component, false)) return; component.AllowRevives = val; - Dirty(component); + Dirty(uid, component); VerifyThresholds(uid, component); } @@ -344,42 +375,37 @@ private void UpdateAlerts(EntityUid target, MobState currentMobState, MobThresho if (!threshold.TriggersAlerts) return; - var dict = threshold.StateAlertDict; - var healthAlert = AlertType.HumanHealth; - var critAlert = AlertType.HumanCrit; - var deadAlert = AlertType.HumanDead; + if (!threshold.StateAlertDict.TryGetValue(currentMobState, out var currentAlert)) + { + Log.Error($"No alert alert for mob state {currentMobState} for entity {ToPrettyString(target)}"); + return; + } - dict.TryGetValue(MobState.Alive, out healthAlert); - dict.TryGetValue(MobState.Critical, out critAlert); - dict.TryGetValue(MobState.Dead, out deadAlert); + if (!_alerts.TryGet(currentAlert, out var alertPrototype)) + { + Log.Error($"Invalid alert type {currentAlert}"); + return; + } - switch (currentMobState) + if (alertPrototype.SupportsSeverity) { - case MobState.Alive: + var severity = _alerts.GetMinSeverity(currentAlert); + if (TryGetNextState(target, currentMobState, out var nextState, threshold) && + TryGetPercentageForState(target, nextState.Value, damageable.TotalDamage, out var percentage)) { - var severity = _alerts.GetMinSeverity(healthAlert); - if (TryGetIncapPercentage(target, damageable.TotalDamage, out var percentage)) - { - severity = (short) MathF.Floor(percentage.Value.Float() * - _alerts.GetSeverityRange(healthAlert)); - severity += _alerts.GetMinSeverity(healthAlert); - } - _alerts.ShowAlert(target, healthAlert, severity); - break; - } - case MobState.Critical: - { - _alerts.ShowAlert(target, critAlert); - break; - } - case MobState.Dead: - { - _alerts.ShowAlert(target, deadAlert); - break; + percentage = FixedPoint2.Clamp(percentage.Value, 0, 1); + + severity = (short) MathF.Round( + MathHelper.Lerp( + _alerts.GetMinSeverity(currentAlert), + _alerts.GetMaxSeverity(currentAlert), + percentage.Value.Float())); } - case MobState.Invalid: - default: - throw new ArgumentOutOfRangeException(nameof(currentMobState), currentMobState, null); + _alerts.ShowAlert(target, currentAlert, severity); + } + else + { + _alerts.ShowAlert(target, currentAlert); } } diff --git a/Resources/Textures/Interface/Alerts/human_alive.rsi/health0.png b/Resources/Textures/Interface/Alerts/human_alive.rsi/health0.png index cce1b027b6101b060904679943dcbe32610f9910..6c9b54e52e29d1909a41d0562da1efb4eba88035 100644 GIT binary patch literal 2177 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 diff --git a/Resources/Textures/Interface/Alerts/human_alive.rsi/health1.png b/Resources/Textures/Interface/Alerts/human_alive.rsi/health1.png index 2ec0eb65515ba5b665988c0d2333bb717e256065..186d07386ec845d1b7f0e5174546f06f38cda0e6 100644 GIT binary patch literal 2267 zcmX|?4LH+lAIB}8Mi=HBN#6RGo)UG`$;w-{aws}X7e|Mz|Wuiy7`f4_I;DbxwQO{SYP zG&J-)J=}a%W2Ne8*WRe=Q=G%&RRiRP?+I58YM=S6hK4rD)9sl5Z)JjVWVo5<=5&go zQPhU04IAuj$M-|-e1Hei{V$%{X`sy{S)MwF6W}!8EWng4_rIunh{SG%vVVIM)}pU}=(Ax^0A(Bz^(*bjOkv z*WvdWqdy%|Rwon`ajP;i;8VWjfsxv-X3n#^+y?nAy;~NoQJe>i0yv7B-R70|@w&_= zxI_>lyMp`I3LWeyICr0T^E%es?NS5U2dCgU^@y-TlWfLv?m+1NljK160vQvipj_U1 z>Ybwm6MJCTJvO*-===%M$#jwyYOXY`Hm7(b7`Nnz@G(UBJf32775}Ir}2A(HLKuaLXG<*tc&9z{eTjEb-(@m^Vk+g1OjpJ;>hqQOc5U2NxY?8#{W4-EEA2L)#E`lNWppEKLGRhkYt?iFBA@=2O!FE{l#HK*|o(<)dC(h!6u?lffx4{eQ7Jr>Q~pY-|n@83g78 zD0hv2!!JW`1&miZk94OP7UT%TmwFn!J}H`BmHT&9zRucn25*+rESx(l<;Inn+fPvw z=)woPZ%$!DqMW&L*;MbflTG2Au}lx%J4RjZQoSHvCb#cw{y_X)PCeccj~Ejle$mQB z3^ymz6px(_gJ1uHOz==NhICbN1Y8O)TUqXdlq8AK;67%O4Nvnc?FI7N{J>(JN@W{V zx8$byJ+uROrUsshKPs;!2q8;#Qb(;68~FC8u88e~IOIBw_Q^+y7F!ibpr9^%X*I|m z@cCPbGk>96NU$etd8h(-z{-;{nabz&K)sfAaF~*kjC`;+Z*|E|<%=;r2YPN9k7=~@ zpuNHX=m^K_I~ugSa8P&r z@Z_vN&pP;v)0+Jn=v&1U;2qdn&s$o?B+*N&O;_GZgG&{UgRj8$IGvwVI#3HYjvv zHnrLJibE2yLEDtWVLGEq+`d!=rs8r*@@Fg8;Ft2RC4X)P_rHIu_xbnS+lcb_&-4cw zefj$Rz)D<%co5XkFtXy|o#ZO0u+OZ6y6d>m|G@sAr_{RAfpvfri=W!`b%`$WS3?j1 ztA@VEGLM5t84>>i_qnaZF5C;8a;Dh!TCFSvGAY+K^ldAb?1+v9l0&ALQ`4Rt8qV^R zF>(QN%xL|H_|0fiJL@y&PJZqRymUR7LF*o^6(_dt@|i?XUKWsG#|I9g-sz3n`oL$42<|4 z-%jVTCx=%X4fJaJlPXVA@$F7i>KAIO$n{PashH9UyZ^Btn!&~&#iVP=S67``&=ukK z30l4KDQLaz$^D~80Ne8kT+)(n_>B{`Wvwn!D|eD3n3foq%^2b^Xt@VL&$!>-L*cZf zpnbBacvKmn?2(G^?6Pn-4SD=pVyQ+A+hPv;qu>FV#_R7>lq_ zhXItY{<>~Z%6dTPzp31$r@db6IBdPNXmL0Ox`ocL^*;-bBlidaIlxCY-?l5I!CeO{x7*c$L~iBa1Q|o^sKDcmS%kv zrvowxIzO+ci-B;(sPSJJiq5B`V-v0Dy<+Mm{06|IQXI(fRI+^DXh$^QkAkdG4p literal 2155 zcmbVOX;4#H7ETNbE|3gOfdVF=(;|%`Dq;Z53vTRaqk_sNEsJ17fg&ziutoMT5Z-UCwennXFruGChv6a5$sp`M_VdGqS+p3|4#Y zaXXY!AT8W{!NPqd$7T=5qG{VX!gl+Ci)^){ZOC0`CX2~@oSYho9H%l*c(5V`j#I>D zh5dkmUd)OZ6tw9nqx8JTwb z?#KCqoSD*fwTD``Z>J@r+e_NQ5k_G5P)o1(ElkQKWfxhB2LPk$cSq0_W&S6Rrxe=x4O;L;OB&kl4ziglnPtQK0fX*E(w4~z{_y%3wT zDzm;CmAr*u$Y}uV0e(2$>jv)GL?9au#r*I-y*BHYY7x}6jV)l1b(={-rpbS!^7&$1 zzj>2FNIX)3&7gIn^sz12?`oOU9%XX{TQUqzuyL6t2;NREno*@Ct?~zjAp+j=DEjzI zKCr3jqD}PCqKhD1ll7Qd$hFj8^Fl`h*nkJ^4n6R*xDMsTokpr2pX{P+?dSCq$Hxi} zp^3DCN=>xPtX35u=`pF#(e}1&KLu}u)Jk|q*j$`tAR|BqKT4j9{`yx+yEySMPzX;{ zmcUb+b3X>n+VAIaa!X)i5Ni*#o+R&H3Ug#gp}KBjfcV%;DfN?Hox{5FV1Ml>^#x;y1#=zpu#w7^SEJMo8FuhXdR{H$x^YxxB1swNnSNp*bvYn{pY}!z&f{(6 zgyB47;twbvyINVERvwmW^|Lalgfl~r zm`gA}ZF#{#r-X$kwxVp>fT&8^F@mt$OH)Qz+D55W6$`eDeBZ99d0*Pliie6TdqLWrn|I+LIYM!wl0vBSr0{ z5jWtQp>BA>Sv?!K-D=K!%~{mO7Ubc_f~q68`~cFcNdd^yy-E@qYV89QvxCjP?Oj~Q z{IN^BK#D0whQ1)yYsKoz& z#QnkV0{QwX!svUh#e0>wVz^q=X1rqFmUM)bPw~CyI5e$`CM&98gs)seVArn*&15N> z45MzV?1*~LhUeANPSnX}|CGLbA}OS+>w#~Dpzjc*OUE>2NuK`b?i=q)!3G-2BsX5U zMh1!J8nL-+Zx|^ChqY%8d~xgVJ7YSDW1{rKM|32-tQaJYB`TT~QvNAK^pm&bxkvMe zTb!h)Ror12dp&6|yeA``;=Lm~7_3v=eHwK&x|{mS-Z)L~3zW9iX}@qAs_l8UIVRsP ze}#<8a!DKhK`#7V+>olGE<-3`|B9-w54l`2`$0x__o@sCgIG(HMXfE8TVoUY^1+k3 zhHV4Cf)|3e4RJOk_&?BdC^~CWj!sY7gnwNP>;{T!c=30XytjM`33~JwvCb~z8NqM< z12gpw=%P6WY}H{-Zdi<_%ueWkC%8=^!JWKElwUe?*w7R0B+5Rk9?EF|j$!dAJHLJv z#$Y|UZDtQ7M#;)Ls5{}^ zOzow$-oWvfXyWW6(65P|y8|EGewiEANj#DctOl!iIz#ja)C&{o^WOXC;F`Bs#br*c z8V_ewDll!Eq4f)#x5NBcD-(e9An-aE1X>ey_FC2lHk3eow^XZ{fe3Rdsdu%`0(Jq% zztrCM_XUbK)h3;K&ggdfQrFsjRU6?D5veip?zq0Zz049#GhiV*6K&mLa%1NhP5z6i zRNrUl`DwM2DNU7XAZdAd>wa6zPcYV3e~Hs}mfSd-z>0e3=bX-2MB0>= z1C~ig++P#NAMymUhhm!MM3&IOD$)dHPfzl#iqK+;oDeWcA?Wf{_3FWd|`t7;5>v-nB0oqL(2><{9 diff --git a/Resources/Textures/Interface/Alerts/human_alive.rsi/health2.png b/Resources/Textures/Interface/Alerts/human_alive.rsi/health2.png index 4fa9ffeccc324cbd18cd79aa7fa5c8a5a9a8ad4f..6463eb386facd0e5a56bcbca291eb2ecfbf5248d 100644 GIT binary patch literal 2249 zcmbVNdpy(YAD>HSatViWYpo&*S-BL$=3dm<${{MO`bA3U9M_Yz$xg(nMycgGDR&{t zkbE&Un!CzzkC9x)n6TS-zp3B(}o zu1B5RB{oMg8s&bH%p~i;D2b5@b3ft$DeK%m1A)kqT%GJaqBGf92eCS?n(^r5t$8(Z zangCY4yTG!Z#U;AVZ6Lk_dYagLD;q4y5*Cj20%{MCb?((Jn=Xs@04bE=H$sI>OGsY z+`acr7`6Y+@@HrHF0TJ4D!bsI0v$!|ud2#^Avz-~c~%mM;!B-xsstgkGTRGedp(O( z;dn8qB{I_Ln_wy)ZNpL>oRUr86`q!q{lj4xhh0(^h*EurQ$p+RESwmY^1WWyRi#R_ z5Mf~5ervo{qx-b-S%smC`=yCBU^)}6S;U-YFzg#~zT&~AvS)_~f?|_tT&{&c@pkCY zC6^wiEJ{Qz3!UP0`Pvc}qlNTSK_M`d=#5!Qzs_0K-Mgd~B%UASO23@RMf9ZC1|Oc) zt+Fi-?zxnMCDI1m>YtUi6V0Rfmk-dkP{F^#VuF&r6R_f8SnWB4TYA-nG|{+nSC^?` zq5Dzj2TK8mrI9jQk5D37i6D?Y0hZhE#nZ=Icet^DD%yiV7K2KOP)%77MD_B7o_BHt z;K=cttC96LRGmL7_ix-%X|j7`t8Q`33Y%9|jkr!+FJV!A;;QD`8G9ha#{`q69C?^Z zc$?`a+K`6DRtCHp{sZOhfnBj2FFF>rli-O~=-D{su?wyO6jN3I?GOXR1#?5q!buq< z-&&MiCcc8}CoWkQJsrBb^@{<#TPm#EQ*=aT#)r*3AM~4&pHPF`YdetK`H^sCsGS!} z?(f4l{$cf719#@CzJ+&0c*g!vucbs1vpz=Zz29o z_zp?z?>V+I&F~6fq>vm>rd{ddL_S4nyD*ADM$qO#V$A6~XtBe}+Gu46#BcLWdLGad#k@csqH}H*d{8~Q zgm{m8uc}h)Sj&~7ov8!22Xne6GL-}4&px=9`r+LrlrPuOyofGqn6^^p$(~CMB zF)(m!iMZ&$+CQJA|D64S#=u%Ks9J?&%phgAX$JXH2zQbWn>Vly=EH-<(PJpl67niA zBdcFr8ukkDyI!qmNszvxS=viop}o#1V4R)RRb`_8u*vsw>EC(Mk-ZRr%p4uD3GJqM zqcYVq$dt)D;*gKv`WT)+wd)H$dbH)Oc!nRTUt?O1E_#%PZ^>O0n@Y&t(^Ph6OJsx} z1-}_QA6~l9f8BSuUjNMGuaorU*} z;0L~`E$?VTHwZo7cF8>^ef4`CH=F!gCcX6M=LXICC3+rWKB)n?ohT=f7WV~7-Q=xV zPs^l_k2*ypw(A?c(qa9n2ZuKKMfI+V32JS8$KO%e<*hzmKzV@^N`&FXcJi+6zA({T zsh$#F+hSc(jYwk06lQ>TEnlsZnV_aRvl3%AllRv(UPI!ygv&e5 z>!p;QC4?nl2UEhy@7M-7R>eoR=ei|h+YwYdja7@E6=uCZ0aY4_MRYyNpnbO4 zxc%k`<0)*7>BvZ{-chrLMc4hOV6UEyn`1uVEiYHQ=o=q=xQQ2@2*#6$rqWyVUTrBS z(BqK!^-C@}O%q5PzMu<4J|0G{k)2=aFsJGJ=YTiruNHqX19KY=?FfTQRML7@ct)5|l*eY_v-PFfK}t8fI| z@~j>C30Cj8K{)X% zuSE8Lx?SWif(o8SYX=I*;Qb!u9v msZZPnO~2-5DQncB!$GLxlg!ej$jY*fQgL<0IF&h^i~BETrgA#~ literal 2152 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 XPo2HGQNQlwHz;1XBOW#GL0A3;FXX>} literal 2207 zcmbW3c~BEs9>(}3U?~nKT z`}uu;opbO2)yl%b0)xR=1^Dj@G|eTZ!6Pm6M=?JyJhMX!-`iM}B;WBq zHT2z<&1e#07t3uT{1_;XsE%?;n2Ok^5Xd-J?lzOt0)9+>(bv>;RvR54HA*`6f0&JV(tK|pYPf#1f^j6C;7}j57V+fDljVi|M%6e< z;o7q`G%1uCjW$^4eE)nCb+7T%lymbxj1SUMG8~Gm0rscFUt7q zDr~1}u9e;doWuC3@$Sv^VgR-%Pmzpy^z=B}mf8B``(k!lVDaww|0G`9T%}KQDYj5Q z4R8S~INmP)rN1iB#}Ei0EbV;|#?ITQi+tVsD(rAD7DthYIL5Dnx$=0_6WS8omDz1f zWh4$goFrON5Y`QYI-n4S!XB&38Q-m@(rtY_!0u?Z>~?bN zum=i^ni^w?$|#bwG-@l5b~Ymjz$fEEe4RW1}U?7q9~QZi)U2A( zb;PY3#EwnTwUI$UNr0a35qUFWjVw6ahPl`H(+cJdgmtaDIs%s7>Xa`mGpzO?K3C(0 zACY1!c$@c@BN3~?;q#^Q4NF@NP7&HDiyB-ky+3ttpeVGL2R>W*p(>sdg4^`ZZY2+XIU8D3i*Yv`5{Fk!SZ*$0e%T?mxokhq_#^QRjGevKv`wG< zL0RjB#Hq8@?9@r6z8kF{$={;euT>X zl1Jd@7CuW8_TQrF(Nkf*?~^XuF8 z6<@Wet-|*L1L#IgZicNUEa{; zVw;cU@)r|{1Jw7Pl|B3Ksf0&QXNn(zt{`Y{88}XedDguB)laZ?gQLi?RGc5BnjgE} z?zv+5rqe*l6fJ9qmTGwQx*TnRb^ZUUz5m0u8fD*@0KTWf)e_p5pcl=~x0i#wJFrv{ zg?tTTC5z>U_RV6W6Z6llJkPN;oYvh_;wCXnwy7?7NA>3YI}w(AtBKhG}5Ren6;|ID%knp(V%>gyjis zrW$3U$zGwF%`SdA2+|7}4OBS1xJqhhDrolPhxgIeK@96mF+0NyE%PSm(*T#l(tc1s z$2Y}lW6Vwb2Ep{igwKqp)407FxBO>XHeL2Hb^oWR4k?G0PZ6A?5DAV-2YLSJzEbGa zATFH*W2st?Omw(}vLT)0lba3lZlr`H?N{u$YN)ZTp*(H_>q7>8F0R;U31gSe3oH;; zTHeXvI@jz_Um>j*b07Ez#mbu*2oD;(VV(1bt!pct$6i2gDPVJ zImk^WJWfd}N0a%uy}*fZblAVwCL|CDwSYnqA{{VC@2VxE zW4W4%Cvc`8aAG&Qtd#P2BlGNIQ+NLT&eU#Xb%{6@$a6c>9|tC2_kmrHd{3nR6N5`! A6951J diff --git a/Resources/Textures/Interface/Alerts/human_alive.rsi/health4.png b/Resources/Textures/Interface/Alerts/human_alive.rsi/health4.png index ea55a429b2415d560556620a05de0fe6a5b3b640..9ae49ead79fb7cec528dcbaf4ab1b9b43a2d45e8 100644 GIT binary patch literal 2401 zcma)7X;4$i8U;~SHEv_{1<PP|hfbBBD6CfS@uWn*xH$GN7Uc!wv%^H-IP#iYy9( z5R}0vDly6y7Hb2+$7 z|6lqV8XC)-4mo%ra|zO!y4uK?ViOXJOq!7%2kkW~x(vrOH1se|4tB@l?uv^x5d??U z*+Lci_mh*{2~C44y(I+HWNjQf~4oa|{iXA8Xs)_YJU^!_Ghs#nzwR$wqh3X2h5BLd- zOo(6gKud_bI4bsqx}ifDe!5}phV$=a?c;!yk#*~K#%AL@ZL-{#1KsT$au*TMpD3rXK(Nn3S)_3`&8yxb_qy=|bpt*yy0(Uf zar+|PPXV+dN8`wUo=YA6cxtb;!8x&-VY{Ur+- zE+zIXgDT3XC5!FL4o{q6pK({Uh8xOWWZ*W! zQL3t?bk{5XTsFeFK7vIsBON1efoBo6-+gNyaOJsTS0ESP zAwHkp|71m7iA*l6t`upx5H1d7vP@^|S&FLT>t2KdZ)pP{HVeE-WX^pj&7c}H(JWx- zCsx2bx!&vADu#uK)VYg39_y`p4lw=cyXc4!REBxaWeR;nG4ees1mP2d2b*mo^_v$1@e>?VtUNkvFZ<23gv)8uahvYsj zhLS~(tz%TtPLvAk8?+mI7gjzzXnj&$KOP(ZN2rRQIjiaDP*JXI!<$qcCVVr;q>qE0 zk#dnNQ><$w*77s*DH`z@)hehZHtd+nL^PT@20A{oSP!;d$`H~{2VUk%j*6$Ksp&B{jul z&!^cH&z@!Mr-{xFYS48nXWh-!KsXAvy1-_1CV6ym+QKOQ9Yqd?RSBYlwYR{VO1Bxh# z3-){c*0+-Soo8MIz|TXA%S~HYc*w^1%}3=utE(cV=jspA?xBSwJarFc`rO>uh_`Z2 znQQEGwQzH-`cXenZM>tAv69jF^a&$ouqHP{a7;~?3pQ-J^L9i>VEz4%%e7}&W^Zxr zr%lP2u*z1KNnDZ65oLAvm;Y=|yvDCcQVhmkc&@W$K$ldny;VUx%A!g&uSZZ&pa<-` zc35zD@viwO^)!bhaR?~>NAcwz1wHr z5p$`)5S$^A&xA+^rl?{>D#V|E8X#`|Kk0th7V$CXM}{H$03#4PA0>-ciFg{a=^Fd_ zN{mu(9(`sXaj&ut4j?kAwiLToBuife+TQXaGA-s7q)(aEY@a3fPk!ddFS=2-kRDh( z=3QG#rPU>|Rx)@T-biGcF##7S78~|t;Up3b7w{H$7Zs|yXQg*pgqq7XSGuVNsYN#@(kxSO{kF=WR9wkO#6*vH6I=K)NS%MRN5{~f(xqcF z_PSbLZt~|Oz3C&Hp5CXkwZ2c>q7qwlyd$A0y=e*UYPTsYZ)M=Yvf_Rs^MUy-?+qy# zW72z9p|QhN!^Mf%5|s6J;N$id+^GLci;J1^L%0>QW*zN#3sg_qaiJbQpZe#nMY%>Kqp+ NadLEVsIU)6{x6GD9+3b5 literal 2269 zcmai0do+~m8lOSNmNE9qilT-sNww2XnNoZ%U5whMP1&`CZYRnX%BC9geUnS-NJ=hU z%%vhk$P`g#=t3%ubHpf@8KE-G6>~8&-#2Gy?X&k;XSMbp&--&+qsA-uK-0 zpeNNqmvEOckuzckE2kQ&!!EXzs%AOg)++_ZuH%8 zqDV}0jI$%6GU{_nDvT^hvCTue^bb@)^PMF%=4G$eaGMqW{lAcm?r=XkbJJRo(YKQx_s~v#`c=39t$pag&9($e2~HJnj!(-`uLKM3aE7h0A{cif!>=tVnz?N+uqEBJ%n`tAI> zY^M@vCvZ?Pd4FD7oV_c|V#k=M8eNHz zJ_RVyThy7#?}AgIQ^;p`<}vP5zzc|(DVO1ROFK}`3)Mw(l$CaU;-A=7mDF@ zH{9W)i<84fWO0w_3Azu}g=kl}BSH7E+CKnrK=$iqqMurBTil5|8!0TsTXEi!W^!KR z5a4J?7L{skWEO1pSEm*uBWJ@?JFy6?jKVVW^?GHjqOCsei*_Bs2pO1&VxY787nn@% z;+U82L~NK|!!oZ*I_}4eHt-zO$y`Pgeq~QqYvdUy9$>=s$~%lVASrZ|z+aq5(|&}` zj^IHvcEi*^d_u&f%bxR#tZKD(bNrUSD1}T1DX7y*a0- zsL2FM`1Z(Z+AcYKS%lF^HI1iW`K{N|+S!OJ$?UQib3femW9aF_dE2!e+e98=WjaZE zr;P!_EiFN26w=1q1Gp1O%6|N`ce2OWERH>#sN7Tm;}$}Fmb-KL>C%VF>wSkP zd-~F?`f(?ukIS66#yvdpM>j(Tm5Nl>HT|GX?`EEq)!@|oR9`KCZnGH4<9A1+Igikcc3&%?F z@s*t6%IXvPlz!z5sNATQ|6^_?+V}5hZ=eT1@++^*61cJpY>N zl|Q+#7Z^bide{fBx#|0o3HtB}Bggl_OOskSOJ3kh@bNb0cKJwnuVXiI!@`m&Ub@a& z(eci2n8;6=F4p^^IWvDoNWSvzL$d*mc!qnj7+6{pn8jsG)UdMP6z9i? z0Q9*o@y?`OffKV(5Uar}gTvj2fr>#N?QQMc>k`k-Nt5b`M&W*C*E^em(d6Bp(0Zo= zezKBR=ij@E6tb{*ywCZUKq$;%Am(x(ojmtgAZ74#rhBh8Jc@ZhGqzb9cl4`F}# z2^s;J=(q5}B@fB@B)0u7P!5NJP0splpUbEwhXQd-91##iag8U zruqizP(8C>S8OA5aI8*>wFcX82#-Hnp5pu=zDk6#hTA){p=O3fw$LV`hJN#_Bz;@Q z{^;gu=v2I~9sOV3LJX`fnd}KWuJuoxx!Ewj=#TG)$@^XeHr)L_j7Q0l)A#?eNdlWPPph(0Sd>2zYqF9j z8XgW15sHRwl*U1o(=q*>iv5qI8JzY(oNX3GRcHiLjp0H+h}emMD~&C0+oa`^#f;^Tinf^Xng%1(+zJ)df} zMn59H$F0o(8?Ao(oZ?~^dpgnok+?zS#cbE2DV${T2ezrjsye>&h)(fD9_gVAk7_P* zjElN0YIC>8Sga}m(!CLOrtmo(lLt1Ro7(C`1O$1Sv0$}Wv_;)G#M*l?cM Date: Thu, 28 Sep 2023 10:06:46 -0400 Subject: [PATCH 22/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ffb5997c8dd..27c9f44af43 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: Nimfar - changes: - - {message: 'Adds a new theft target for the Syndicate, Emergency Security Orders - from the HoS.', type: Add} - id: 4413 - time: '2023-08-02T10:05:12.0000000+00:00' - author: Bhijn and Myr changes: - {message: 'Interaction outlines now directly react to lighting. You can no longer @@ -2968,3 +2962,9 @@ Entries: - {message: Arcade machine maintenance panels can be opened again., type: Fix} id: 4912 time: '2023-09-28T14:00:19.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: The health alerts now have text to help discern how gravely injured + you are., type: Tweak} + id: 4913 + time: '2023-09-28T14:05:42.0000000+00:00' From 8778e13a23a6d50101e8e037f7d01bfe722cc185 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 07:48:59 -0700 Subject: [PATCH 23/98] Add active and ended game rule components, generic TryRoundStartAttempt and minPlayers field (#20564) * Improve active game rule querying, add generic try round start attempt method, move minPlayers to GameRuleComponent * Nukeops todo and cleanup * Remove Active field * Add EndedGameRuleComponent --- .../GameTicking/GameTicker.GameRule.cs | 23 ++--- .../Components/ActiveGameRuleComponent.cs | 10 ++ .../Components/EndedGameRuleComponent.cs | 10 ++ .../Rules/Components/GameRuleComponent.cs | 16 +--- .../Rules/Components/NukeopsRuleComponent.cs | 96 +++++++++---------- .../GameTicking/Rules/GameRuleSystem.cs | 33 +++++++ .../GameTicking/Rules/NukeopsRuleSystem.cs | 30 +++--- 7 files changed, 132 insertions(+), 86 deletions(-) create mode 100644 Content.Server/GameTicking/Rules/Components/ActiveGameRuleComponent.cs create mode 100644 Content.Server/GameTicking/Rules/Components/EndedGameRuleComponent.cs diff --git a/Content.Server/GameTicking/GameTicker.GameRule.cs b/Content.Server/GameTicking/GameTicker.GameRule.cs index 82e2872914e..c04b8d67116 100644 --- a/Content.Server/GameTicking/GameTicker.GameRule.cs +++ b/Content.Server/GameTicking/GameTicker.GameRule.cs @@ -94,7 +94,7 @@ public bool StartGameRule(EntityUid ruleEntity, GameRuleComponent? ruleData = nu ruleData ??= EnsureComp(ruleEntity); // can't start an already active rule - if (ruleData.Active || ruleData.Ended) + if (HasComp(ruleEntity) || HasComp(ruleEntity)) return false; if (MetaData(ruleEntity).EntityPrototype?.ID is not { } id) // you really fucked up @@ -103,8 +103,9 @@ public bool StartGameRule(EntityUid ruleEntity, GameRuleComponent? ruleData = nu _allPreviousGameRules.Add((RoundDuration(), id)); _sawmill.Info($"Started game rule {ToPrettyString(ruleEntity)}"); - ruleData.Active = true; + EnsureComp(ruleEntity); ruleData.ActivatedAt = _gameTiming.CurTime; + var ev = new GameRuleStartedEvent(ruleEntity, id); RaiseLocalEvent(ruleEntity, ref ev, true); return true; @@ -120,14 +121,15 @@ public bool EndGameRule(EntityUid ruleEntity, GameRuleComponent? ruleData = null return false; // don't end it multiple times - if (ruleData.Ended) + if (HasComp(ruleEntity)) return false; if (MetaData(ruleEntity).EntityPrototype?.ID is not { } id) // you really fucked up return false; - ruleData.Active = false; - ruleData.Ended = true; + RemComp(ruleEntity); + EnsureComp(ruleEntity); + _sawmill.Info($"Ended game rule {ToPrettyString(ruleEntity)}"); var ev = new GameRuleEndedEvent(ruleEntity, id); @@ -137,7 +139,7 @@ public bool EndGameRule(EntityUid ruleEntity, GameRuleComponent? ruleData = null public bool IsGameRuleAdded(EntityUid ruleEntity, GameRuleComponent? component = null) { - return Resolve(ruleEntity, ref component) && !component.Ended; + return Resolve(ruleEntity, ref component) && !HasComp(ruleEntity); } public bool IsGameRuleAdded(string rule) @@ -153,7 +155,7 @@ public bool IsGameRuleAdded(string rule) public bool IsGameRuleActive(EntityUid ruleEntity, GameRuleComponent? component = null) { - return Resolve(ruleEntity, ref component) && component.Active; + return Resolve(ruleEntity, ref component) && HasComp(ruleEntity); } public bool IsGameRuleActive(string rule) @@ -193,11 +195,10 @@ public IEnumerable GetAddedGameRules() /// public IEnumerable GetActiveGameRules() { - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var ruleData)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out _)) { - if (ruleData.Active) - yield return uid; + yield return uid; } } diff --git a/Content.Server/GameTicking/Rules/Components/ActiveGameRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/ActiveGameRuleComponent.cs new file mode 100644 index 00000000000..956768bdd99 --- /dev/null +++ b/Content.Server/GameTicking/Rules/Components/ActiveGameRuleComponent.cs @@ -0,0 +1,10 @@ +namespace Content.Server.GameTicking.Rules.Components; + +/// +/// Added to game rules before and removed before . +/// Mutually exclusive with . +/// +[RegisterComponent] +public sealed partial class ActiveGameRuleComponent : Component +{ +} diff --git a/Content.Server/GameTicking/Rules/Components/EndedGameRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/EndedGameRuleComponent.cs new file mode 100644 index 00000000000..4484abd4d0b --- /dev/null +++ b/Content.Server/GameTicking/Rules/Components/EndedGameRuleComponent.cs @@ -0,0 +1,10 @@ +namespace Content.Server.GameTicking.Rules.Components; + +/// +/// Added to game rules before . +/// Mutually exclusive with . +/// +[RegisterComponent] +public sealed partial class EndedGameRuleComponent : Component +{ +} diff --git a/Content.Server/GameTicking/Rules/Components/GameRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/GameRuleComponent.cs index cc384b47d3c..80a5ab340aa 100644 --- a/Content.Server/GameTicking/Rules/Components/GameRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/GameRuleComponent.cs @@ -9,25 +9,17 @@ namespace Content.Server.GameTicking.Rules.Components; [RegisterComponent] public sealed partial class GameRuleComponent : Component { - /// - /// Whether or not the rule is active. - /// Is enabled after and disabled after - /// - [DataField("active")] - public bool Active; - /// /// Game time when game rule was activated /// - [DataField("activatedAt", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan ActivatedAt; /// - /// Whether or not the gamerule finished. - /// Used for tracking whether a non-active gamerule has been started before. + /// The minimum amount of players needed for this game rule. /// - [DataField("ended")] - public bool Ended; + [DataField] + public int MinPlayers; } /// diff --git a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs index 8ddfd9c14bb..55c14f88d4e 100644 --- a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs @@ -4,7 +4,6 @@ using Content.Shared.Dataset; using Content.Shared.Roles; using Robust.Shared.Map; -using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; @@ -16,79 +15,80 @@ namespace Content.Server.GameTicking.Rules.Components; [RegisterComponent, Access(typeof(NukeopsRuleSystem), typeof(LoneOpsSpawnRule))] public sealed partial class NukeopsRuleComponent : Component { + // TODO Replace with GameRuleComponent.minPlayers /// /// The minimum needed amount of players /// - [DataField("minPlayers")] + [DataField] public int MinPlayers = 20; /// /// This INCLUDES the operatives. So a value of 3 is satisfied by 2 players & 1 operative /// - [DataField("playersPerOperative")] + [DataField] public int PlayersPerOperative = 10; - [DataField("maxOps")] - public int MaxOperatives = 5; + [DataField] + public int MaxOps = 5; /// /// What will happen if all of the nuclear operatives will die. Used by LoneOpsSpawn event. /// - [DataField("roundEndBehavior")] + [DataField] public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.ShuttleCall; /// /// Text for shuttle call if RoundEndBehavior is ShuttleCall. /// - [DataField("roundEndTextSender")] + [DataField] public string RoundEndTextSender = "comms-console-announcement-title-centcom"; /// /// Text for shuttle call if RoundEndBehavior is ShuttleCall. /// - [DataField("roundEndTextShuttleCall")] + [DataField] public string RoundEndTextShuttleCall = "nuke-ops-no-more-threat-announcement-shuttle-call"; /// /// Text for announcement if RoundEndBehavior is ShuttleCall. Used if shuttle is already called /// - [DataField("roundEndTextAnnouncement")] + [DataField] public string RoundEndTextAnnouncement = "nuke-ops-no-more-threat-announcement"; /// /// Time to emergency shuttle to arrive if RoundEndBehavior is ShuttleCall. /// - [DataField("evacShuttleTime")] + [DataField] public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(10); /// /// Whether or not to spawn the nuclear operative outpost. Used by LoneOpsSpawn event. /// - [DataField("spawnOutpost")] + [DataField] public bool SpawnOutpost = true; /// /// Whether or not nukie left their outpost /// - [DataField("leftOutpost")] - public bool LeftOutpost = false; + [DataField] + public bool LeftOutpost; /// /// Enables opportunity to get extra TC for war declaration /// - [DataField("canEnableWarOps")] + [DataField] public bool CanEnableWarOps = true; /// /// Indicates time when war has been declared, null if not declared /// - [DataField("warDeclaredTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan? WarDeclaredTime; /// /// This amount of TC will be given to each nukie /// - [DataField("warTCAmountPerNukie")] + [DataField] public int WarTCAmountPerNukie = 40; /// @@ -100,55 +100,55 @@ public sealed partial class NukeopsRuleComponent : Component /// /// Delay between war declaration and nuke ops arrival on station map. Gives crew time to prepare /// - [DataField("warNukieArriveDelay")] + [DataField] public TimeSpan? WarNukieArriveDelay = TimeSpan.FromMinutes(15); /// /// Minimal operatives count for war declaration /// - [DataField("warDeclarationMinOps")] + [DataField] public int WarDeclarationMinOps = 4; - [DataField("spawnPointProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string SpawnPointPrototype = "SpawnPointNukies"; + [DataField] + public EntProtoId SpawnPointProto = "SpawnPointNukies"; - [DataField("ghostSpawnPointProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string GhostSpawnPointProto = "SpawnPointGhostNukeOperative"; + [DataField] + public EntProtoId GhostSpawnPointProto = "SpawnPointGhostNukeOperative"; - [DataField("commanderRoleProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string CommanderRolePrototype = "NukeopsCommander"; + [DataField] + public ProtoId CommanderRoleProto = "NukeopsCommander"; - [DataField("operativeRoleProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string OperativeRoleProto = "Nukeops"; + [DataField] + public ProtoId OperativeRoleProto = "Nukeops"; - [DataField("medicRoleProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MedicRoleProto = "NukeopsMedic"; + [DataField] + public ProtoId MedicRoleProto = "NukeopsMedic"; - [DataField("commanderStartingGearProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string CommanderStartGearPrototype = "SyndicateCommanderGearFull"; + [DataField] + public ProtoId CommanderStartGearProto = "SyndicateCommanderGearFull"; - [DataField("medicStartGearProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MedicStartGearPrototype = "SyndicateOperativeMedicFull"; + [DataField] + public ProtoId MedicStartGearProto = "SyndicateOperativeMedicFull"; - [DataField("operativeStartGearProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string OperativeStartGearPrototype = "SyndicateOperativeGearFull"; + [DataField] + public ProtoId OperativeStartGearProto = "SyndicateOperativeGearFull"; - [DataField("eliteNames", customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string EliteNames = "SyndicateNamesElite"; - [DataField("normalNames", customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string NormalNames = "SyndicateNamesNormal"; - [DataField("outpostMap", customTypeSerializer: typeof(ResPathSerializer))] - public ResPath NukieOutpostMap = new("/Maps/nukieplanet.yml"); + [DataField(customTypeSerializer: typeof(ResPathSerializer))] + public ResPath OutpostMap = new("/Maps/nukieplanet.yml"); - [DataField("shuttleMap", customTypeSerializer: typeof(ResPathSerializer))] - public ResPath NukieShuttleMap = new("/Maps/infiltrator.yml"); + [DataField(customTypeSerializer: typeof(ResPathSerializer))] + public ResPath ShuttleMap = new("/Maps/infiltrator.yml"); - [DataField("winType")] + [DataField] public WinType WinType = WinType.Neutral; - [DataField("winConditions")] + [DataField] public List WinConditions = new (); public MapId? NukiePlanet; @@ -162,30 +162,30 @@ public sealed partial class NukeopsRuleComponent : Component /// /// Cached starting gear prototypes. /// - [DataField("startingGearPrototypes")] + [DataField] public Dictionary StartingGearPrototypes = new (); /// /// Cached operator name prototypes. /// - [DataField("operativeNames")] + [DataField] public Dictionary> OperativeNames = new(); /// /// Data to be used in for an operative once the Mind has been added. /// - [DataField("operativeMindPendingData")] + [DataField] public Dictionary OperativeMindPendingData = new(); /// /// Players who played as an operative at some point in the round. /// Stores the mind as well as the entity name /// - [DataField("operativePlayers")] + [DataField] public Dictionary OperativePlayers = new(); - [DataField("faction", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] - public string Faction = default!; + [DataField(required: true)] + public ProtoId Faction = default!; } public enum WinType : byte diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.cs index e87660c2cc4..b13f00f3638 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.cs @@ -1,9 +1,11 @@ +using Content.Server.Chat.Managers; using Content.Server.GameTicking.Rules.Components; namespace Content.Server.GameTicking.Rules; public abstract partial class GameRuleSystem : EntitySystem where T : Component { + [Dependency] protected readonly IChatManager ChatManager = default!; [Dependency] protected readonly GameTicker GameTicker = default!; public override void Initialize() @@ -36,6 +38,7 @@ private void OnGameRuleEnded(EntityUid uid, T component, ref GameRuleEndedEvent Ended(uid, component, ruleData, args); } + /// /// Called when the gamerule is added /// @@ -68,6 +71,36 @@ protected virtual void ActiveTick(EntityUid uid, T component, GameRuleComponent } + protected EntityQueryEnumerator QueryActiveRules() + { + return EntityQueryEnumerator(); + } + + protected bool TryRoundStartAttempt(RoundStartAttemptEvent ev, string localizedPresetName) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out _, out _, out _, out var gameRule)) + { + var minPlayers = gameRule.MinPlayers; + if (!ev.Forced && ev.Players.Length < minPlayers) + { + ChatManager.SendAdminAnnouncement(Loc.GetString("preset-not-enough-ready-players", + ("readyPlayersCount", ev.Players.Length), ("minimumPlayers", minPlayers), + ("presetName", localizedPresetName))); + ev.Cancel(); + continue; + } + + if (ev.Players.Length == 0) + { + ChatManager.DispatchServerAnnouncement(Loc.GetString("preset-no-one-ready")); + ev.Cancel(); + } + } + + return !ev.Cancelled; + } + public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index df9fbcc1301..3bd3d13d277 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -595,7 +595,7 @@ private void OnPlayersSpawning(RulePlayerSpawningEvent ev) // Basically copied verbatim from traitor code var playersPerOperative = nukeops.PlayersPerOperative; - var maxOperatives = nukeops.MaxOperatives; + var maxOperatives = nukeops.MaxOps; // Dear lord what is happening HERE. var everyone = new List(ev.PlayerPool); @@ -614,15 +614,15 @@ private void OnPlayersSpawning(RulePlayerSpawningEvent ev) } var profile = ev.Profiles[player.UserId]; - if (profile.AntagPreferences.Contains(nukeops.OperativeRoleProto)) + if (profile.AntagPreferences.Contains(nukeops.OperativeRoleProto.Id)) { prefList.Add(player); } - if (profile.AntagPreferences.Contains(nukeops.MedicRoleProto)) + if (profile.AntagPreferences.Contains(nukeops.MedicRoleProto.Id)) { medPrefList.Add(player); } - if (profile.AntagPreferences.Contains(nukeops.CommanderRolePrototype)) + if (profile.AntagPreferences.Contains(nukeops.CommanderRoleProto.Id)) { cmdrPrefList.Add(player); } @@ -808,8 +808,8 @@ private bool SpawnMap(EntityUid uid, NukeopsRuleComponent? component = null) if (!component.SpawnOutpost) return true; - var path = component.NukieOutpostMap; - var shuttlePath = component.NukieShuttleMap; + var path = component.OutpostMap; + var shuttlePath = component.ShuttleMap; var mapId = _mapManager.CreateMap(); var options = new MapLoadOptions @@ -866,18 +866,18 @@ private bool SpawnMap(EntityUid uid, NukeopsRuleComponent? component = null) { case 0: name = Loc.GetString("nukeops-role-commander") + " " + _random.PickAndTake(component.OperativeNames[component.EliteNames]); - role = component.CommanderRolePrototype; - gear = component.CommanderStartGearPrototype; + role = component.CommanderRoleProto; + gear = component.CommanderStartGearProto; break; case 1: name = Loc.GetString("nukeops-role-agent") + " " + _random.PickAndTake(component.OperativeNames[component.NormalNames]); role = component.MedicRoleProto; - gear = component.MedicStartGearPrototype; + gear = component.MedicStartGearProto; break; default: name = Loc.GetString("nukeops-role-operator") + " " + _random.PickAndTake(component.OperativeNames[component.NormalNames]); role = component.OperativeRoleProto; - gear = component.OperativeStartGearPrototype; + gear = component.OperativeStartGearProto; break; } @@ -915,7 +915,7 @@ private void SpawnOperatives(int spawnCount, List sessions, bool // Forgive me for hardcoding prototypes foreach (var (_, meta, xform) in EntityQuery(true)) { - if (meta.EntityPrototype?.ID != component.SpawnPointPrototype) + if (meta.EntityPrototype?.ID != component.SpawnPointProto.Id) continue; if (xform.ParentUid != component.NukieOutpost) @@ -981,7 +981,7 @@ private void SpawnOperativesForGhostRoles(EntityUid uid, NukeopsRuleComponent? c } // Basically copied verbatim from traitor code var playersPerOperative = component.PlayersPerOperative; - var maxOperatives = component.MaxOperatives; + var maxOperatives = component.MaxOps; var playerPool = _playerManager.ServerSessions.ToList(); var numNukies = MathHelper.Clamp(playerPool.Count / playersPerOperative, 1, maxOperatives); @@ -1115,9 +1115,9 @@ protected override void Started(EntityUid uid, NukeopsRuleComponent component, G // TODO: Loot table or something foreach (var proto in new[] { - component.CommanderStartGearPrototype, - component.MedicStartGearPrototype, - component.OperativeStartGearPrototype + component.CommanderStartGearProto, + component.MedicStartGearProto, + component.OperativeStartGearProto }) { component.StartingGearPrototypes.Add(proto, _prototypeManager.Index(proto)); From 4908931b6e59623bbd41e3166cbb5b71d1b51d8b Mon Sep 17 00:00:00 2001 From: Skarletto <122584947+Skarletto@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:18:10 -0400 Subject: [PATCH 24/98] bartender suit (#20521) * give me a drink bartender * guh * aARG --- .../bartender.rsi/equipped-INNERCLOTHING.png | Bin 1284 -> 1281 bytes .../Uniforms/Jumpsuit/bartender.rsi/meta.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/bartender.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/bartender.rsi/equipped-INNERCLOTHING.png index 475c96e522e52fe4b5b2df581d21488ba845a130..4b5753f79256b65df17a79775fac4d5bc33b2f90 100644 GIT binary patch delta 1262 zcmVPx(yGcYrRCt{2nlVrES{%k72?$1mn-Uf^ z4EU-ElM7Q1Z5z%V zuBW#Jl%7Jl_q}g_NyF*s;XMEI^qha1o&pXI4h{|u4h{}~CVx{bjd`9Yb8~Y5fWyN> z?Z4;e=L7&=Ute*2e9Y7*3mnH0T8>7eTD>GmTKVkkj7i^Zwjs~+WOsKL0C0MG3IJqt za}!rrS11;XI669_O^F>Qa2!WYPEG&-7Z(?XK}RAH?Ck7l`m81lh39#qM-T)Oi^Yf_ z2xNPEn+SqnxPQ*`JQ?1rb$v>uQW;o3R(&d7sZjt6#$UW=e6=U$>;MBMe*A2}x<06*$H&LM z_O#uwyJeO^`uf55p0nzIYe2bN#@^oERJmLpc>SvxFzkP38Pw0p%F4jD`ucI{_n}Wn zgb*T%q9OT=JNx&-aU2mv(U9!uA&Mf=KPQ;Q^m9Nj)oK;NV9=I?_Z6W~2*BW_r@zhu zQ-WGuU4JDmmkaTD919Bzh{xj)1Od;_&kzIw-EJ56_xH9v2}Yw)vazv&hld9&EiD;- z7Z(>%DwQBf5|ci&0W&i*+WE)F2fSXdcHZf9Y&C%10E#Tjn4X^2&aK=4%S%8}6v(m+ zm&*l@$78h{X7qZpENeGFQ51B$UFQBQ8K5W%RDV^4+wF#`ssJ!i6JB0k`pQ0^&r)Be zo&>+b&guRY9*+k;pAT-g8>Lcd%I$W;=kr;<0V5gkf55T-`+O#!;`=4KbR9c?ReQPN8dWk~v_|dLIF z+}8a?{DF*=#b2TOk|{lll310KnVZo8cPW zAhFE=8UXN*36mVWK89WstPCEokY@w*0{_O~X$;L~(-1>%Y-aiGHb=+J$Oc&5l^qA; z&>qPEMN!ahw?_`bD(!ZAWD`a*fc2rn4n~c^vH_~9qS0sou$FvAg=#h$4d?p+2M6o? Y1$ts;Qq5Z>bN~PV07*qoM6N<$f(S8G?*IS* delta 1265 zcmV7=~ZTB0&vy973ap0*{(dStyv$;1962 zFrLC>6Dwmw#UI$l!bB<>5-NUxHrwo47!xe?NFo6ngU|p$P$0}HuCrNmm7Rqp_uM;A zvSFAV=6&benUBrR0vry9!{Kl^oc||NER7{eB6D+d0Dyyo1ApzeXJ=;w0GiDvj*gC) z`eZ>AMMBG)o10p_s;XM~^z@WTUohKHk|eUTvjYG)IXM9UvcA5KtE(&I^LZQ|9@3`7 zjv$DlNRE$>0RZRc=L3Tdg+kcg-q!S4gD@0Hl87EzmPsTMA+ju!t*tF0%ksc^Ns`F$ zUajj>ip8Q~{eM{Xsd%wiB((hc`ugdh!qn8bOwc~*@m&D)?ab;s%rq*MO2}rjTG{1t z!R2z{`ubWcmr5l7KsKAz%Ht%P%|cO>Z`&w}qWLt-w>f~W`>#6n`~8OX*=!c?`C_De z@KK+x`*1jn#l=OfU8z)pq9{;R6@fs2Nq^`JpiwvK=zrVF%6LZN`&-QB4|p78TCnQ1$Q50n$`HVaJe?$~T zqA1EhvZIHhC`5msU>4K&0Us%qO7Q#rwj{i-2m}HEjF+DNJPS+-YI%8?xZQ4SY;3^m z^&%RLLVuQJR4Nr*US6WzZsY#`-nKiz&CN}+wzh`H$44wIEDU`9`0)b|4-ZgPl}VpD z01k%(E|&`c@b>nml>yiu0I%1p-HHQ1tJT8H%#8NE*=(XxsW9oAx)0Dp2i)y;(dl&1 z?RHta7>Q1&13?fV2m<>3zEGy0Mu$VI2;bk`ph#xkDb%~E8K3kHds2{olYm*ZnvfWMhd`x0m}gp1k3-R|0@2v z8PIOGnd*nZd>M^|dcB^O4DG~7XHwc64u`|xa5x+ehr@}->dCWBBYgn#n;(qw@-2RuJNYi0V*5ar_Hg4qBoA2swI z^xn+E9DrmpiF7)RMxy}$xVgE}&c$LeW&^C~HK=x@(Lg$#MlzXX?$6Rw;cz$%07#`$ z+LqMsySs_afZum_0RGt~OQli+o>*bZ0n^jd0Dx+>ioLx(t-f3?VzC$!iGPG8 zBW8)kV)(hTqOEu8qgt&Fcr*+14A2jpLf76TbAZu$H}Wp>wcju%Y?p@V3hT5Z*P&$=S_QH4gm0ZTWofA764GM*O|nv5DW&%{QNus;N|6I z;2hl`Ve!DU1ZcuLkqdQYq#m~(($VA6xvdoT)u6%T*i=IFQ?IRKM> zMP}UEBL$$_?V{CcjcmdytyXK~AdD0M)|(DH7}bO20Q7o2)M_;V){@VtP|aGc#@`R% baIEtOGyQiP@#pUR00000NkvXXu0mjfkgjiN diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/bartender.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/bartender.rsi/meta.json index 37207b882f8..b02e5f4b8a6 100644 --- a/Resources/Textures/Clothing/Uniforms/Jumpsuit/bartender.rsi/meta.json +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/bartender.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039, monkey made by brainfood1183 (github), monkey made by brainfood1183 (github) for ss14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039, monkey made by brainfood1183 (github), monkey made by brainfood1183 (github) for ss14, default suit edit by Skarletto (github)", "size": { "x": 32, "y": 32 From e227286404ec6ba7de2d6e2fbe3bf3d593329e8b Mon Sep 17 00:00:00 2001 From: NULL882 <104377798+NULL882@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:07:12 +0300 Subject: [PATCH 25/98] Necropolis and mine walls (#20578) --- .../Structures/Wallmounts/Signs/signs.yml | 18 +++++ .../Entities/Structures/Walls/walls.yml | 73 ++++++++++++++++++ .../Structures/Wallmounts/signs.rsi/meta.json | 18 ++++- .../Wallmounts/signs.rsi/ntmining.png | Bin 0 -> 519 bytes .../Wallmounts/signs.rsi/survival.png | Bin 0 -> 3164 bytes .../Structures/Walls/mining.rsi/full.png | Bin 0 -> 797 bytes .../Structures/Walls/mining.rsi/meta.json | 46 +++++++++++ .../Structures/Walls/mining.rsi/mining0.png | Bin 0 -> 1033 bytes .../Structures/Walls/mining.rsi/mining1.png | Bin 0 -> 1159 bytes .../Structures/Walls/mining.rsi/mining2.png | Bin 0 -> 1033 bytes .../Structures/Walls/mining.rsi/mining3.png | Bin 0 -> 1159 bytes .../Structures/Walls/mining.rsi/mining4.png | Bin 0 -> 1076 bytes .../Structures/Walls/mining.rsi/mining5.png | Bin 0 -> 1189 bytes .../Structures/Walls/mining.rsi/mining6.png | Bin 0 -> 1076 bytes .../Structures/Walls/mining.rsi/mining7.png | Bin 0 -> 879 bytes .../Walls/mining_diagonal.rsi/meta.json | 17 ++++ .../Walls/mining_diagonal.rsi/state0.png | Bin 0 -> 3511 bytes .../Walls/mining_diagonal.rsi/state1.png | Bin 0 -> 3511 bytes .../Structures/Walls/necropolis.rsi/full.png | Bin 0 -> 1387 bytes .../Structures/Walls/necropolis.rsi/meta.json | 46 +++++++++++ .../Walls/necropolis.rsi/necropolis0.png | Bin 0 -> 4413 bytes .../Walls/necropolis.rsi/necropolis1.png | Bin 0 -> 3875 bytes .../Walls/necropolis.rsi/necropolis2.png | Bin 0 -> 4413 bytes .../Walls/necropolis.rsi/necropolis3.png | Bin 0 -> 3875 bytes .../Walls/necropolis.rsi/necropolis4.png | Bin 0 -> 3895 bytes .../Walls/necropolis.rsi/necropolis5.png | Bin 0 -> 3762 bytes .../Walls/necropolis.rsi/necropolis6.png | Bin 0 -> 3895 bytes .../Walls/necropolis.rsi/necropolis7.png | Bin 0 -> 2930 bytes 28 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/ntmining.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/survival.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/full.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/meta.json create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining0.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining1.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining2.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining3.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining4.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining5.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining6.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/mining7.png create mode 100644 Resources/Textures/Structures/Walls/mining_diagonal.rsi/meta.json create mode 100644 Resources/Textures/Structures/Walls/mining_diagonal.rsi/state0.png create mode 100644 Resources/Textures/Structures/Walls/mining_diagonal.rsi/state1.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/full.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/meta.json create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis0.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis1.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis2.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis3.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis4.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis5.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis6.png create mode 100644 Resources/Textures/Structures/Walls/necropolis.rsi/necropolis7.png diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml index 2e3f00724a9..628b2e5852e 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml @@ -1278,3 +1278,21 @@ components: - type: Sprite state: zero + +- type: entity + parent: BaseSign + id: SignSurvival + name: survival sign + description: A sign. "Survival" is written on it. + components: + - type: Sprite + state: survival + +- type: entity + parent: BaseSign + id: SignNTMine + name: mine sign + description: A sign. "Mine" is written on it. + components: + - type: Sprite + state: ntmining diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml index 3e15f276636..07c2fb2d37c 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml @@ -990,6 +990,79 @@ node: wall +# Lavalend Walls + +- type: entity + parent: BaseWall + id: WallNecropolis + name: stone wall + components: + - type: Tag + tags: + - Wall + - type: Sprite + sprite: Structures/Walls/necropolis.rsi + - type: Icon + sprite: Structures/Walls/necropolis.rsi + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 1000 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: IconSmooth + key: walls + base: necropolis + +- type: entity + parent: BaseWall + id: WallMining + name: wall + components: + - type: Tag + tags: + - Wall + - type: Sprite + sprite: Structures/Walls/mining.rsi + - type: Icon + sprite: Structures/Walls/mining.rsi + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 700 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: IconSmooth + key: walls + base: mining + +- type: entity + parent: WallShuttleDiagonal + id: WallMiningDiagonal + name: wall + suffix: diagonal + placement: + mode: SnapgridCenter + snap: + - Wall + components: + - type: Sprite + drawdepth: Walls + sprite: Structures/Walls/mining_diagonal.rsi + state: state0 + - type: IconSmooth + mode: Diagonal + key: walls + base: state + - type: Icon + sprite: Structures/Walls/mining_diagonal.rsi + state: state0 + + # Vault Walls - type: entity diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json index 209c9c7d752..e2cbbff9892 100644 --- a/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json @@ -5,7 +5,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 4e0bbe682d0a00192d24708fdb7031008aa03f18 and bee station at commit https://github.com/BeeStation/BeeStation-Hornet/commit/13dd5ac712385642574138f6d7b30eea7c2fab9c, except numerical signs which were created by discord: brainfood#7460", + "copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 4e0bbe682d0a00192d24708fdb7031008aa03f18 and bee station at commit https://github.com/BeeStation/BeeStation-Hornet/commit/13dd5ac712385642574138f6d7b30eea7c2fab9c, except numerical signs which were created by discord: brainfood#7460, states: 'survival' and 'ntmining' from https://github.com/tgstation/tgstation/commit/f743754ec3ef446c8172388431effa73aeddb7ff#diff-b429dd7fccbca60d740d4887c1077a178abf1efffe57e7ae2a0b607c8a9e2202", "states": [ { "name": "ai", @@ -1357,6 +1357,22 @@ 1 ] ] + }, + { + "name": "survival", + "delays": [ + [ + 1 + ] + ] + }, + { + "name": "ntmining", + "delays": [ + [ + 1 + ] + ] } ] } diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/ntmining.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/ntmining.png new file mode 100644 index 0000000000000000000000000000000000000000..bd452d172babb819b6965b26928eda16797e9443 GIT binary patch literal 519 zcmV+i0{H!jP)E= z<1>Z#$EGZp3kOIXdhi>yw3Ua(X%<$~d6u*NIsu!9=L!LMcvkJ;KBJmh(4gD8ArSGj z25^!kYXD^yvpoC4=DZ($ak~(D5F(LWC&f{9dyVYbd7`1W(Fx2?4xn%Qd1|D@;w+(u zct6z23^cW!BSqb$s(}#z%2E98)O76mO zY0QlSD^aL?t`#ceV)c6OkU6?k@HS_JmJVAH0tp}iB!C3)qYp13_@Jw(p`HK$002ov JPDHLkV1j|G;Y$Dj literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/survival.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/survival.png new file mode 100644 index 0000000000000000000000000000000000000000..a4261fbcf88dcadf5384430888b3351e7b55a3c8 GIT binary patch literal 3164 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 be8m1AK}CMel|cgQ00000NkvXXu0mjf^BQWJ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining.rsi/meta.json b/Resources/Textures/Structures/Walls/mining.rsi/meta.json new file mode 100644 index 00000000000..4ce4691c516 --- /dev/null +++ b/Resources/Textures/Structures/Walls/mining.rsi/meta.json @@ -0,0 +1,46 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/commit/f743754ec3ef446c8172388431effa73aeddb7ff#diff-b429dd7fccbca60d740d4887c1077a178abf1efffe57e7ae2a0b607c8a9e2202 and modified.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "full" + }, + { + "name": "mining0", + "directions": 4 + }, + { + "name": "mining1", + "directions": 4 + }, + { + "name": "mining2", + "directions": 4 + }, + { + "name": "mining3", + "directions": 4 + }, + { + "name": "mining4", + "directions": 4 + }, + { + "name": "mining5", + "directions": 4 + }, + { + "name": "mining6", + "directions": 4 + }, + { + "name": "mining7", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Structures/Walls/mining.rsi/mining0.png b/Resources/Textures/Structures/Walls/mining.rsi/mining0.png new file mode 100644 index 0000000000000000000000000000000000000000..b0f8c7117060bdc270b39dbbd699e6918e4cf0d6 GIT binary patch literal 1033 zcmV+k1or!hP)-CQAvB%Q%bFy6i+Bx8N(051S0B$^B8}A#ds&(*pN8x}= zk*0ke46p&Z4~JJLj7VsUccczjzQ7mLT*8EP27 z=Qo}%jCU~rhSNQO8V2~_GceCh@JqGE0FL4CI+;u+Nl_I0u`J7y`Fy^c20w%Ue)JB2 z@w3_NXiBWtMLmvqp@IP};X^2jRc$=90>lp=SEB>C@rdrORRG4@PEZ^J+}i_g{C2BU z37Tc_u|6W&XW3vk=l`7CHy8}`Fn~Wzik9N08e#e9tsf#9K_0D%L?N$9y>%B zfJiT~H*W(X3_xBV;7QB(0wD$%!+Fxu25oV9@-qgAFyQX)Yb|o@q$LM89#9hm!2nWt zWS~p!#U_9VLOS66%y}Ck46xC(xETXP7(jV?d%Ve5+lV3|(k4V4aA|#CO+LUzllp!v zd4Z2rAoLG_0m$S6=cF*M#i#{D7(i7VBZWJj+P+dL3e@P1Sgh)?QKET!i_Brhq zV}u9;@HBnZo7nRNA`C!Hz)p)}I$&JA1Hb_OYJP7*Q8<&Eb5b zF$S1qiND8yu2t2?o1=-E_XS>CTm{rHz*QywSN#RglQGrxE3>*z00000NkvXXu0mjf D@Kw;L literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining.rsi/mining1.png b/Resources/Textures/Structures/Walls/mining.rsi/mining1.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bc3f00e9e8edd97e989cb039b4be600963e404 GIT binary patch literal 1159 zcmV;21bF+2P)$lw3kwU(_jixW&1RFit{ZwseU{Bmv3mVS z*8y8v-?r|6Y;qtE;SBF2_<|1%?9JAT}Vu0MGNd z@d$;N3=}K`9Oh0OOOKpw^L@13J?**!R9vud3?w{)#co=#PgN5O$@xXGn#a^a?0kgB0JFoBGWbO80 zWPMcc0ow-??9tkLzMp^a>s0BYsch z*watmK<$df8(rspV76g|0SHP41=^5dfQ)_v8OL#q%;LH*!hn{l9Ui$(uKYvG;zS{yAJ#M{Y&V1rBdPHu^b`7__!6q7K{u5Rq_(a3z6zVpoHGX zx*v7W!6uB0qWxrd(gfoUh%z2*K<|t67l36k4KU&Wh@680L&2vI2gJ$VqXKOQjI!~7 zwIPreoXIjM&`BT%sYy^q)G~-T0AdOB0ucw0nFLkzI^>WxoJn?Amc9Y3|3Wq=7YdJ$ zkMZPau{a-+#f9`O1E)LF25kr2d-b{J))%`zT-Vp%hMuPZ+78&>-r{SZkhTWB;(vi* z^#okS_lJe`6CyyMA_uyn>jtX@at&Zkp>UlaqLhahQgN3KJbp@K`N@c%5dxAXMi{Ri zqJ#?l_||#WZtH(L6%LRg#|!{^zTZQX!yt7Ih{IXM7pZW7ESbwOgQ_-@Wk8Zl7MEr> zwGB^&1BQXAZTQGK05Gu)A6W;G8Uj&y!(JdY1Z3mo9D)k6%V0nFZvr7Xhk!UBm&+fQ zWssT!-CQAvB%Q%bFy6i+Bx8N(051S0B$^B8}A#ds&(*pN8x}= zk*0ke46p&Z4~JJLj7VsUccczjzQ7mLT*8EP27 z=Qo}%jCU~rhSNQO8V2~_GceCh@JqGE0FL4CI+;u+Nl_I0u`J7y`Fy^c20w%Ue)JB2 z@w3_NXiBWtMLmvqp@IP};X^2jRc$=90>lp=SEB>C@rdrORRG4@PEZ^J+}i_g{C2BU z37Tc_u|6W&XW3vk=l`7CHy8}`Fn~Wzik9N08e#e9tsf#9K_0D%L?N$9y>%B zfJiT~H*W(X3_xBV;7QB(0wD$%!+Fxu25oV9@-qgAFyQX)Yb|o@q$LM89#9hm!2nWt zWS~p!#U_9VLOS66%y}Ck46xC(xETXP7(jV?d%Ve5+lV3|(k4V4aA|#CO+LUzllp!v zd4Z2rAoLG_0m$S6=cF*M#i#{D7(i7VBZWJj+P+dL3e@P1Sgh)?QKET!i_Brhq zV}u9;@HBnZo7nRNA`C!Hz)p)}I$&JA1Hb_OYJP7*Q8<&Eb5b zF$S1qiND8yu2t2?o1=-E_XS>CTm{rHz*QywSN#RglQGrxE3>*z00000NkvXXu0mjf D@Kw;L literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining.rsi/mining3.png b/Resources/Textures/Structures/Walls/mining.rsi/mining3.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bc3f00e9e8edd97e989cb039b4be600963e404 GIT binary patch literal 1159 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 FV1lxWg75$U literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining_diagonal.rsi/meta.json b/Resources/Textures/Structures/Walls/mining_diagonal.rsi/meta.json new file mode 100644 index 00000000000..d908dd0c08a --- /dev/null +++ b/Resources/Textures/Structures/Walls/mining_diagonal.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/commit/f743754ec3ef446c8172388431effa73aeddb7ff#diff-b429dd7fccbca60d740d4887c1077a178abf1efffe57e7ae2a0b607c8a9e2202 and modified.", + "states": [ + { + "name": "state0" + }, + { + "name": "state1" + } + ] +} diff --git a/Resources/Textures/Structures/Walls/mining_diagonal.rsi/state0.png b/Resources/Textures/Structures/Walls/mining_diagonal.rsi/state0.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f7db27920ccbfdda434c165e111f1aa5d59b74 GIT binary patch literal 3511 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining_diagonal.rsi/state1.png b/Resources/Textures/Structures/Walls/mining_diagonal.rsi/state1.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f7db27920ccbfdda434c165e111f1aa5d59b74 GIT binary patch literal 3511 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/necropolis.rsi/full.png b/Resources/Textures/Structures/Walls/necropolis.rsi/full.png new file mode 100644 index 0000000000000000000000000000000000000000..f03d79132b48fe9f5c8b01db505e27ee35dfc30d GIT binary patch literal 1387 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 D`e`zH literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis1.png b/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis1.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4c7d7912a4ebb7de2eda11c8d9e7d834168707 GIT binary patch literal 3875 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 D`e`zH literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis3.png b/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis3.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4c7d7912a4ebb7de2eda11c8d9e7d834168707 GIT binary patch literal 3875 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 FV1kAdEk6JN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis5.png b/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis5.png new file mode 100644 index 0000000000000000000000000000000000000000..28bbea2a946f6072b55b2c6a57de15cd20c264c8 GIT binary patch literal 3762 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 FV1kAdEk6JN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis7.png b/Resources/Textures/Structures/Walls/necropolis.rsi/necropolis7.png new file mode 100644 index 0000000000000000000000000000000000000000..745e5b0ce39d8d7d93c3f048c43099e47d99b5e2 GIT binary patch literal 2930 zcmZ`*XEYq@7X4hJx2Qq5L>G)MIx~6=MvNBSDA5v$7BYIvB_eu8NTQbrF*16uF@mV0 zL=S=&B_mPh$-leaTJNm2&pzv{eSVyM{+y)Srh0VLoYVjSIs<)ei%Zu014{DCT;UbC zcu7Z0743|co_94ff)%PWnk^04{94h2ab`Z4p7npDf7fQQ9u?B zoCf&$LqKdUV9`CWR{e3ahH+Eu(y81!Rjh!LPLv&`L?DH=wIq)S&VcFSM7NbC@l#UuC3#Tmtxgi2E>Y&-O8V1Cm=O`w zu|fdgpxM9kiwGqt$}?tpG?=)rajsV=2v8md&jSItt1Tc2AF9{rrvyN|FiNaei|eTK zns^8K_0B8voit}o3b9auo-QaOl-dn-{l1fERWwv2ex#OL%n9;ElUuIC+%rBSfL^l8 z>La~c0K;!*%7RXjmMAJRtpQ4AXTG^a5|?BIe<~$=Zrll9r#=}|iU99mB8&MAqjY(F zX^Uhyua!Rcf!h7QloIT9o6=PVfK2pRe2bp+i>NwtwJ)>{Fl?D3XRPjPn$K=Q(s^lY zh54WFf8bPms!+7~xzdwiE=?WQFV*qw8ij1nJt@h)Zs_}4;#3)~!|!iY(N^|x*50Wi zZB9CN9ep26#uTN~L8U+z4CQs^(b7j4BTQ%X%XqH~$X%VIQluh{HSZF>kx^#!L8$5K zubyizGSUeMeR2LNrZi>-D|RITx)y>cGPGW&A_)OmMbC_L*9lQ>x}Di>*Ve^GFnz| z@+=n0ir`n}(`=#DMHq{B<_TrYau4&AMq=0ujEbvYXHIZ>vU?J|-hB&dy1J0bW19Wh zdVF|G?_2ga(xYHnx_H)@{zRk*NB%X6YePuFoRR#L?jwP2R zvRtJsp#oXv57&4bX>*=LZqsetZ3cU5UijW|wWW`j#+9Q!M4Zout}^~%lzflS`;pnl zkHngD&bgaY)GEr0lwh)kvexw$hc7%dC{}X=#o~QW}DL}daZs#VS8acWE$=Yded^&a-o#El+8p< z`M5^1!l#(4s98I>-LG^nr=aaFs=(O4bTPDb^Y`@#$T|Gn_jl>B9xZ~ro>qVyPm8;z z+AAOEugVSS$Nw;gIdp5nik&l^vzKGjv16)lCUyVOWq9hf7hr_eO|Zh)>AK zWZPsf&%y*-B3hzitYX|h@@eGt$W*R;zMAy3%x3;({&fCQqmyljtvIF(^U>X)Zq2sD zW)IWi7iX(vQ;e{(b*R^^Mpp|?HCH#6UMoer|8jLR{ z!Wrqpj%@6$>E6p|&4_4<_~%@Wf-Yf}zLMLPJMzJY`z*?Llo#`GFZVPedXKWUAV|b0 z=_uvxc%fn(ef>qk z^l`T%zfFCnaNclE>5iloj!THMj@L*HNJMasNoUIkkIlm#ENTDN&eC4YM@pM1y^}DM z7gMj0^j4iyY?5oz=#%uY`80_@BMj~tU00G6t5NW~*S2)Fdzi3-UZGhHXU~BQI0S?i z;ku6EO4-UKnZ%W|G>sEYZ@u`B7Nb}h+f%^<=3v28>d-FkF60f!n8H}%49s4P$Mis7 z%p~mj_w*L|P=Q|AV)1ostZ@0W7GpZ&g?!}#w!BBYzA|dct zhR37fD)+d$i(bE!MhH(P#h_39v#KjL64V%I$v3#I$g~(m9n#&}qkSZ4NGYqb;O5Bg zr}`oMGsTztuZX)$T};c*F~#vl))L%^jn*n}r8?EXP(1Z2>y?}FcgU+$KPF?ud?(E+ zcdfH)B3p&ROnjp5b`C{%Hjw!2&{$Eg$3^VSPwzUIAs{wO4bH#g(Ol}RNy#-Vc=l}8 zCo>}RA?sWT{zL7#^DjP>SN34tMm@$owl)?e3hd~!DzZ1S>HX+t=RVLa-TAP4{8I-H z$sQ5GH^*RL*f;H}A6wi@2XP}R8t}L9BlvH)!ru5ogY)!>-`E~kc*{?@?~{1D7Q(su zU>n|w#L8sSW77T9;Iy8gQIk}$b&_@J>rid#8@Ss~I!<~{!B3Bw#(tUP9#?}~q)px2 z(WCGGyX^wKA1pzqKxg&O%f1!<0PWDVEdtdNfrn0c?$Oims%46azaMcUxgp-ryn{U5 ze9OF3I~Thqvrp<{Q`?JSXL|U*8D7e%+JqV&!Uw(PwxTC8kO!kr(V6IoNXcLGPWacD z@J(0Tk~f3@eiLKR^0*E$WmBa^1!sToG3cNUzs_v^(K_#)vZL>I(6;JD#)Mga^ULPE z8mzq!b}y{8A>4zo#Z{n)TR3VB{lP|@nk-OKTWCED^C$EYj+fXLBJT^I5nlNxpx^E3PNPrN&V3lGQU^$6r~F{2mh$7u|(D`~lD!|`-hZ>iV7B&{_lXG6^Vj=h%g?2!85|iIL^9Hx!!uV|3H;^1 z$?K|bVFEyyAONTs0DciKc?*DtQUGi_0ic`%0K5Nl$6nn_E!sd^3m!7}9WPBED@9AD z$>pG@)lY1vm_(C34C(gL$(&VBmp5dd-ILZ8+}itg)>ds!(oaaHMtC1wPX8-V9ES!F zed6Kfz8~aY?f+AT$p3h(Ik#lCNmDV@_P?6{IPzS!h(uB#lgSVr1J$VcqcG4h)vkd$ GMgJGl6I0g! literal 0 HcmV?d00001 From d76d3060537d7a53d626513f5a3d922bd85283cf Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 13:08:17 -0400 Subject: [PATCH 26/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 27c9f44af43..926e70570f1 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Bhijn and Myr - changes: - - {message: 'Interaction outlines now directly react to lighting. You can no longer - merely wave your mouse around in the dark to see objects in the distance in - maint. Interaction outlines that''re in-range are far brighter even in dim conditions, - though out-of-range interaction outlines are hard to see in poor light conditions.', - type: Add} - id: 4414 - time: '2023-08-02T10:07:12.0000000+00:00' - author: eclips_e changes: - {message: The P-Block crate will now have oxygen and nitrogen jugs., type: Fix} @@ -2968,3 +2959,10 @@ Entries: you are., type: Tweak} id: 4913 time: '2023-09-28T14:05:42.0000000+00:00' +- author: NULL882 + changes: + - {message: Added Necropolis Wall., type: Add} + - {message: Added Mine Wall., type: Add} + - {message: Added Sings for Mine Wall., type: Add} + id: 4914 + time: '2023-09-28T17:07:13.0000000+00:00' From c34e1e2fab9a7cebe06a80df1da914103a451770 Mon Sep 17 00:00:00 2001 From: lunarcomets <140772713+lunarcomets@users.noreply.github.com> Date: Thu, 28 Sep 2023 12:19:58 -0700 Subject: [PATCH 27/98] archaic accent tweaks (#20567) --- Resources/Locale/en-US/accent/archaic.ftl | 15 ++++++--------- .../Prototypes/Accents/word_replacements.yml | 1 - 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Resources/Locale/en-US/accent/archaic.ftl b/Resources/Locale/en-US/accent/archaic.ftl index a9ff88746f8..11c6a7857e3 100644 --- a/Resources/Locale/en-US/accent/archaic.ftl +++ b/Resources/Locale/en-US/accent/archaic.ftl @@ -135,7 +135,7 @@ accent-archaic-replaced-43 = onto accent-archaic-replacement-43 = unto accent-archaic-replaced-44 = can i -accent-archaic-replacement-44 = am i allowed to +accent-archaic-replacement-44 = am I allowed to accent-archaic-replaced-45 = upon accent-archaic-replacement-45 = unto @@ -185,9 +185,6 @@ accent-archaic-replacement-59 = bemadding accent-archaic-replaced-60 = suggest accent-archaic-replacement-60 = bespeak -accent-archaic-replaced-53 = request -accent-archaic-replacement-53 = bespeak - accent-archaic-replaced-61 = indicate accent-archaic-replacement-61 = bespeak @@ -510,7 +507,7 @@ accent-archaic-replaced-175 = will accent-archaic-replacement-175 = shall accent-archaic-replaced-176 = i am thirsty -accent-archaic-replacement-176 = i require a drink +accent-archaic-replacement-176 = I require a drink accent-archaic-replaced-177 = hate accent-archaic-replacement-177 = loathe @@ -591,7 +588,7 @@ accent-archaic-replaced-204 = airlock accent-archaic-replacement-204 = door accent-archaic-replaced-205 = sorry -accent-archaic-replacement-205 = i apologise +accent-archaic-replacement-205 = I apologise accent-archaic-replaced-206 = hey accent-archaic-replacement-206 = pardon me @@ -615,7 +612,7 @@ accent-archaic-replaced-212 = why accent-archaic-replacement-212 = for what reason accent-archaic-replaced-213 = im -accent-archaic-replacement-213 = i am +accent-archaic-replacement-213 = I am accent-archaic-replaced-214 = sink accent-archaic-replacement-214 = taps @@ -645,13 +642,13 @@ accent-archaic-replaced-222 = myself accent-archaic-replacement-222 = mineself accent-archaic-replaced-223 = i am hungry -accent-archaic-replacement-223 = i require grub +accent-archaic-replacement-223 = I require grub accent-archaic-replaced-224 = you suck accent-archaic-replacement-224 = thou are foul accent-archaic-replaced-225 = please -accent-archaic-replacement-225 = i request of thee +accent-archaic-replacement-225 = I request of thee accent-archaic-replaced-226 = secway accent-archaic-replacement-226 = patrol cart diff --git a/Resources/Prototypes/Accents/word_replacements.yml b/Resources/Prototypes/Accents/word_replacements.yml index d12308e4179..befcfa6e6c7 100644 --- a/Resources/Prototypes/Accents/word_replacements.yml +++ b/Resources/Prototypes/Accents/word_replacements.yml @@ -319,7 +319,6 @@ accent-archaic-replaced-50: accent-archaic-replacement-50 accent-archaic-replaced-51: accent-archaic-replacement-51 accent-archaic-replaced-52: accent-archaic-replacement-52 - accent-archaic-replaced-53: accent-archaic-replacement-53 accent-archaic-replaced-54: accent-archaic-replacement-54 accent-archaic-replaced-55: accent-archaic-replacement-55 accent-archaic-replaced-56: accent-archaic-replacement-56 From f4ec8a39f3eaad4e303d381517d96d82427c271b Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 15:21:03 -0400 Subject: [PATCH 28/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 926e70570f1..61fdab9ddf0 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: eclips_e - changes: - - {message: The P-Block crate will now have oxygen and nitrogen jugs., type: Fix} - id: 4415 - time: '2023-08-02T14:32:08.0000000+00:00' - author: chromiumboy changes: - {message: Containers used in recipes now drop their contents when crafted., type: Fix} @@ -2966,3 +2961,9 @@ Entries: - {message: Added Sings for Mine Wall., type: Add} id: 4914 time: '2023-09-28T17:07:13.0000000+00:00' +- author: lunarcomets + changes: + - {message: 'Tweaked archaic issues to fix capitalization issues, and removed the + replacement for ''request'' for consistency.', type: Tweak} + id: 4915 + time: '2023-09-28T19:19:58.0000000+00:00' From 37df00d5222226c4558d2f2f50194cddadfa96b8 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 15:46:06 -0700 Subject: [PATCH 29/98] Add confirmation to kick and respawn in the admin player actions panel (#20542) --- .../Administration/UI/AdminUIHelpers.cs | 59 +++++++++++++++++++ .../UI/Bwoink/BwoinkControl.xaml.cs | 41 ++----------- .../Tabs/AdminTab/PlayerActionsWindow.xaml.cs | 19 +++++- 3 files changed, 79 insertions(+), 40 deletions(-) create mode 100644 Content.Client/Administration/UI/AdminUIHelpers.cs diff --git a/Content.Client/Administration/UI/AdminUIHelpers.cs b/Content.Client/Administration/UI/AdminUIHelpers.cs new file mode 100644 index 00000000000..89ab33e931d --- /dev/null +++ b/Content.Client/Administration/UI/AdminUIHelpers.cs @@ -0,0 +1,59 @@ +using System.Threading; +using Content.Client.Stylesheets; +using Robust.Client.UserInterface.Controls; +using Timer = Robust.Shared.Timing.Timer; + +namespace Content.Client.Administration.UI; + +public static class AdminUIHelpers +{ + private static void ResetButton(Button button, ConfirmationData data) + { + data.Cancellation.Cancel(); + button.ModulateSelfOverride = null; + button.Text = data.OriginalText; + } + + public static bool RemoveConfirm(Button button, Dictionary confirmations) + { + if (confirmations.Remove(button, out var data)) + { + ResetButton(button, data); + return true; + } + + return false; + } + + public static void RemoveAllConfirms(Dictionary confirmations) + { + foreach (var (button, confirmation) in confirmations) + { + ResetButton(button, confirmation); + } + + confirmations.Clear(); + } + + public static bool TryConfirm(Button button, Dictionary confirmations) + { + if (RemoveConfirm(button, confirmations)) + return true; + + var data = new ConfirmationData(new CancellationTokenSource(), button.Text); + confirmations[button] = data; + + Timer.Spawn(TimeSpan.FromSeconds(5), () => + { + confirmations.Remove(button); + button.ModulateSelfOverride = null; + button.Text = data.OriginalText; + }, data.Cancellation.Token); + + button.ModulateSelfOverride = StyleNano.ButtonColorCautionDefault; + button.Text = Loc.GetString("admin-player-actions-confirm"); + return false; + } +} + +public readonly record struct ConfirmationData(CancellationTokenSource Cancellation, string? OriginalText); diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs index e1903c307b2..6d8bb781064 100644 --- a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs +++ b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs @@ -1,22 +1,16 @@ using System.Linq; using System.Text; -using System.Threading; using Content.Client.Administration.Managers; using Content.Client.Administration.UI.CustomControls; -using Content.Client.Administration.UI.Tabs.AdminTab; -using Content.Client.Stylesheets; using Content.Client.UserInterface.Systems.Bwoink; -using Content.Client.UserInterface.Systems.Chat.Controls; using Content.Shared.Administration; using Robust.Client.AutoGenerated; using Robust.Client.Console; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Network; using Robust.Shared.Utility; -using Timer = Robust.Shared.Timing.Timer; namespace Content.Client.Administration.UI.Bwoink { @@ -31,8 +25,8 @@ public sealed partial class BwoinkControl : Control [Dependency] private readonly IUserInterfaceManager _ui = default!; public AdminAHelpUIHandler AHelpHelper = default!; - //private readonly BwoinkSystem _bwoinkSystem; - private PlayerInfo? _currentPlayer = default; + private PlayerInfo? _currentPlayer; + private readonly Dictionary _confirmations = new(); public BwoinkControl() { @@ -131,7 +125,7 @@ public BwoinkControl() Kick.OnPressed += _ => { - if (!TryConfirm(Kick)) + if (!AdminUIHelpers.TryConfirm(Kick, _confirmations)) { return; } @@ -149,7 +143,7 @@ public BwoinkControl() Respawn.OnPressed += _ => { - if (!TryConfirm(Respawn)) + if (!AdminUIHelpers.TryConfirm(Respawn, _confirmations)) { return; } @@ -164,8 +158,6 @@ public BwoinkControl() }; } - private Dictionary Confirmations { get; } = new(); - public void OnBwoink(NetUserId channel) { ChannelSelector.PopulateList(); @@ -246,30 +238,5 @@ private void SwitchToChannel(NetUserId ch) var panel = AHelpHelper.EnsurePanel(ch); panel.Visible = true; } - - private bool TryConfirm(Button button) - { - if (Confirmations.Remove(button, out var tuple)) - { - tuple.cancellation.Cancel(); - button.ModulateSelfOverride = null; - button.Text = tuple.originalText; - return true; - } - - tuple = (new CancellationTokenSource(), button.Text); - Confirmations[button] = tuple; - - Timer.Spawn(TimeSpan.FromSeconds(5), () => - { - Confirmations.Remove(button); - button.ModulateSelfOverride = null; - button.Text = tuple.originalText; - }, tuple.cancellation.Token); - - button.ModulateSelfOverride = StyleNano.ButtonColorCautionDefault; - button.Text = Loc.GetString("admin-player-actions-confirm"); - return false; - } } } diff --git a/Content.Client/Administration/UI/Tabs/AdminTab/PlayerActionsWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/AdminTab/PlayerActionsWindow.xaml.cs index 3532609fec1..6f960aaae19 100644 --- a/Content.Client/Administration/UI/Tabs/AdminTab/PlayerActionsWindow.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/AdminTab/PlayerActionsWindow.xaml.cs @@ -4,8 +4,7 @@ using Robust.Client.Console; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.IoC; -using Robust.Shared.Players; +using Robust.Client.UserInterface.XAML; using Robust.Shared.Utility; namespace Content.Client.Administration.UI.Tabs.AdminTab @@ -15,9 +14,12 @@ namespace Content.Client.Administration.UI.Tabs.AdminTab public sealed partial class PlayerActionsWindow : DefaultWindow { private PlayerInfo? _selectedPlayer; + private readonly Dictionary _confirmations = new(); - protected override void EnteredTree() + public PlayerActionsWindow() { + RobustXamlLoader.Load(this); + SubmitKickButton.OnPressed += SubmitKickButtonOnPressed; SubmitAHelpButton.OnPressed += SubmitAhelpButtonOnPressed; SubmitRespawnButton.OnPressed += SubmitRespawnButtonOnPressed; @@ -26,6 +28,9 @@ protected override void EnteredTree() private void OnListOnOnSelectionChanged(PlayerInfo? obj) { + if (_selectedPlayer != obj) + AdminUIHelpers.RemoveAllConfirms(_confirmations); + _selectedPlayer = obj; var disableButtons = _selectedPlayer == null; SubmitKickButton.Disabled = disableButtons; @@ -37,6 +42,10 @@ private void SubmitKickButtonOnPressed(BaseButton.ButtonEventArgs obj) { if (_selectedPlayer == null) return; + + if (!AdminUIHelpers.TryConfirm(SubmitKickButton, _confirmations)) + return; + IoCManager.Resolve().ExecuteCommand( $"kick \"{_selectedPlayer.Username}\" \"{CommandParsing.Escape(ReasonLine.Text)}\""); } @@ -54,6 +63,10 @@ private void SubmitRespawnButtonOnPressed(BaseButton.ButtonEventArgs obj) { if (_selectedPlayer == null) return; + + if (!AdminUIHelpers.TryConfirm(SubmitRespawnButton, _confirmations)) + return; + IoCManager.Resolve().ExecuteCommand( $"respawn \"{_selectedPlayer.Username}\""); } From ae248dcffe0e0858f64b2ab96b78e8c6dc45556c Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 15:46:26 -0700 Subject: [PATCH 30/98] Remove windows-latest CI runs, remove unused build-test-release.yml (#20540) --- .github/workflows/build-map-renderer.yml | 2 +- .github/workflows/build-test-debug.yml | 2 +- .github/workflows/build-test-release.yml | 62 ------------------------ 3 files changed, 2 insertions(+), 64 deletions(-) delete mode 100644 .github/workflows/build-test-release.yml diff --git a/.github/workflows/build-map-renderer.yml b/.github/workflows/build-map-renderer.yml index 4aa4b29c85e..e921bd2558c 100644 --- a/.github/workflows/build-map-renderer.yml +++ b/.github/workflows/build-map-renderer.yml @@ -13,7 +13,7 @@ jobs: if: github.actor != 'PJBot' && github.event.pull_request.draft == false strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/build-test-debug.yml b/.github/workflows/build-test-debug.yml index 12584c4da72..9abd4fbe17e 100644 --- a/.github/workflows/build-test-debug.yml +++ b/.github/workflows/build-test-debug.yml @@ -13,7 +13,7 @@ jobs: if: github.actor != 'PJBot' && github.event.pull_request.draft == false strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/build-test-release.yml b/.github/workflows/build-test-release.yml deleted file mode 100644 index d62bed3a5d1..00000000000 --- a/.github/workflows/build-test-release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Build & Test Release - -on: - push: - branches: [ master, staging, trying ] - merge_group: - pull_request: - types: [ opened, reopened, synchronize, ready_for_review ] - branches: [ master ] - -jobs: - build: - if: github.actor != 'PJBot' && github.event.pull_request.draft == false - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - - runs-on: ${{ matrix.os }} - - steps: - - name: Checkout Master - uses: actions/checkout@v3.6.0 - - - name: Setup Submodule - run: | - git submodule update --init --recursive - - - name: Pull engine updates - uses: space-wizards/submodule-dependency@v0.1.5 - - - name: Update Engine Submodules - run: | - cd RobustToolbox/ - git submodule update --init --recursive - - - name: Setup .NET Core - uses: actions/setup-dotnet@v3.2.0 - with: - dotnet-version: 7.0.x - - - name: Install dependencies - run: dotnet restore - - - name: Build Project - run: dotnet build --configuration Tools --no-restore /p:WarningsAsErrors=nullable /m - - - name: Run Content.Tests - run: dotnet test --configuration Tools --no-build Content.Tests/Content.Tests.csproj -- NUnit.ConsoleOut=0 - - - name: Run Content.IntegrationTests - shell: pwsh - run: | - $env:DOTNET_gcServer=1 - dotnet test --configuration Tools --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -- NUnit.ConsoleOut=0 NUnit.MapWarningTo=Failed - ci-success: - name: Build & Test Release - needs: - - build - runs-on: ubuntu-latest - steps: - - name: CI succeeded - run: exit 0 From a8b4304af3edc2e39c849c6a09889062ac9de4ea Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 15:46:36 -0700 Subject: [PATCH 31/98] Change .editorconfig to keep existing attribute arrangement (#20538) --- .editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 0409377f1dd..a8ce1d6b68b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -196,7 +196,7 @@ csharp_preserve_single_line_blocks = true #dotnet_naming_style.begins_with_i.word_separator = #dotnet_naming_style.begins_with_i.capitalization = pascal_case -dotnet_diagnostic.IDE0055.severity = warning +dotnet_diagnostic.ide0055.severity = warning dotnet_naming_rule.constants_rule.severity = warning dotnet_naming_rule.constants_rule.style = upper_camel_case_style @@ -336,6 +336,7 @@ dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter # ReSharper properties resharper_braces_for_ifelse = required_for_multiline +resharper_keep_existing_attribute_arrangement = true [*.{csproj,xml,yml,dll.config,msbuildproj,targets}] indent_size = 2 From 4defed95ab2cf1cc90d49ae527b50d01cef674dc Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 28 Sep 2023 18:47:11 -0400 Subject: [PATCH 32/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 61fdab9ddf0..282a00a7a4b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: chromiumboy - changes: - - {message: Containers used in recipes now drop their contents when crafted., type: Fix} - id: 4416 - time: '2023-08-02T18:32:51.0000000+00:00' - author: PuceTint changes: - {message: Nitrous oxide now causes laughing, type: Add} @@ -2967,3 +2962,9 @@ Entries: replacement for ''request'' for consistency.', type: Tweak} id: 4915 time: '2023-09-28T19:19:58.0000000+00:00' +- author: DrSmugleaf + changes: + - {message: Changed the player actions panel to ask for confirmation when kicking + and respawning players., type: Tweak} + id: 4916 + time: '2023-09-28T22:46:07.0000000+00:00' From 49aa1165498a470491234dfbdf886cc6ef91c1c4 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 15:48:29 -0700 Subject: [PATCH 33/98] Catch replay start and end errors on round restarts (#20565) --- .../GameTicking/GameTicker.Replays.cs | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/Content.Server/GameTicking/GameTicker.Replays.cs b/Content.Server/GameTicking/GameTicker.Replays.cs index 03cf748d09d..78a8182ce6f 100644 --- a/Content.Server/GameTicking/GameTicker.Replays.cs +++ b/Content.Server/GameTicking/GameTicker.Replays.cs @@ -23,38 +23,45 @@ private void InitializeReplays() /// private void ReplayStartRound() { - if (!_cfg.GetCVar(CCVars.ReplayAutoRecord)) - return; - - if (_replays.IsRecording) + try { - _sawmillReplays.Warning("Already an active replay recording before the start of the round, not starting automatic recording."); - return; - } + if (!_cfg.GetCVar(CCVars.ReplayAutoRecord)) + return; - _sawmillReplays.Debug($"Starting replay recording for round {RoundId}"); + if (_replays.IsRecording) + { + _sawmillReplays.Warning("Already an active replay recording before the start of the round, not starting automatic recording."); + return; + } - var finalPath = GetAutoReplayPath(); - var recordPath = finalPath; - var tempDir = _cfg.GetCVar(CCVars.ReplayAutoRecordTempDir); - ResPath? moveToPath = null; + _sawmillReplays.Debug($"Starting replay recording for round {RoundId}"); - if (!string.IsNullOrEmpty(tempDir)) - { - var baseReplayPath = new ResPath(_cfg.GetCVar(CVars.ReplayDirectory)).ToRootedPath(); - moveToPath = baseReplayPath / finalPath; + var finalPath = GetAutoReplayPath(); + var recordPath = finalPath; + var tempDir = _cfg.GetCVar(CCVars.ReplayAutoRecordTempDir); + ResPath? moveToPath = null; - var fileName = finalPath.Filename; - recordPath = new ResPath(tempDir) / fileName; + if (!string.IsNullOrEmpty(tempDir)) + { + var baseReplayPath = new ResPath(_cfg.GetCVar(CVars.ReplayDirectory)).ToRootedPath(); + moveToPath = baseReplayPath / finalPath; - _sawmillReplays.Debug($"Replay will record in temporary position: {recordPath}"); - } + var fileName = finalPath.Filename; + recordPath = new ResPath(tempDir) / fileName; + + _sawmillReplays.Debug($"Replay will record in temporary position: {recordPath}"); + } - var recordState = new ReplayRecordState(moveToPath); + var recordState = new ReplayRecordState(moveToPath); - if (!_replays.TryStartRecording(_resourceManager.UserData, recordPath.ToString(), state: recordState)) + if (!_replays.TryStartRecording(_resourceManager.UserData, recordPath.ToString(), state: recordState)) + { + _sawmillReplays.Error("Can't start automatic replay recording!"); + } + } + catch (Exception e) { - _sawmillReplays.Error("Can't start automatic replay recording!"); + Log.Error($"Error while starting an automatic replay recording:\n{e}"); } } @@ -63,9 +70,16 @@ private void ReplayStartRound() /// private void ReplayEndRound() { - if (_replays.ActiveRecordingState is ReplayRecordState) + try + { + if (_replays.ActiveRecordingState is ReplayRecordState) + { + _replays.StopRecording(); + } + } + catch (Exception e) { - _replays.StopRecording(); + Log.Error($"Error while stopping replay recording:\n{e}"); } } From 729295b5c883346eba79cc13730f8dcd9abb4a8b Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 16:20:29 -0700 Subject: [PATCH 34/98] Update trivial components to use auto comp states (#20539) --- .../UI/AccessOverriderBoundUserInterface.cs | 6 +- .../Access/UI/AccessOverriderWindow.xaml.cs | 4 +- .../UI/IdCardConsoleBoundUserInterface.cs | 6 +- .../Access/UI/IdCardConsoleWindow.xaml.cs | 2 +- Content.Client/Alerts/ClientAlertsSystem.cs | 14 +-- Content.Client/BarSign/BarSignSystem.cs | 23 ++-- Content.Client/Buckle/BuckleSystem.cs | 23 ++-- .../Systems/ChameleonClothingSystem.cs | 9 +- Content.Client/Cuffs/CuffableSystem.cs | 9 -- .../Humanoid/HumanoidAppearanceSystem.cs | 110 +++++++---------- ...manoidMarkingModifierBoundUserInterface.cs | 2 - .../HumanoidMarkingModifierWindow.xaml.cs | 3 +- Content.Client/Implants/ImplanterSystem.cs | 10 +- Content.Client/Lathe/UI/LatheMenu.xaml.cs | 5 +- .../Movement/Systems/ClimbSystem.cs | 11 -- Content.Client/Points/PointSystem.cs | 10 +- .../Radiation/Systems/GeigerSystem.cs | 15 +-- Content.Client/Tabletop/TabletopSystem.cs | 9 -- .../Ranged/Systems/GunSystem.Ballistic.cs | 2 +- .../Access/Systems/AccessOverriderSystem.cs | 8 +- .../BarSign/Systems/BarSignSystem.cs | 11 +- Content.Server/Climbing/ClimbSystem.cs | 7 -- .../Systems/ChameleonClothingSystem.cs | 18 +-- Content.Server/Cuffs/CuffableSystem.cs | 10 +- Content.Server/Doors/Systems/DoorSystem.cs | 15 +-- .../Electrocution/ElectrocutionSystem.cs | 2 +- Content.Server/Implants/ImplanterSystem.cs | 7 -- Content.Server/Lathe/LatheSystem.cs | 14 +-- Content.Server/Points/PointSystem.cs | 7 -- .../Radiation/Systems/GeigerSystem.cs | 14 --- .../Melee/EnergySword/EnergySwordSystem.cs | 4 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 8 +- .../Ranged/Systems/GunSystem.Ballistic.cs | 2 +- .../Weapons/Ranged/Systems/GunSystem.cs | 6 +- .../Zombies/ZombieSystem.Transform.cs | 3 +- Content.Server/Zombies/ZombieSystem.cs | 2 +- .../Components/AccessOverriderComponent.cs | 16 +-- .../Components/IdCardConsoleComponent.cs | 12 +- .../Systems/SharedAccessOverriderSystem.cs | 25 ---- .../Systems/SharedIdCardConsoleSystem.cs | 26 ---- Content.Shared/Alert/AlertsComponent.cs | 7 +- Content.Shared/Alert/AlertsComponentState.cs | 14 --- Content.Shared/Alert/AlertsSystem.cs | 7 -- .../Anomaly/Components/AnomalyComponent.cs | 56 ++++----- .../AnomalySupercriticalComponent.cs | 17 +-- Content.Shared/Anomaly/SharedAnomalySystem.cs | 42 ------- Content.Shared/BarSign/BarSignComponent.cs | 26 +--- .../Body/Components/BodyComponent.cs | 33 ++---- .../Body/Systems/SharedBodySystem.Body.cs | 26 ---- .../Buckle/Components/BuckleComponent.cs | 38 ++---- .../Buckle/Components/StrapComponent.cs | 52 +++----- .../Buckle/SharedBuckleSystem.Buckle.cs | 10 +- .../Buckle/SharedBuckleSystem.Strap.cs | 22 ---- Content.Shared/Buckle/SharedBuckleSystem.cs | 2 +- .../Cabinet/ItemCabinetComponent.cs | 34 +----- .../Cabinet/SharedItemCabinetSystem.cs | 22 ---- .../CartridgeLoader/CartridgeComponent.cs | 14 +-- .../SharedCartridgeLoaderSystem.cs | 22 ---- .../MovespeedModifierMetabolismComponent.cs | 25 +--- .../MetabolismMovespeedModifierSystem.cs | 25 +--- Content.Shared/Climbing/ClimbingComponent.cs | 20 +--- .../Components/ChameleonClothingComponent.cs | 15 +-- .../SharedChameleonClothingSystem.cs | 4 +- Content.Shared/Conveyor/ConveyorComponent.cs | 41 ++----- .../Cuffs/Components/HandcuffComponent.cs | 52 +++----- .../Damage/Components/StaminaComponent.cs | 18 +-- .../Damage/Systems/StaminaSystem.cs | 44 +------ .../Components/DeviceListComponent.cs | 29 +---- .../NetworkConfiguratorComponent.cs | 41 ++----- .../Systems/SharedDeviceListSystem.cs | 24 ---- .../SharedNetworkConfiguratorSystem.cs | 27 ----- .../Doors/Components/AirlockComponent.cs | 51 ++++---- .../Doors/Components/DoorComponent.cs | 92 ++++++--------- .../Doors/Systems/SharedAirlockSystem.cs | 18 --- .../Doors/Systems/SharedDoorSystem.cs | 25 +--- .../Electrocution/InsulatedComponent.cs | 22 +--- .../SharedElectrocutionSystem.cs | 21 +--- Content.Shared/Emoting/EmoteSystem.cs | 68 +++-------- Content.Shared/Emoting/EmotingComponent.cs | 15 ++- .../Follower/Components/FollowedComponent.cs | 6 +- Content.Shared/Follower/FollowerSystem.cs | 29 +---- .../Gravity/FloatingVisualsComponent.cs | 25 +--- .../Gravity/GravityShakeComponent.cs | 6 +- .../Gravity/SharedFloatingVisualizerSystem.cs | 18 --- .../Gravity/SharedGravitySystem.Shake.cs | 30 ----- .../Humanoid/HumanoidAppearanceComponent.cs | 111 ++++++------------ .../Prototypes/HumanoidProfilePrototype.cs | 1 - .../SharedHumanoidAppearanceSystem.cs | 22 +--- .../SharedHumanoidMarkingModifierSystem.cs | 1 - .../Implants/Components/ImplanterComponent.cs | 43 ++----- .../Components/InteractionRelayComponent.cs | 19 +-- .../SharedInteractionSystem.Relay.cs | 22 +--- .../Interaction/SharedInteractionSystem.cs | 4 - .../Jittering/JitteringComponent.cs | 39 ++---- .../Jittering/SharedJitteringSystem.cs | 17 --- Content.Shared/Lathe/LatheComponent.cs | 40 +++---- Content.Shared/Lathe/LatheMessages.cs | 5 +- Content.Shared/Lathe/SharedLatheSystem.cs | 28 ----- .../InsertingMaterialStorageComponent.cs | 21 +--- .../Materials/MaterialReclaimerComponent.cs | 61 ++++------ .../Materials/MaterialStorageComponent.cs | 46 +++----- .../SharedMaterialReclaimerSystem.cs | 21 ---- .../Materials/SharedMaterialStorageSystem.cs | 37 +----- .../Mech/Components/MechComponent.cs | 67 ++++------- .../Mech/Components/MechPilotComponent.cs | 11 +- .../Mech/EntitySystems/SharedMechSystem.cs | 52 -------- .../Components/FootstepModifierComponent.cs | 19 ++- .../Components/InputMoverComponent.cs | 15 ++- .../Components/JetpackUserComponent.cs | 3 +- .../Movement/Components/MobMoverComponent.cs | 11 +- .../MovementSpeedModifierComponent.cs | 29 ++--- .../Systems/MovementSpeedModifierSystem.cs | 39 ------ .../Movement/Systems/SharedJetpackSystem.cs | 25 ---- .../SharedMoverController.Footsteps.cs | 35 ------ .../Systems/SharedMoverController.Input.cs | 57 +-------- .../Systems/SharedMoverController.Mob.cs | 39 ------ .../Movement/Systems/SharedMoverController.cs | 22 ++-- .../Controllers/SharedConveyorController.cs | 19 --- .../Physics/PreventCollideComponent.cs | 14 +-- .../Physics/SharedPreventCollideSystem.cs | 19 +-- .../Placeable/ItemPlacerComponent.cs | 9 +- Content.Shared/Placeable/ItemPlacerSystem.cs | 32 ----- .../Placeable/PlaceableSurfaceComponent.cs | 39 ++---- .../Placeable/PlaceableSurfaceSystem.cs | 26 +--- .../Points/PointManagerComponent.cs | 22 +--- .../Radiation/Components/GeigerComponent.cs | 27 ++--- .../Shuttles/Components/IFFComponent.cs | 7 +- .../Components/RadarConsoleComponent.cs | 5 +- .../Systems/SharedRadarConsoleSystem.cs | 31 ----- .../Systems/SharedShuttleSystem.IFF.cs | 33 ------ .../Shuttles/Systems/SharedShuttleSystem.cs | 5 - Content.Shared/Slippery/SlipperyComponent.cs | 25 +--- Content.Shared/Slippery/SlipperySystem.cs | 18 --- Content.Shared/Speech/SpeechComponent.cs | 27 ++--- Content.Shared/Speech/SpeechSystem.cs | 29 ----- .../Standing/StandingStateComponent.cs | 8 +- .../Standing/StandingStateSystem.cs | 36 ------ .../Components/StepTriggerComponent.cs | 46 ++------ .../StepTrigger/Systems/StepTriggerSystem.cs | 38 +----- .../Storage/Components/BinComponent.cs | 32 ++--- .../Storage/EntitySystems/BinSystem.cs | 18 --- .../Components/TabletopDraggableComponent.cs | 5 +- .../Tabletop/SharedTabletopSystem.cs | 7 -- .../Components/LinkedEntityComponent.cs | 20 +--- .../Components/PortalTimeoutComponent.cs | 18 +-- .../Systems/LinkedEntitySystem.cs | 19 +-- .../Systems/SharedPortalSystem.cs | 16 --- Content.Shared/Timing/UseDelayComponent.cs | 57 ++++----- Content.Shared/Timing/UseDelaySystem.cs | 19 +-- .../Tools/Components/MultipleToolComponent.cs | 64 ++++------ .../Systems/SharedToolSystem.MultipleTool.cs | 17 +-- Content.Shared/Vehicle/SharedVehicleSystem.cs | 12 +- .../Weapons/Melee/MeleeWeaponComponent.cs | 62 +++------- .../Weapons/Melee/SharedMeleeWeaponSystem.cs | 26 +--- .../BallisticAmmoProviderComponent.cs | 27 ++--- .../Systems/SharedGunSystem.Ballistic.cs | 36 +----- Content.Shared/Zombies/ZombieComponent.cs | 3 +- .../Alert/ServerAlertsComponentTests.cs | 6 +- 158 files changed, 803 insertions(+), 2863 deletions(-) delete mode 100644 Content.Shared/Alert/AlertsComponentState.cs delete mode 100644 Content.Shared/Movement/Systems/SharedMoverController.Footsteps.cs delete mode 100644 Content.Shared/Movement/Systems/SharedMoverController.Mob.cs diff --git a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs index cb431854845..0c23542f798 100644 --- a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs +++ b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs @@ -1,7 +1,7 @@ +using Content.Shared.Access; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; -using Robust.Client.GameObjects; using Robust.Shared.Prototypes; using static Content.Shared.Access.Components.AccessOverriderComponent; @@ -23,7 +23,7 @@ protected override void Open() { base.Open(); - List accessLevels; + List> accessLevels; if (EntMan.TryGetComponent(Owner, out var accessOverrider)) { @@ -33,7 +33,7 @@ protected override void Open() else { - accessLevels = new List(); + accessLevels = new List>(); _accessOverriderSystem.Log.Error($"No AccessOverrider component found for {EntMan.ToPrettyString(Owner)}!"); } diff --git a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs index 6a4dcba3078..2fd00571215 100644 --- a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs +++ b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs @@ -21,7 +21,7 @@ public sealed partial class AccessOverriderWindow : DefaultWindow private readonly Dictionary _accessButtons = new(); public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototypeManager prototypeManager, - List accessLevels) + List> accessLevels) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -31,7 +31,7 @@ public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototype foreach (var access in accessLevels) { - if (!prototypeManager.TryIndex(access, out var accessLevel)) + if (!prototypeManager.TryIndex(access, out var accessLevel)) { _logMill.Error($"Unable to find accesslevel for {access}"); continue; diff --git a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs index be45e57c8b1..898792aa030 100644 --- a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs +++ b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs @@ -1,8 +1,8 @@ +using Content.Shared.Access; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; using Content.Shared.CrewManifest; -using Robust.Client.GameObjects; using Robust.Shared.Prototypes; using static Content.Shared.Access.Components.IdCardConsoleComponent; @@ -23,7 +23,7 @@ public IdCardConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner protected override void Open() { base.Open(); - List accessLevels; + List> accessLevels; if (EntMan.TryGetComponent(Owner, out var idCard)) { @@ -32,7 +32,7 @@ protected override void Open() } else { - accessLevels = new List(); + accessLevels = new List>(); _idCardConsoleSystem.Log.Error($"No IdCardConsole component found for {EntMan.ToPrettyString(Owner)}!"); } diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs index f8450fe578f..670ba088713 100644 --- a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs +++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs @@ -28,7 +28,7 @@ public sealed partial class IdCardConsoleWindow : DefaultWindow private string? _lastJobProto; public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeManager prototypeManager, - List accessLevels) + List> accessLevels) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); diff --git a/Content.Client/Alerts/ClientAlertsSystem.cs b/Content.Client/Alerts/ClientAlertsSystem.cs index 17f6edb95ff..cfdae7bc931 100644 --- a/Content.Client/Alerts/ClientAlertsSystem.cs +++ b/Content.Client/Alerts/ClientAlertsSystem.cs @@ -1,10 +1,8 @@ using System.Linq; using Content.Shared.Alert; -using Content.Shared.Mobs.Systems; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Player; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; namespace Content.Client.Alerts; @@ -27,7 +25,7 @@ public override void Initialize() SubscribeLocalEvent(OnPlayerAttached); SubscribeLocalEvent(OnPlayerDetached); - SubscribeLocalEvent(ClientAlertsHandleState); + SubscribeLocalEvent(ClientAlertsHandleState); } protected override void LoadPrototypes() { @@ -65,16 +63,10 @@ protected override void AfterClearAlert(AlertsComponent alertsComponent) SyncAlerts?.Invoke(this, alertsComponent.Alerts); } - private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref ComponentHandleState args) + private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref AfterAutoHandleStateEvent args) { - var componentAlerts = (args.Current as AlertsComponentState)?.Alerts; - if (componentAlerts == null) - return; - - component.Alerts = new Dictionary(componentAlerts); - if (_playerManager.LocalPlayer?.ControlledEntity == uid) - SyncAlerts?.Invoke(this, componentAlerts); + SyncAlerts?.Invoke(this, component.Alerts); } private void OnPlayerAttached(EntityUid uid, AlertsComponent component, PlayerAttachedEvent args) diff --git a/Content.Client/BarSign/BarSignSystem.cs b/Content.Client/BarSign/BarSignSystem.cs index 7a289488117..05db00d8194 100644 --- a/Content.Client/BarSign/BarSignSystem.cs +++ b/Content.Client/BarSign/BarSignSystem.cs @@ -1,7 +1,6 @@ using Content.Shared.BarSign; using Content.Shared.Power; using Robust.Client.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; namespace Content.Client.BarSign; @@ -13,33 +12,29 @@ public sealed class BarSignSystem : VisualizerSystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnAfterAutoHandleState); } - private void OnHandleState(EntityUid uid, BarSignComponent component, ref ComponentHandleState args) + private void OnAfterAutoHandleState(EntityUid uid, BarSignComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not BarSignComponentState state) - return; - - component.CurrentSign = state.CurrentSign; - UpdateAppearance(component); + UpdateAppearance(uid, component); } protected override void OnAppearanceChange(EntityUid uid, BarSignComponent component, ref AppearanceChangeEvent args) { - UpdateAppearance(component, args.Component, args.Sprite); + UpdateAppearance(uid, component, args.Component, args.Sprite); } - private void UpdateAppearance(BarSignComponent sign, AppearanceComponent? appearance = null, SpriteComponent? sprite = null) + private void UpdateAppearance(EntityUid id, BarSignComponent sign, AppearanceComponent? appearance = null, SpriteComponent? sprite = null) { - if (!Resolve(sign.Owner, ref appearance, ref sprite)) + if (!Resolve(id, ref appearance, ref sprite)) return; - AppearanceSystem.TryGetData(sign.Owner, PowerDeviceVisuals.Powered, out var powered, appearance); + AppearanceSystem.TryGetData(id, PowerDeviceVisuals.Powered, out var powered, appearance); if (powered - && sign.CurrentSign != null - && _prototypeManager.TryIndex(sign.CurrentSign, out BarSignPrototype? proto)) + && sign.Current != null + && _prototypeManager.TryIndex(sign.Current, out BarSignPrototype? proto)) { sprite.LayerSetState(0, proto.Icon); sprite.LayerSetShader(0, "unshaded"); diff --git a/Content.Client/Buckle/BuckleSystem.cs b/Content.Client/Buckle/BuckleSystem.cs index f09bb1f08ab..db5fa2bd991 100644 --- a/Content.Client/Buckle/BuckleSystem.cs +++ b/Content.Client/Buckle/BuckleSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Buckle.Components; using Content.Shared.Vehicle.Components; using Robust.Client.GameObjects; -using Robust.Shared.GameStates; namespace Content.Client.Buckle; @@ -15,20 +14,12 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnBuckleHandleState); + SubscribeLocalEvent(OnBuckleAfterAutoHandleState); SubscribeLocalEvent(OnAppearanceChange); } - private void OnBuckleHandleState(EntityUid uid, BuckleComponent component, ref ComponentHandleState args) + private void OnBuckleAfterAutoHandleState(EntityUid uid, BuckleComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not BuckleComponentState state) - return; - - component.Buckled = state.Buckled; - component.BuckledTo = EnsureEntity(state.BuckledTo, uid); - component.LastEntityBuckledTo = EnsureEntity(state.LastEntityBuckledTo, uid); - component.DontCollide = state.DontCollide; - ActionBlocker.UpdateCanMove(uid); if (!TryComp(uid, out var ownerSprite)) @@ -38,11 +29,11 @@ private void OnBuckleHandleState(EntityUid uid, BuckleComponent component, ref C return; // Adjust draw depth when the chair faces north so that the seat back is drawn over the player. - // Reset the draw depth when rotated in any other direction. - // TODO when ECSing, make this a visualizer - // This code was written before rotatable viewports were introduced, so hard-coding Direction.North - // and comparing it against LocalRotation now breaks this in other rotations. This is a FIXME, but - // better to get it working for most people before we look at a more permanent solution. + // Reset the draw depth when rotated in any other direction. + // TODO when ECSing, make this a visualizer + // This code was written before rotatable viewports were introduced, so hard-coding Direction.North + // and comparing it against LocalRotation now breaks this in other rotations. This is a FIXME, but + // better to get it working for most people before we look at a more permanent solution. if (component is { Buckled: true, LastEntityBuckledTo: { } } && Transform(component.LastEntityBuckledTo.Value).LocalRotation.GetCardinalDir() == Direction.North && TryComp(component.LastEntityBuckledTo, out var buckledSprite)) diff --git a/Content.Client/Clothing/Systems/ChameleonClothingSystem.cs b/Content.Client/Clothing/Systems/ChameleonClothingSystem.cs index a0142614c7f..f067d910515 100644 --- a/Content.Client/Clothing/Systems/ChameleonClothingSystem.cs +++ b/Content.Client/Clothing/Systems/ChameleonClothingSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Clothing.EntitySystems; using Content.Shared.Inventory; using Robust.Client.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; namespace Content.Client.Clothing.Systems; @@ -27,7 +26,7 @@ public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(HandleState); + SubscribeLocalEvent(HandleState); PrepareAllVariants(); _proto.PrototypesReloaded += OnProtoReloaded; @@ -44,12 +43,8 @@ private void OnProtoReloaded(PrototypesReloadedEventArgs _) PrepareAllVariants(); } - private void HandleState(EntityUid uid, ChameleonClothingComponent component, ref ComponentHandleState args) + private void HandleState(EntityUid uid, ChameleonClothingComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not ChameleonClothingComponentState state) - return; - component.SelectedId = state.SelectedId; - UpdateVisuals(uid, component); } diff --git a/Content.Client/Cuffs/CuffableSystem.cs b/Content.Client/Cuffs/CuffableSystem.cs index e69d2922214..aa5ff81f8a6 100644 --- a/Content.Client/Cuffs/CuffableSystem.cs +++ b/Content.Client/Cuffs/CuffableSystem.cs @@ -17,15 +17,6 @@ public override void Initialize() SubscribeLocalEvent(OnCuffableShutdown); SubscribeLocalEvent(OnCuffableHandleState); - SubscribeLocalEvent(OnHandcuffHandleState); - } - - private void OnHandcuffHandleState(EntityUid uid, HandcuffComponent component, ref ComponentHandleState args) - { - if (args.Current is not HandcuffComponentState state) - return; - - component.OverlayIconState = state.IconState; } private void OnCuffableShutdown(EntityUid uid, CuffableComponent component, ComponentShutdown args) diff --git a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs index 0b37844c6ee..5bae35da5ba 100644 --- a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs +++ b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs @@ -1,14 +1,10 @@ -using System.Linq; -using Content.Shared.Ghost; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Prototypes; using Content.Shared.Preferences; using Robust.Client.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Utility; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Client.Humanoid; @@ -21,34 +17,20 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnHandleState); } - private void OnHandleState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentHandleState args) + private void OnHandleState(EntityUid uid, HumanoidAppearanceComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not HumanoidAppearanceState state) - return; - - ApplyState(uid, component, Comp(uid), state); + UpdateSprite(component, Comp(uid)); } - private void ApplyState(EntityUid uid, HumanoidAppearanceComponent component, SpriteComponent sprite, HumanoidAppearanceState state) + private void UpdateSprite(HumanoidAppearanceComponent component, SpriteComponent sprite) { - component.Sex = state.Sex; - component.Species = state.Species; - component.Age = state.Age; - component.SkinColor = state.SkinColor; - component.EyeColor = state.EyeColor; - component.HiddenLayers = new(state.HiddenLayers); - component.PermanentlyHidden = new(state.PermanentlyHidden); - - component.CustomBaseLayers = state.CustomBaseLayers.ShallowClone(); - UpdateLayers(component, sprite); + ApplyMarkingSet(component, sprite); - ApplyMarkingSet(uid, state.Markings, component, sprite); - - sprite[sprite.LayerMapReserveBlank(HumanoidVisualLayers.Eyes)].Color = state.EyeColor; + sprite[sprite.LayerMapReserveBlank(HumanoidVisualLayers.Eyes)].Color = component.EyeColor; } private static bool IsHidden(HumanoidAppearanceComponent humanoid, HumanoidVisualLayers layer) @@ -60,7 +42,7 @@ private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent component.BaseLayers.Clear(); // add default species layers - var speciesProto = _prototypeManager.Index(component.Species); + var speciesProto = _prototypeManager.Index(component.Species); var baseSprites = _prototypeManager.Index(speciesProto.SpriteSet); foreach (var (key, id) in baseSprites.Sprites) { @@ -73,7 +55,7 @@ private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent foreach (var (key, info) in component.CustomBaseLayers) { oldLayers.Remove(key); - SetLayerData(component, sprite, key, info.ID, sexMorph: false, color: info.Color); ; + SetLayerData(component, sprite, key, info.Id, sexMorph: false, color: info.Color); } // hide old layers @@ -161,12 +143,14 @@ public override void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile // We need to ensure hair before applying it or coloring can try depend on markings that can be invalid var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager) - ? profile.Appearance.SkinColor.WithAlpha(hairAlpha) : profile.Appearance.HairColor; + ? profile.Appearance.SkinColor.WithAlpha(hairAlpha) + : profile.Appearance.HairColor; var hair = new Marking(profile.Appearance.HairStyleId, new[] { hairColor }); var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager) - ? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor; + ? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) + : profile.Appearance.FacialHairColor; var facialHair = new Marking(profile.Appearance.FacialHairStyleId, new[] { facialHairColor }); @@ -200,69 +184,60 @@ public override void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile DebugTools.Assert(IsClientSide(uid)); - var state = new HumanoidAppearanceState(markings, - new(), - new(), - customBaseLayers, - profile.Sex, - profile.Gender, - profile.Age, - profile.Species, - profile.Appearance.SkinColor, - profile.Appearance.EyeColor); - - ApplyState(uid, humanoid, Comp(uid), state); + humanoid.MarkingSet = markings; + humanoid.PermanentlyHidden = new HashSet(); + humanoid.HiddenLayers = new HashSet(); + humanoid.CustomBaseLayers = customBaseLayers; + humanoid.Sex = profile.Sex; + humanoid.Gender = profile.Gender; + humanoid.Age = profile.Age; + humanoid.Species = profile.Species; + humanoid.SkinColor = profile.Appearance.SkinColor; + humanoid.EyeColor = profile.Appearance.EyeColor; + + UpdateSprite(humanoid, Comp(uid)); } - private void ApplyMarkingSet(EntityUid uid, - MarkingSet newMarkings, - HumanoidAppearanceComponent humanoid, - SpriteComponent sprite) + private void ApplyMarkingSet(HumanoidAppearanceComponent humanoid, SpriteComponent sprite) { - // skip this entire thing if both sets are empty - if (humanoid.MarkingSet.Markings.Count == 0 && newMarkings.Markings.Count == 0) - return; - // I am lazy and I CBF resolving the previous mess, so I'm just going to nuke the markings. // Really, markings should probably be a separate component altogether. - - ClearAllMarkings(uid, humanoid, sprite); - - humanoid.MarkingSet = new(newMarkings); + ClearAllMarkings(humanoid, sprite); foreach (var markingList in humanoid.MarkingSet.Markings.Values) { foreach (var marking in markingList) { if (_markingManager.TryGetMarking(marking, out var markingPrototype)) - ApplyMarking(uid, markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite); + ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite); } } + + humanoid.ClientOldMarkings = new MarkingSet(humanoid.MarkingSet); } - private void ClearAllMarkings(EntityUid uid, HumanoidAppearanceComponent humanoid, - SpriteComponent sprite) + private void ClearAllMarkings(HumanoidAppearanceComponent humanoid, SpriteComponent sprite) { - foreach (var markingList in humanoid.MarkingSet.Markings.Values) + foreach (var markingList in humanoid.ClientOldMarkings.Markings.Values) { foreach (var marking in markingList) { - RemoveMarking(uid, marking, sprite); + RemoveMarking(marking, sprite); } } - } - private void ClearMarkings(EntityUid uid, List markings, HumanoidAppearanceComponent humanoid, - SpriteComponent spriteComp) - { - foreach (var marking in markings) + humanoid.ClientOldMarkings.Clear(); + + foreach (var markingList in humanoid.MarkingSet.Markings.Values) { - RemoveMarking(uid, marking, spriteComp); + foreach (var marking in markingList) + { + RemoveMarking(marking, sprite); + } } } - private void RemoveMarking(EntityUid uid, Marking marking, - SpriteComponent spriteComp) + private void RemoveMarking(Marking marking, SpriteComponent spriteComp) { if (!_markingManager.TryGetMarking(marking, out var prototype)) { @@ -286,8 +261,7 @@ private void RemoveMarking(EntityUid uid, Marking marking, spriteComp.RemoveLayer(index); } } - private void ApplyMarking(EntityUid uid, - MarkingPrototype markingPrototype, + private void ApplyMarking(MarkingPrototype markingPrototype, IReadOnlyList? colors, bool visible, HumanoidAppearanceComponent humanoid, @@ -393,7 +367,7 @@ protected override void SetLayerVisibility( foreach (var marking in markingList) { if (_markingManager.TryGetMarking(marking, out var markingPrototype) && markingPrototype.BodyPart == layer) - ApplyMarking(uid, markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite); + ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite); } } } diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs index a1742219fb0..a8872604a4c 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs @@ -1,7 +1,5 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; -using Robust.Client.GameObjects; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Client.Humanoid; diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs index 8cf90c4e63a..4cde587c58c 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs @@ -6,7 +6,6 @@ using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Client.Humanoid; @@ -76,7 +75,7 @@ Dictionary info continue; } - modifier.SetState(true, layerInfo.ID ?? string.Empty, layerInfo.Color ?? Color.White); + modifier.SetState(true, layerInfo.Id ?? string.Empty, layerInfo.Color ?? Color.White); } var eyesColor = Color.White; diff --git a/Content.Client/Implants/ImplanterSystem.cs b/Content.Client/Implants/ImplanterSystem.cs index bf15b9b26b3..6949a94d67c 100644 --- a/Content.Client/Implants/ImplanterSystem.cs +++ b/Content.Client/Implants/ImplanterSystem.cs @@ -2,7 +2,6 @@ using Content.Client.Items; using Content.Shared.Implants; using Content.Shared.Implants.Components; -using Robust.Shared.GameStates; namespace Content.Client.Implants; @@ -12,17 +11,12 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHandleImplanterState); + SubscribeLocalEvent(OnHandleImplanterState); SubscribeLocalEvent(OnItemImplanterStatus); } - private void OnHandleImplanterState(EntityUid uid, ImplanterComponent component, ref ComponentHandleState args) + private void OnHandleImplanterState(EntityUid uid, ImplanterComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not ImplanterComponentState state) - return; - - component.CurrentMode = state.CurrentMode; - component.ImplantOnly = state.ImplantOnly; component.UiUpdateNeeded = true; } diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index 1fd7c78ea40..3b3d90293c1 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -1,6 +1,5 @@ using System.Linq; using System.Text; -using Content.Shared.FixedPoint; using Content.Shared.Lathe; using Content.Shared.Materials; using Content.Shared.Research.Prototypes; @@ -24,7 +23,7 @@ public sealed partial class LatheMenu : DefaultWindow public event Action? OnServerListButtonPressed; public event Action? RecipeQueueAction; public event Action? OnEjectPressed; - public List Recipes = new(); + public List> Recipes = new(); /// /// Default volume for a sheet if the material's entity prototype has no material composition. @@ -115,7 +114,7 @@ public void PopulateRecipes(EntityUid lathe) var recipesToShow = new List(); foreach (var recipe in Recipes) { - if (!_prototypeManager.TryIndex(recipe, out var proto)) + if (!_prototypeManager.TryIndex(recipe, out var proto)) continue; if (SearchBar.Text.Trim().Length != 0) diff --git a/Content.Client/Movement/Systems/ClimbSystem.cs b/Content.Client/Movement/Systems/ClimbSystem.cs index 826c3b0a52d..003b478b30d 100644 --- a/Content.Client/Movement/Systems/ClimbSystem.cs +++ b/Content.Client/Movement/Systems/ClimbSystem.cs @@ -1,7 +1,6 @@ using Content.Client.Interactable; using Content.Shared.Climbing; using Content.Shared.DragDrop; -using Robust.Shared.GameStates; namespace Content.Client.Movement.Systems; @@ -12,19 +11,9 @@ public sealed class ClimbSystem : SharedClimbSystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnClimbingState); SubscribeLocalEvent(OnCanDragDropOn); } - private static void OnClimbingState(EntityUid uid, ClimbingComponent component, ref ComponentHandleState args) - { - if (args.Current is not ClimbingComponent.ClimbModeComponentState climbModeState) - return; - - component.IsClimbing = climbModeState.Climbing; - component.OwnerIsTransitioning = climbModeState.IsTransitioning; - } - protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args) { base.OnCanDragDropOn(uid, component, ref args); diff --git a/Content.Client/Points/PointSystem.cs b/Content.Client/Points/PointSystem.cs index f41c4b09aba..2cc6bd2312b 100644 --- a/Content.Client/Points/PointSystem.cs +++ b/Content.Client/Points/PointSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Points; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Shared.GameStates; namespace Content.Client.Points; @@ -17,17 +16,12 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnGetCharacterInfoControls); } - private void OnHandleState(EntityUid uid, PointManagerComponent component, ref ComponentHandleState args) + private void OnHandleState(EntityUid uid, PointManagerComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not PointManagerComponentState state) - return; - - component.Points = new(state.Points); - component.Scoreboard = state.Scoreboard; _characterInfo.RequestCharacterInfo(); } diff --git a/Content.Client/Radiation/Systems/GeigerSystem.cs b/Content.Client/Radiation/Systems/GeigerSystem.cs index 7a193d4a751..ffb0ad426e3 100644 --- a/Content.Client/Radiation/Systems/GeigerSystem.cs +++ b/Content.Client/Radiation/Systems/GeigerSystem.cs @@ -2,10 +2,6 @@ using Content.Client.Radiation.UI; using Content.Shared.Radiation.Components; using Content.Shared.Radiation.Systems; -using Robust.Client.GameObjects; -using Robust.Client.Player; -using Robust.Shared.GameStates; -using Robust.Shared.Player; namespace Content.Client.Radiation.Systems; @@ -14,19 +10,12 @@ public sealed class GeigerSystem : SharedGeigerSystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnGetStatusMessage); } - private void OnHandleState(EntityUid uid, GeigerComponent component, ref ComponentHandleState args) + private void OnHandleState(EntityUid uid, GeigerComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not GeigerComponentState state) - return; - - component.CurrentRadiation = state.CurrentRadiation; - component.DangerLevel = state.DangerLevel; - component.IsEnabled = state.IsEnabled; - component.User = EnsureEntity(state.User, uid); component.UiUpdateNeeded = true; } diff --git a/Content.Client/Tabletop/TabletopSystem.cs b/Content.Client/Tabletop/TabletopSystem.cs index d43111f39c1..c71c34d0efd 100644 --- a/Content.Client/Tabletop/TabletopSystem.cs +++ b/Content.Client/Tabletop/TabletopSystem.cs @@ -11,7 +11,6 @@ using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.GameStates; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Map; @@ -49,7 +48,6 @@ public override void Initialize() .Register(); SubscribeNetworkEvent(OnTabletopPlay); - SubscribeLocalEvent(HandleComponentState); SubscribeLocalEvent(HandleDraggableRemoved); SubscribeLocalEvent(OnAppearanceChange); } @@ -148,13 +146,6 @@ private void OnTabletopPlay(TabletopPlayEvent msg) _window.OnClose += OnWindowClose; } - private void HandleComponentState(EntityUid uid, TabletopDraggableComponent component, ref ComponentHandleState args) - { - if (args.Current is not TabletopDraggableComponentState state) return; - - component.DraggingPlayer = state.DraggingPlayer; - } - private void OnWindowClose() { if (_table != null) diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs index e0d4fa8e84d..b0e3566bdc8 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs @@ -39,7 +39,7 @@ protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent comp else if (component.UnspawnedCount > 0) { component.UnspawnedCount--; - ent = Spawn(component.FillProto, coordinates); + ent = Spawn(component.Proto, coordinates); EnsureShootable(ent.Value); } diff --git a/Content.Server/Access/Systems/AccessOverriderSystem.cs b/Content.Server/Access/Systems/AccessOverriderSystem.cs index a41c0839da1..3ec767c200d 100644 --- a/Content.Server/Access/Systems/AccessOverriderSystem.cs +++ b/Content.Server/Access/Systems/AccessOverriderSystem.cs @@ -1,15 +1,15 @@ +using System.Linq; +using Content.Server.Popups; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Administration.Logs; using Content.Shared.Database; +using Content.Shared.DoAfter; using Content.Shared.Interaction; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Containers; -using System.Linq; using static Content.Shared.Access.Components.AccessOverriderComponent; -using Content.Server.Popups; -using Content.Shared.DoAfter; namespace Content.Server.Access.Systems; @@ -46,7 +46,7 @@ private void AfterInteractOn(EntityUid uid, AccessOverriderComponent component, if (!_interactionSystem.InRangeUnobstructed(args.User, (EntityUid) args.Target)) return; - var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, component.DoAfterTime, new AccessOverriderDoAfterEvent(), uid, target: args.Target, used: uid) + var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, component.DoAfter, new AccessOverriderDoAfterEvent(), uid, target: args.Target, used: uid) { BreakOnTargetMove = true, BreakOnUserMove = true, diff --git a/Content.Server/BarSign/Systems/BarSignSystem.cs b/Content.Server/BarSign/Systems/BarSignSystem.cs index c26fe2c2884..4a481408452 100644 --- a/Content.Server/BarSign/Systems/BarSignSystem.cs +++ b/Content.Server/BarSign/Systems/BarSignSystem.cs @@ -1,6 +1,5 @@ using System.Linq; using Content.Shared.BarSign; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -15,17 +14,11 @@ public sealed class BarSignSystem : EntitySystem public override void Initialize() { SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnGetState); - } - - private void OnGetState(EntityUid uid, BarSignComponent component, ref ComponentGetState args) - { - args.State = new BarSignComponentState(component.CurrentSign); } private void OnMapInit(EntityUid uid, BarSignComponent component, MapInitEvent args) { - if (component.CurrentSign != null) + if (component.Current != null) return; var prototypes = _prototypeManager @@ -40,7 +33,7 @@ private void OnMapInit(EntityUid uid, BarSignComponent component, MapInitEvent a _metaData.SetEntityName(uid, Loc.GetString(name), meta); _metaData.SetEntityDescription(uid, Loc.GetString(newPrototype.Description), meta); - component.CurrentSign = newPrototype.ID; + component.Current = newPrototype.ID; Dirty(component); } } diff --git a/Content.Server/Climbing/ClimbSystem.cs b/Content.Server/Climbing/ClimbSystem.cs index 73c0eda3f36..e9d25f361f2 100644 --- a/Content.Server/Climbing/ClimbSystem.cs +++ b/Content.Server/Climbing/ClimbSystem.cs @@ -21,7 +21,6 @@ using Content.Shared.Verbs; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Physics; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Components; @@ -62,7 +61,6 @@ public override void Initialize() SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(OnClimbEndCollide); SubscribeLocalEvent(OnBuckleChange); - SubscribeLocalEvent(OnClimbingGetState); SubscribeLocalEvent(OnGlassClimbed); } @@ -366,11 +364,6 @@ private void OnBuckleChange(EntityUid uid, ClimbingComponent component, ref Buck StopClimb(uid, component); } - private static void OnClimbingGetState(EntityUid uid, ClimbingComponent component, ref ComponentGetState args) - { - args.State = new ClimbingComponent.ClimbModeComponentState(component.IsClimbing, component.OwnerIsTransitioning); - } - private void OnGlassClimbed(EntityUid uid, GlassTableComponent component, ClimbedOnEvent args) { if (TryComp(args.Climber, out var physics) && physics.Mass <= component.MassLimit) diff --git a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs index 10fadbbba1c..7dc3b8489df 100644 --- a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs +++ b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs @@ -5,7 +5,6 @@ using Content.Shared.Prototypes; using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -22,22 +21,13 @@ public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(GetState); SubscribeLocalEvent>(OnVerb); SubscribeLocalEvent(OnSelected); } private void OnMapInit(EntityUid uid, ChameleonClothingComponent component, MapInitEvent args) { - SetSelectedPrototype(uid, component.SelectedId, true, component); - } - - private void GetState(EntityUid uid, ChameleonClothingComponent component, ref ComponentGetState args) - { - args.State = new ChameleonClothingComponentState - { - SelectedId = component.SelectedId - }; + SetSelectedPrototype(uid, component.Default, true, component); } private void OnVerb(EntityUid uid, ChameleonClothingComponent component, GetVerbsEvent args) @@ -72,7 +62,7 @@ private void UpdateUi(EntityUid uid, ChameleonClothingComponent? component = nul if (!Resolve(uid, ref component)) return; - var state = new ChameleonBoundUserInterfaceState(component.Slot, component.SelectedId); + var state = new ChameleonBoundUserInterfaceState(component.Slot, component.Default); _uiSystem.TrySetUiState(uid, ChameleonUiKey.Key, state); } @@ -87,7 +77,7 @@ public void SetSelectedPrototype(EntityUid uid, string? protoId, bool forceUpdat // check that wasn't already selected // forceUpdate on component init ignores this check - if (component.SelectedId == protoId && !forceUpdate) + if (component.Default == protoId && !forceUpdate) return; // make sure that it is valid change @@ -95,7 +85,7 @@ public void SetSelectedPrototype(EntityUid uid, string? protoId, bool forceUpdat return; if (!IsValidTarget(proto, component.Slot)) return; - component.SelectedId = protoId; + component.Default = protoId; UpdateIdentityBlocker(uid, component, proto); UpdateVisuals(uid, component); diff --git a/Content.Server/Cuffs/CuffableSystem.cs b/Content.Server/Cuffs/CuffableSystem.cs index 2b65803673b..2c28603c3f4 100644 --- a/Content.Server/Cuffs/CuffableSystem.cs +++ b/Content.Server/Cuffs/CuffableSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Cuffs; -using JetBrains.Annotations; using Content.Shared.Cuffs.Components; +using JetBrains.Annotations; using Robust.Shared.GameStates; namespace Content.Server.Cuffs @@ -12,15 +12,9 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHandcuffGetState); SubscribeLocalEvent(OnCuffableGetState); } - private void OnHandcuffGetState(EntityUid uid, HandcuffComponent component, ref ComponentGetState args) - { - args.State = new HandcuffComponentState(component.OverlayIconState); - } - private void OnCuffableGetState(EntityUid uid, CuffableComponent component, ref ComponentGetState args) { // there are 2 approaches i can think of to handle the handcuff overlay on players @@ -34,7 +28,7 @@ private void OnCuffableGetState(EntityUid uid, CuffableComponent component, ref args.State = new CuffableComponentState(component.CuffedHandCount, component.CanStillInteract, cuffs?.CuffedRSI, - $"{cuffs?.OverlayIconState}-{component.CuffedHandCount}", + $"{cuffs?.BodyIconState}-{component.CuffedHandCount}", cuffs?.Color); // the iconstate is formatted as blah-2, blah-4, blah-6, etc. // the number corresponds to how many hands are cuffed. diff --git a/Content.Server/Doors/Systems/DoorSystem.cs b/Content.Server/Doors/Systems/DoorSystem.cs index aa4de6b86bb..5899baf2fcd 100644 --- a/Content.Server/Doors/Systems/DoorSystem.cs +++ b/Content.Server/Doors/Systems/DoorSystem.cs @@ -1,22 +1,19 @@ using Content.Server.Access; +using Content.Server.Administration.Logs; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; +using Content.Server.Power.EntitySystems; using Content.Shared.Database; -using Content.Shared.Doors; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; using Content.Shared.Emag.Systems; using Content.Shared.Interaction; +using Content.Shared.Prying.Components; +using Content.Shared.Prying.Systems; +using Content.Shared.Tools.Systems; using Robust.Shared.Audio; -using Content.Server.Administration.Logs; -using Content.Server.Power.EntitySystems; -using Content.Shared.Tools; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; -using Content.Shared.DoAfter; -using Content.Shared.Prying.Systems; -using Content.Shared.Prying.Components; -using Content.Shared.Tools.Systems; namespace Content.Server.Doors.Systems; @@ -25,8 +22,6 @@ public sealed class DoorSystem : SharedDoorSystem [Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly AirtightSystem _airtightSystem = default!; - [Dependency] private readonly SharedToolSystem _toolSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly PryingSystem _pryingSystem = default!; public override void Initialize() diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index c6ce90692ff..63517c9962e 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -210,7 +210,7 @@ private void OnElectrifiedInteractUsing(EntityUid uid, ElectrifiedComponent elec return; var siemens = TryComp(args.Used, out var insulation) - ? insulation.SiemensCoefficient + ? insulation.Coefficient : 1; TryDoElectrifiedAct(uid, args.User, siemens, electrified); diff --git a/Content.Server/Implants/ImplanterSystem.cs b/Content.Server/Implants/ImplanterSystem.cs index db5602a2bb9..f3072769e4d 100644 --- a/Content.Server/Implants/ImplanterSystem.cs +++ b/Content.Server/Implants/ImplanterSystem.cs @@ -8,7 +8,6 @@ using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Robust.Shared.Containers; -using Robust.Shared.GameStates; namespace Content.Server.Implants; @@ -24,7 +23,6 @@ public override void Initialize() InitializeImplanted(); SubscribeLocalEvent(OnImplanterAfterInteract); - SubscribeLocalEvent(OnImplanterGetState); SubscribeLocalEvent(OnImplant); SubscribeLocalEvent(OnDraw); @@ -109,11 +107,6 @@ public void TryDraw(ImplanterComponent component, EntityUid user, EntityUid targ } - private void OnImplanterGetState(EntityUid uid, ImplanterComponent component, ref ComponentGetState args) - { - args.State = new ImplanterComponentState(component.CurrentMode, component.ImplantOnly); - } - private void OnImplant(EntityUid uid, ImplanterComponent component, ImplantEvent args) { if (args.Cancelled || args.Handled || args.Target == null || args.Used == null) diff --git a/Content.Server/Lathe/LatheSystem.cs b/Content.Server/Lathe/LatheSystem.cs index 9761ae57657..309ee583162 100644 --- a/Content.Server/Lathe/LatheSystem.cs +++ b/Content.Server/Lathe/LatheSystem.cs @@ -107,11 +107,11 @@ private void OnGetWhitelist(EntityUid uid, LatheComponent component, ref GetMate { if (args.Storage != uid) return; - var materialWhitelist = new List(); + var materialWhitelist = new List>(); var recipes = GetAllBaseRecipes(component); foreach (var id in recipes) { - if (!_proto.TryIndex(id, out var proto)) + if (!_proto.TryIndex(id, out var proto)) continue; foreach (var (mat, _) in proto.RequiredMaterials) { @@ -127,7 +127,7 @@ private void OnGetWhitelist(EntityUid uid, LatheComponent component, ref GetMate } [PublicAPI] - public bool TryGetAvailableRecipes(EntityUid uid, [NotNullWhen(true)] out List? recipes, [NotNullWhen(true)] LatheComponent? component = null) + public bool TryGetAvailableRecipes(EntityUid uid, [NotNullWhen(true)] out List>? recipes, [NotNullWhen(true)] LatheComponent? component = null) { recipes = null; if (!Resolve(uid, ref component)) @@ -136,17 +136,17 @@ public bool TryGetAvailableRecipes(EntityUid uid, [NotNullWhen(true)] out List GetAvailableRecipes(EntityUid uid, LatheComponent component) + public List> GetAvailableRecipes(EntityUid uid, LatheComponent component) { var ev = new LatheGetRecipesEvent(uid) { - Recipes = new List(component.StaticRecipes) + Recipes = new List>(component.StaticRecipes) }; RaiseLocalEvent(uid, ev); return ev.Recipes; } - public static List GetAllBaseRecipes(LatheComponent component) + public static List> GetAllBaseRecipes(LatheComponent component) { return component.StaticRecipes.Union(component.DynamicRecipes).ToList(); } @@ -300,7 +300,7 @@ private void OnPowerChanged(EntityUid uid, LatheComponent component, ref PowerCh private void OnPartsRefresh(EntityUid uid, LatheComponent component, RefreshPartsEvent args) { - var printTimeRating = args.PartRatings[component.MachinePartPrintTime]; + var printTimeRating = args.PartRatings[component.MachinePartPrintSpeed]; var materialUseRating = args.PartRatings[component.MachinePartMaterialUse]; component.TimeMultiplier = MathF.Pow(component.PartRatingPrintTimeMultiplier, printTimeRating - 1); diff --git a/Content.Server/Points/PointSystem.cs b/Content.Server/Points/PointSystem.cs index c3265701c07..56831980d0f 100644 --- a/Content.Server/Points/PointSystem.cs +++ b/Content.Server/Points/PointSystem.cs @@ -5,7 +5,6 @@ using Robust.Server.GameObjects; using Robust.Server.GameStates; using Robust.Server.Player; -using Robust.Shared.GameStates; using Robust.Shared.Utility; namespace Content.Server.Points; @@ -22,7 +21,6 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnGetState); } private void OnStartup(EntityUid uid, PointManagerComponent component, ComponentStartup args) @@ -30,11 +28,6 @@ private void OnStartup(EntityUid uid, PointManagerComponent component, Component _pvsOverride.AddGlobalOverride(uid); } - private void OnGetState(EntityUid uid, PointManagerComponent component, ref ComponentGetState args) - { - args.State = new PointManagerComponentState(component.Points, component.Scoreboard); - } - /// /// Adds the specified point value to a player. /// diff --git a/Content.Server/Radiation/Systems/GeigerSystem.cs b/Content.Server/Radiation/Systems/GeigerSystem.cs index 050b1698192..640a257694d 100644 --- a/Content.Server/Radiation/Systems/GeigerSystem.cs +++ b/Content.Server/Radiation/Systems/GeigerSystem.cs @@ -5,8 +5,6 @@ using Content.Shared.Inventory.Events; using Content.Shared.Radiation.Components; using Content.Shared.Radiation.Systems; -using Robust.Shared.GameStates; -using Robust.Shared.Player; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -32,7 +30,6 @@ public override void Initialize() SubscribeLocalEvent(OnUnequippedHand); SubscribeLocalEvent(OnUpdate); - SubscribeLocalEvent(OnGetState); } private void OnActivate(EntityUid uid, GeigerComponent component, ActivateInWorldEvent args) @@ -86,17 +83,6 @@ private void OnUpdate(RadiationSystemUpdatedEvent ev) } } - private void OnGetState(EntityUid uid, GeigerComponent component, ref ComponentGetState args) - { - args.State = new GeigerComponentState - { - CurrentRadiation = component.CurrentRadiation, - DangerLevel = component.DangerLevel, - IsEnabled = component.IsEnabled, - User = GetNetEntity(component.User) - }; - } - private void SetCurrentRadiation(EntityUid uid, GeigerComponent component, float rads) { // check that it's approx equal diff --git a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs index 67866e6e5a7..fcd42f5a288 100644 --- a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs +++ b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs @@ -110,7 +110,7 @@ private void TurnOff(EntityUid uid, EnergySwordComponent comp, ref EnergySwordDe { weaponComp.HitSound = comp.OnHitOff; if (comp.Secret) - weaponComp.HideFromExamine = true; + weaponComp.Hidden = true; } if (comp.IsSharp) @@ -135,7 +135,7 @@ private void TurnOn(EntityUid uid, EnergySwordComponent comp, ref EnergySwordAct { weaponComp.HitSound = comp.OnHitOn; if (comp.Secret) - weaponComp.HideFromExamine = false; + weaponComp.Hidden = false; } if (TryComp(uid, out var malus)) diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index c4fec25139f..a0a3f6d5d7b 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -8,11 +8,13 @@ using Content.Server.CombatMode.Disarm; using Content.Server.Contests; using Content.Server.Movement.Systems; -using Content.Shared.Administration.Components; using Content.Shared.Actions.Events; +using Content.Shared.Administration.Components; using Content.Shared.CombatMode; using Content.Shared.Damage.Events; +using Content.Shared.Damage.Systems; using Content.Shared.Database; +using Content.Shared.Effects; using Content.Shared.FixedPoint; using Content.Shared.Hands.Components; using Content.Shared.IdentityManagement; @@ -29,8 +31,6 @@ using Robust.Shared.Player; using Robust.Shared.Players; using Robust.Shared.Random; -using Content.Shared.Effects; -using Content.Shared.Damage.Systems; namespace Content.Server.Weapons.Melee; @@ -57,7 +57,7 @@ public override void Initialize() private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args) { - if (component.HideFromExamine) + if (component.Hidden) return; var damageSpec = GetDamage(uid, args.User, component); diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs index ef3127e39bf..a2990c20376 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs @@ -22,7 +22,7 @@ protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent comp else if (component.UnspawnedCount > 0) { component.UnspawnedCount--; - ent = Spawn(component.FillProto, coordinates); + ent = Spawn(component.Proto, coordinates); EnsureShootable(ent.Value); } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 0acb20f5a24..0859cb94427 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -54,12 +54,12 @@ public override void Initialize() private void OnBallisticPrice(EntityUid uid, BallisticAmmoProviderComponent component, ref PriceCalculationEvent args) { - if (string.IsNullOrEmpty(component.FillProto) || component.UnspawnedCount == 0) + if (string.IsNullOrEmpty(component.Proto) || component.UnspawnedCount == 0) return; - if (!ProtoManager.TryIndex(component.FillProto, out var proto)) + if (!ProtoManager.TryIndex(component.Proto, out var proto)) { - Log.Error($"Unable to find fill prototype for price on {component.FillProto} on {ToPrettyString(uid)}"); + Log.Error($"Unable to find fill prototype for price on {component.Proto} on {ToPrettyString(uid)}"); return; } diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 19e80132208..3014edd1b9a 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -12,7 +12,6 @@ using Content.Server.NPC.Components; using Content.Server.NPC.HTN; using Content.Server.NPC.Systems; -using Content.Server.Nutrition.Components; using Content.Server.Roles; using Content.Server.Speech.Components; using Content.Server.Temperature.Components; @@ -113,7 +112,7 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) //This is the actual damage of the zombie. We assign the visual appearance //and range here because of stuff we'll find out later var melee = EnsureComp(target); - melee.ClickAnimation = zombiecomp.AttackAnimation; + melee.Animation = zombiecomp.AttackAnimation; melee.WideAnimation = zombiecomp.AttackAnimation; melee.Range = 1.2f; diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index 0d51da03ae8..1f8f5fbd42f 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -255,7 +255,7 @@ public bool UnZombify(EntityUid source, EntityUid target, ZombieComponent? zombi foreach (var (layer, info) in zombiecomp.BeforeZombifiedCustomBaseLayers) { _humanoidAppearance.SetBaseLayerColor(target, layer, info.Color); - _humanoidAppearance.SetBaseLayerId(target, layer, info.ID); + _humanoidAppearance.SetBaseLayerId(target, layer, info.Id); } if(TryComp(target, out var appcomp)) { diff --git a/Content.Shared/Access/Components/AccessOverriderComponent.cs b/Content.Shared/Access/Components/AccessOverriderComponent.cs index 459cc24f0ca..4e1a376ab62 100644 --- a/Content.Shared/Access/Components/AccessOverriderComponent.cs +++ b/Content.Shared/Access/Components/AccessOverriderComponent.cs @@ -2,22 +2,22 @@ using Content.Shared.Containers.ItemSlots; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Access.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedAccessOverriderSystem))] public sealed partial class AccessOverriderComponent : Component { public static string PrivilegedIdCardSlotId = "AccessOverrider-privilegedId"; - [DataField("privilegedIdSlot")] + [DataField] public ItemSlot PrivilegedIdSlot = new(); [ViewVariables(VVAccess.ReadWrite)] - [DataField("denialSound")] + [DataField] public SoundSpecifier? DenialSound; public EntityUid TargetAccessReaderId = new(); @@ -33,12 +33,12 @@ public WriteToTargetAccessReaderIdMessage(List accessList) } } - [DataField("accessLevels", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List AccessLevels = new(); + [DataField, AutoNetworkedField(true)] + public List> AccessLevels = new(); [ViewVariables(VVAccess.ReadWrite)] - [DataField("doAfter")] - public float DoAfterTime = 0f; + [DataField] + public float DoAfter; [Serializable, NetSerializable] public sealed class AccessOverriderBoundUserInterfaceState : BoundUserInterfaceState diff --git a/Content.Shared/Access/Components/IdCardConsoleComponent.cs b/Content.Shared/Access/Components/IdCardConsoleComponent.cs index 7edd9614f1d..51336a66255 100644 --- a/Content.Shared/Access/Components/IdCardConsoleComponent.cs +++ b/Content.Shared/Access/Components/IdCardConsoleComponent.cs @@ -1,12 +1,12 @@ using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Access.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedIdCardConsoleSystem))] public sealed partial class IdCardConsoleComponent : Component { @@ -16,10 +16,10 @@ public sealed partial class IdCardConsoleComponent : Component public static string PrivilegedIdCardSlotId = "IdCardConsole-privilegedId"; public static string TargetIdCardSlotId = "IdCardConsole-targetId"; - [DataField("privilegedIdSlot")] + [DataField] public ItemSlot PrivilegedIdSlot = new(); - [DataField("targetIdSlot")] + [DataField] public ItemSlot TargetIdSlot = new(); [Serializable, NetSerializable] @@ -41,8 +41,8 @@ public WriteToTargetIdMessage(string fullName, string jobTitle, List acc // Put this on shared so we just send the state once in PVS range rather than every time the UI updates. - [DataField("accessLevels", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List AccessLevels = new() + [DataField, AutoNetworkedField] + public List> AccessLevels = new() { "Armory", "Atmospherics", diff --git a/Content.Shared/Access/Systems/SharedAccessOverriderSystem.cs b/Content.Shared/Access/Systems/SharedAccessOverriderSystem.cs index c19fe697e6c..36c74ed0dd8 100644 --- a/Content.Shared/Access/Systems/SharedAccessOverriderSystem.cs +++ b/Content.Shared/Access/Systems/SharedAccessOverriderSystem.cs @@ -2,7 +2,6 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.DoAfter; using JetBrains.Annotations; -using Robust.Shared.GameStates; using Robust.Shared.Serialization; namespace Content.Shared.Access.Systems @@ -23,19 +22,6 @@ public override void Initialize() SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnComponentRemove); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnHandleState(EntityUid uid, AccessOverriderComponent component, ref ComponentHandleState args) - { - if (args.Current is not AccessOverriderComponentState state) return; - component.AccessLevels = state.AccessLevels; - } - - private void OnGetState(EntityUid uid, AccessOverriderComponent component, ref ComponentGetState args) - { - args.State = new AccessOverriderComponentState(component.AccessLevels); } private void OnComponentInit(EntityUid uid, AccessOverriderComponent component, ComponentInit args) @@ -48,17 +34,6 @@ private void OnComponentRemove(EntityUid uid, AccessOverriderComponent component _itemSlotsSystem.RemoveItemSlot(uid, component.PrivilegedIdSlot); } - [Serializable, NetSerializable] - private sealed class AccessOverriderComponentState : ComponentState - { - public List AccessLevels; - - public AccessOverriderComponentState(List accessLevels) - { - AccessLevels = accessLevels; - } - } - [Serializable, NetSerializable] public sealed partial class AccessOverriderDoAfterEvent : DoAfterEvent { diff --git a/Content.Shared/Access/Systems/SharedIdCardConsoleSystem.cs b/Content.Shared/Access/Systems/SharedIdCardConsoleSystem.cs index 9abb91de473..12e25e1e229 100644 --- a/Content.Shared/Access/Systems/SharedIdCardConsoleSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardConsoleSystem.cs @@ -1,8 +1,6 @@ using Content.Shared.Access.Components; using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Access.Systems { @@ -22,19 +20,6 @@ public override void Initialize() SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnComponentRemove); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnHandleState(EntityUid uid, IdCardConsoleComponent component, ref ComponentHandleState args) - { - if (args.Current is not IdCardConsoleComponentState state) return; - component.AccessLevels = state.AccessLevels; - } - - private void OnGetState(EntityUid uid, IdCardConsoleComponent component, ref ComponentGetState args) - { - args.State = new IdCardConsoleComponentState(component.AccessLevels); } private void OnComponentInit(EntityUid uid, IdCardConsoleComponent component, ComponentInit args) @@ -48,16 +33,5 @@ private void OnComponentRemove(EntityUid uid, IdCardConsoleComponent component, _itemSlotsSystem.RemoveItemSlot(uid, component.PrivilegedIdSlot); _itemSlotsSystem.RemoveItemSlot(uid, component.TargetIdSlot); } - - [Serializable, NetSerializable] - private sealed class IdCardConsoleComponentState : ComponentState - { - public List AccessLevels; - - public IdCardConsoleComponentState(List accessLevels) - { - AccessLevels = accessLevels; - } - } } } diff --git a/Content.Shared/Alert/AlertsComponent.cs b/Content.Shared/Alert/AlertsComponent.cs index 4468db44638..05b11e19efb 100644 --- a/Content.Shared/Alert/AlertsComponent.cs +++ b/Content.Shared/Alert/AlertsComponent.cs @@ -6,11 +6,12 @@ namespace Content.Shared.Alert; /// Handles the icons on the right side of the screen. /// Should only be used for player-controlled entities. /// -[RegisterComponent] -[NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class AlertsComponent : Component { - [ViewVariables] public Dictionary Alerts = new(); + [ViewVariables] + [AutoNetworkedField] + public Dictionary Alerts = new(); public override bool SendOnlyToOwner => true; } diff --git a/Content.Shared/Alert/AlertsComponentState.cs b/Content.Shared/Alert/AlertsComponentState.cs deleted file mode 100644 index c503338ea84..00000000000 --- a/Content.Shared/Alert/AlertsComponentState.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Alert; - -[Serializable, NetSerializable] -public sealed class AlertsComponentState : ComponentState -{ - public Dictionary Alerts; - - public AlertsComponentState(Dictionary alerts) - { - Alerts = alerts; - } -} diff --git a/Content.Shared/Alert/AlertsSystem.cs b/Content.Shared/Alert/AlertsSystem.cs index 37c49a46ce8..db6911f12b2 100644 --- a/Content.Shared/Alert/AlertsSystem.cs +++ b/Content.Shared/Alert/AlertsSystem.cs @@ -1,5 +1,4 @@ using System.Diagnostics.CodeAnalysis; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; namespace Content.Shared.Alert; @@ -170,7 +169,6 @@ public override void Initialize() SubscribeLocalEvent(HandleComponentStartup); SubscribeLocalEvent(HandleComponentShutdown); - SubscribeLocalEvent(ClientAlertsGetState); SubscribeNetworkEvent(HandleClickAlert); LoadPrototypes(); @@ -243,9 +241,4 @@ private void HandleClickAlert(ClickAlertEvent msg, EntitySessionEventArgs args) alert.OnClick?.AlertClicked(player.Value); } - - private static void ClientAlertsGetState(EntityUid uid, AlertsComponent component, ref ComponentGetState args) - { - args.State = new AlertsComponentState(component.Alerts); - } } diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index e1e15561f81..07fc603e26f 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -2,7 +2,6 @@ using Content.Shared.Damage; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Anomaly.Components; @@ -14,7 +13,8 @@ namespace Content.Shared.Anomaly.Components; /// /// Anomalies and their related components were designed here: https://hackmd.io/@ss14-design/r1sQbkJOs /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedAnomalySystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedAnomalySystem))] public sealed partial class AnomalyComponent : Component { /// @@ -27,7 +27,7 @@ public sealed partial class AnomalyComponent : Component /// Note that this doesn't refer to stability as a percentage: This is an arbitrary /// value that only matters in relation to the and /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float Stability = 0f; /// @@ -39,7 +39,7 @@ public sealed partial class AnomalyComponent : Component /// /// Wacky-Stability scale lives on in my heart. - emo /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float Severity = 0f; #region Health @@ -49,7 +49,7 @@ public sealed partial class AnomalyComponent : Component /// When the health of an anomaly reaches 0, it is destroyed without ever /// reaching a supercritical point. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float Health = 1f; /// @@ -85,25 +85,26 @@ public sealed partial class AnomalyComponent : Component /// /// The time at which the next artifact pulse will occur. /// - [DataField("nextPulseTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] public TimeSpan NextPulseTime = TimeSpan.Zero; /// /// The minimum interval between pulses. /// - [DataField("minPulseLength")] + [DataField] public TimeSpan MinPulseLength = TimeSpan.FromMinutes(1); /// /// The maximum interval between pulses. /// - [DataField("maxPulseLength")] + [DataField] public TimeSpan MaxPulseLength = TimeSpan.FromMinutes(2); /// /// A percentage by which the length of a pulse might vary. /// - [DataField("pulseVariation")] + [DataField] public float PulseVariation = 0.1f; /// @@ -112,19 +113,19 @@ public sealed partial class AnomalyComponent : Component /// /// This is more likely to trend upwards than donwards, because that's funny /// - [DataField("pulseStabilityVariation")] + [DataField] public Vector2 PulseStabilityVariation = new(-0.1f, 0.15f); /// /// The sound played when an anomaly pulses /// - [DataField("pulseSound")] + [DataField] public SoundSpecifier? PulseSound = new SoundCollectionSpecifier("RadiationPulse"); /// /// The sound plays when an anomaly goes supercritical /// - [DataField("supercriticalSound")] + [DataField] public SoundSpecifier? SupercriticalSound = new SoundCollectionSpecifier("explosion"); #endregion @@ -134,7 +135,7 @@ public sealed partial class AnomalyComponent : Component /// /// +/- 0.2 from perfect stability (0.5) /// - [DataField("initialStabilityRange")] + [DataField] public (float, float) InitialStabilityRange = (0.4f, 0.6f); /// @@ -143,25 +144,25 @@ public sealed partial class AnomalyComponent : Component /// /// Between 0 and 0.5, which should be all mild effects /// - [DataField("initialSeverityRange")] + [DataField] public (float, float) InitialSeverityRange = (0.1f, 0.5f); /// /// The particle type that increases the severity of the anomaly. /// - [DataField("severityParticleType")] + [DataField] public AnomalousParticleType SeverityParticleType; /// /// The particle type that destabilizes the anomaly. /// - [DataField("destabilizingParticleType")] + [DataField] public AnomalousParticleType DestabilizingParticleType; /// /// The particle type that weakens the anomalys health. /// - [DataField("weakeningParticleType")] + [DataField] public AnomalousParticleType WeakeningParticleType; #region Points and Vessels @@ -197,14 +198,14 @@ public sealed partial class AnomalyComponent : Component /// The amount of damage dealt when either a player touches the anomaly /// directly or by hitting the anomaly. /// - [DataField("anomalyContactDamage", required: true)] + [DataField(required: true)] public DamageSpecifier AnomalyContactDamage = default!; /// /// The sound effect played when a player /// burns themselves on an anomaly via contact. /// - [DataField("anomalyContactDamageSound")] + [DataField] public SoundSpecifier AnomalyContactDamageSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); #region Floating Animation @@ -226,23 +227,6 @@ public sealed partial class AnomalyComponent : Component #endregion } -[Serializable, NetSerializable] -public sealed class AnomalyComponentState : ComponentState -{ - public float Severity; - public float Stability; - public float Health; - public TimeSpan NextPulseTime; - - public AnomalyComponentState(float severity, float stability, float health, TimeSpan nextPulseTime) - { - Severity = severity; - Stability = stability; - Health = health; - NextPulseTime = nextPulseTime; - } -} - /// /// Event raised at regular intervals on an anomaly to do whatever its effect is. /// diff --git a/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs b/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs index e5101fef667..bd8f40852d8 100644 --- a/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs @@ -1,5 +1,4 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Anomaly.Components; @@ -7,31 +6,27 @@ namespace Content.Shared.Anomaly.Components; /// /// Tracks anomalies going supercritical /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedAnomalySystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedAnomalySystem))] public sealed partial class AnomalySupercriticalComponent : Component { /// /// The time when the supercritical animation ends and it does whatever effect. /// - [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] public TimeSpan EndTime; /// /// The length of the animation before it goes supercritical. /// + [AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] public TimeSpan SupercriticalDuration = TimeSpan.FromSeconds(10); /// /// The maximum size the anomaly scales to while going supercritical /// - [DataField("maxScaleAmount")] + [DataField] public float MaxScaleAmount = 3; } - -[Serializable, NetSerializable] -public sealed class AnomalySupercriticalComponentState : ComponentState -{ - public TimeSpan EndTime; - public TimeSpan Duration; -} diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index 12a97fda42a..4b2b3ada70a 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -5,7 +5,6 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Weapons.Melee.Events; -using Robust.Shared.GameStates; using Robust.Shared.Network; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -30,10 +29,6 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnAnomalyGetState); - SubscribeLocalEvent(OnAnomalyHandleState); - SubscribeLocalEvent(OnSupercriticalGetState); - SubscribeLocalEvent(OnSupercriticalHandleState); SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnAttacked); @@ -44,43 +39,6 @@ public override void Initialize() _sawmill = Logger.GetSawmill("anomaly"); } - private void OnAnomalyGetState(EntityUid uid, AnomalyComponent component, ref ComponentGetState args) - { - args.State = new AnomalyComponentState( - component.Severity, - component.Stability, - component.Health, - component.NextPulseTime); - } - - private void OnAnomalyHandleState(EntityUid uid, AnomalyComponent component, ref ComponentHandleState args) - { - if (args.Current is not AnomalyComponentState state) - return; - component.Severity = state.Severity; - component.Stability = state.Stability; - component.Health = state.Health; - component.NextPulseTime = state.NextPulseTime; - } - - private void OnSupercriticalGetState(EntityUid uid, AnomalySupercriticalComponent component, ref ComponentGetState args) - { - args.State = new AnomalySupercriticalComponentState - { - EndTime = component.EndTime, - Duration = component.SupercriticalDuration - }; - } - - private void OnSupercriticalHandleState(EntityUid uid, AnomalySupercriticalComponent component, ref ComponentHandleState args) - { - if (args.Current is not AnomalySupercriticalComponentState state) - return; - - component.EndTime = state.EndTime; - component.SupercriticalDuration = state.Duration; - } - private void OnInteractHand(EntityUid uid, AnomalyComponent component, InteractHandEvent args) { DoAnomalyBurnDamage(uid, args.User, component); diff --git a/Content.Shared/BarSign/BarSignComponent.cs b/Content.Shared/BarSign/BarSignComponent.cs index 182597ba2e6..d50726216e6 100644 --- a/Content.Shared/BarSign/BarSignComponent.cs +++ b/Content.Shared/BarSign/BarSignComponent.cs @@ -1,24 +1,10 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; -namespace Content.Shared.BarSign -{ - [RegisterComponent, NetworkedComponent] - public sealed partial class BarSignComponent : Component - { - [DataField("current", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string? CurrentSign; - } - - [Serializable, NetSerializable] - public sealed class BarSignComponentState : ComponentState - { - public string? CurrentSign; +namespace Content.Shared.BarSign; - public BarSignComponentState(string? current) - { - CurrentSign = current; - } - } +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class BarSignComponent : Component +{ + [DataField, AutoNetworkedField] public ProtoId? Current; } diff --git a/Content.Shared/Body/Components/BodyComponent.cs b/Content.Shared/Body/Components/BodyComponent.cs index a93f1e2fd80..481e22150b0 100644 --- a/Content.Shared/Body/Components/BodyComponent.cs +++ b/Content.Shared/Body/Components/BodyComponent.cs @@ -4,18 +4,17 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; namespace Content.Shared.Body.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedBodySystem))] public sealed partial class BodyComponent : Component { /// /// Relevant template to spawn for this body. /// - [DataField] + [DataField, AutoNetworkedField] public ProtoId? Prototype; /// @@ -29,35 +28,17 @@ public sealed partial class BodyComponent : Component [ViewVariables] public string RootPartSlot => RootContainer.ID; - [DataField] public SoundSpecifier GibSound = new SoundCollectionSpecifier("gib"); + [DataField, AutoNetworkedField] + public SoundSpecifier GibSound = new SoundCollectionSpecifier("gib"); /// /// The amount of legs required to move at full speed. /// If 0, then legs do not impact speed. /// - [DataField] public int RequiredLegs; + [DataField, AutoNetworkedField] + public int RequiredLegs; [ViewVariables] - [DataField] + [DataField, AutoNetworkedField] public HashSet LegEntities = new(); } - -[Serializable, NetSerializable] -public sealed class BodyComponentState : ComponentState -{ - public string? Prototype; - public string? RootPartSlot; - public SoundSpecifier GibSound; - public int RequiredLegs; - public HashSet LegNetEntities; - - public BodyComponentState(string? prototype, string? rootPartSlot, SoundSpecifier gibSound, - int requiredLegs, HashSet legNetEntities) - { - Prototype = prototype; - RootPartSlot = rootPartSlot; - GibSound = gibSound; - RequiredLegs = requiredLegs; - LegNetEntities = legNetEntities; - } -} diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs index 9356224f412..072826f08b3 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs @@ -6,9 +6,7 @@ using Content.Shared.Body.Prototypes; using Content.Shared.DragDrop; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Map; -using MapInitEvent = Robust.Shared.GameObjects.MapInitEvent; namespace Content.Shared.Body.Systems; @@ -30,8 +28,6 @@ private void InitializeBody() SubscribeLocalEvent(OnBodyInit); SubscribeLocalEvent(OnBodyMapInit); SubscribeLocalEvent(OnBodyCanDrag); - SubscribeLocalEvent(OnBodyGetState); - SubscribeLocalEvent(OnBodyHandleState); } private void OnBodyInserted(EntityUid uid, BodyComponent component, EntInsertedIntoContainerMessage args) @@ -82,28 +78,6 @@ private void OnBodyRemoved(EntityUid uid, BodyComponent component, EntRemovedFro } } - private void OnBodyHandleState(EntityUid uid, BodyComponent component, ref ComponentHandleState args) - { - if (args.Current is not BodyComponentState state) - return; - - component.Prototype = state.Prototype != null ? state.Prototype : null!; - component.GibSound = state.GibSound; - component.RequiredLegs = state.RequiredLegs; - component.LegEntities = EntityManager.EnsureEntitySet(state.LegNetEntities, uid); - } - - private void OnBodyGetState(EntityUid uid, BodyComponent component, ref ComponentGetState args) - { - args.State = new BodyComponentState( - component.Prototype, - component.RootPartSlot, - component.GibSound, - component.RequiredLegs, - EntityManager.GetNetEntitySet(component.LegEntities) - ); - } - private void OnBodyInit(EntityUid bodyId, BodyComponent body, ComponentInit args) { // Setup the initial container. diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index 8f44c7fead3..cf28b56d51f 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -4,7 +4,7 @@ namespace Content.Shared.Buckle.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] [Access(typeof(SharedBuckleSystem))] public sealed partial class BuckleComponent : Component { @@ -13,7 +13,7 @@ public sealed partial class BuckleComponent : Component /// Separated from normal interaction range to fix the "someone buckled to a strap /// across a table two tiles away" problem. /// - [DataField("range")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public float Range = SharedInteractionSystem.InteractionRange / 1.4f; @@ -21,32 +21,34 @@ public sealed partial class BuckleComponent : Component /// True if the entity is buckled, false otherwise. /// [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public bool Buckled; [ViewVariables] + [AutoNetworkedField] public EntityUid? LastEntityBuckledTo; /// /// Whether or not collisions should be possible with the entity we are strapped to /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("dontCollide")] + [DataField, AutoNetworkedField] public bool DontCollide; /// /// Whether or not we should be allowed to pull the entity we are strapped to /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("pullStrap")] + [DataField] public bool PullStrap; /// /// The amount of time that must pass for this entity to /// be able to unbuckle after recently buckling. /// - [DataField("delay")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] - public TimeSpan UnbuckleDelay = TimeSpan.FromSeconds(0.25f); + public TimeSpan Delay = TimeSpan.FromSeconds(0.25f); /// /// The time that this entity buckled at. @@ -58,39 +60,21 @@ public sealed partial class BuckleComponent : Component /// The strap that this component is buckled to. /// [ViewVariables] + [AutoNetworkedField] public EntityUid? BuckledTo; /// /// The amount of space that this entity occupies in a /// . /// - [DataField("size")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public int Size = 100; /// /// Used for client rendering /// - [ViewVariables] - public int? OriginalDrawDepth; -} - -[Serializable, NetSerializable] -public sealed class BuckleComponentState : ComponentState -{ - public BuckleComponentState(bool buckled, NetEntity? buckledTo, NetEntity? lastEntityBuckledTo, - bool dontCollide) - { - Buckled = buckled; - BuckledTo = buckledTo; - LastEntityBuckledTo = lastEntityBuckledTo; - DontCollide = dontCollide; - } - - public readonly bool Buckled; - public readonly NetEntity? BuckledTo; - public readonly NetEntity? LastEntityBuckledTo; - public readonly bool DontCollide; + [ViewVariables] public int? OriginalDrawDepth; } [ByRefEvent] diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index 8cb11ddd435..4efe154797c 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -8,28 +8,29 @@ namespace Content.Shared.Buckle.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedBuckleSystem), typeof(SharedVehicleSystem))] public sealed partial class StrapComponent : Component { /// /// The entities that are currently buckled /// + [AutoNetworkedField(true)] [ViewVariables] // TODO serialization - public readonly HashSet BuckledEntities = new(); + public HashSet BuckledEntities = new(); /// /// Entities that this strap accepts and can buckle /// If null it accepts any entity /// - [DataField("allowedEntities")] + [DataField] [ViewVariables] public EntityWhitelist? AllowedEntities; /// /// The change in position to the strapped mob /// - [DataField("position")] + [DataField, AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] public StrapPosition Position = StrapPosition.None; @@ -43,7 +44,7 @@ public sealed partial class StrapComponent : Component /// whereas the server doesnt, thus the client tries to unbuckle like 15 times because it passes the strap null check /// This is why this needs to be above 0.1 to make the InRange check fail in both client and server. /// - [DataField("maxBuckleDistance", required: false)] + [DataField, AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] public float MaxBuckleDistance = 0.2f; @@ -51,8 +52,8 @@ public sealed partial class StrapComponent : Component /// Gets and clamps the buckle offset to MaxBuckleDistance /// [ViewVariables] - public Vector2 BuckleOffset => Vector2.Clamp( - BuckleOffsetUnclamped, + public Vector2 BuckleOffsetClamped => Vector2.Clamp( + BuckleOffset, Vector2.One * -MaxBuckleDistance, Vector2.One * MaxBuckleDistance); @@ -60,21 +61,21 @@ public sealed partial class StrapComponent : Component /// The buckled entity will be offset by this amount from the center of the strap object. /// If this offset it too big, it will be clamped to /// - [DataField("buckleOffset", required: false)] + [DataField, AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] - public Vector2 BuckleOffsetUnclamped = Vector2.Zero; + public Vector2 BuckleOffset = Vector2.Zero; /// /// The angle in degrees to rotate the player by when they get strapped /// - [DataField("rotation")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public int Rotation; /// /// The size of the strap which is compared against when buckling entities /// - [DataField("size")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public int Size = 100; @@ -87,58 +88,39 @@ public sealed partial class StrapComponent : Component /// /// You can specify the offset the entity will have after unbuckling. /// - [DataField("unbuckleOffset", required: false)] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public Vector2 UnbuckleOffset = Vector2.Zero; /// /// The sound to be played when a mob is buckled /// - [DataField("buckleSound")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier BuckleSound = new SoundPathSpecifier("/Audio/Effects/buckle.ogg"); /// /// The sound to be played when a mob is unbuckled /// - [DataField("unbuckleSound")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier UnbuckleSound = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg"); /// /// ID of the alert to show when buckled /// - [DataField("buckledAlertType")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public AlertType BuckledAlertType = AlertType.Buckled; /// /// The sum of the sizes of all the buckled entities in this strap /// + [AutoNetworkedField] [ViewVariables] public int OccupiedSize; } -[Serializable, NetSerializable] -public sealed class StrapComponentState : ComponentState -{ - public readonly StrapPosition Position; - public readonly float MaxBuckleDistance; - public readonly Vector2 BuckleOffsetClamped; - public readonly HashSet BuckledEntities; - public readonly int OccupiedSize; - - public StrapComponentState(StrapPosition position, Vector2 offset, HashSet buckled, - float maxBuckleDistance, int occupiedSize) - { - Position = position; - BuckleOffsetClamped = offset; - BuckledEntities = buckled; - MaxBuckleDistance = maxBuckleDistance; - OccupiedSize = occupiedSize; - } -} - public enum StrapPosition { /// diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 3fb77df97d7..020b47f7081 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -12,14 +12,12 @@ using Content.Shared.Movement.Events; using Content.Shared.Popups; using Content.Shared.Pulling.Components; -using Content.Shared.Pulling.Events; using Content.Shared.Standing; using Content.Shared.Storage.Components; using Content.Shared.Stunnable; using Content.Shared.Throwing; using Content.Shared.Vehicle.Components; using Content.Shared.Verbs; -using Robust.Shared.GameStates; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Utility; @@ -32,7 +30,6 @@ private void InitializeBuckle() { SubscribeLocalEvent(OnBuckleComponentStartup); SubscribeLocalEvent(OnBuckleComponentShutdown); - SubscribeLocalEvent(OnBuckleComponentGetState); SubscribeLocalEvent(OnBuckleMove); SubscribeLocalEvent(OnBuckleInteractHand); SubscribeLocalEvent>(AddUnbuckleVerb); @@ -58,11 +55,6 @@ private void OnBuckleComponentShutdown(EntityUid uid, BuckleComponent component, component.BuckleTime = default; } - private void OnBuckleComponentGetState(EntityUid uid, BuckleComponent component, ref ComponentGetState args) - { - args.State = new BuckleComponentState(component.Buckled, GetNetEntity(component.BuckledTo), GetNetEntity(component.LastEntityBuckledTo), component.DontCollide); - } - private void OnBuckleMove(EntityUid uid, BuckleComponent component, ref MoveEvent ev) { if (component.BuckledTo is not {} strapUid) @@ -434,7 +426,7 @@ public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force = fal if (attemptEvent.Cancelled) return false; - if (_gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.UnbuckleDelay) + if (_gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay) return false; if (!_interaction.InRangeUnobstructed(userUid, strapUid, buckleComp.Range, popup: true)) diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs index 7ffbfd3a42b..8616546480b 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs @@ -7,7 +7,6 @@ using Content.Shared.Storage; using Content.Shared.Verbs; using Robust.Shared.Containers; -using Robust.Shared.GameStates; namespace Content.Shared.Buckle; @@ -19,9 +18,6 @@ private void InitializeStrap() SubscribeLocalEvent(OnStrapShutdown); SubscribeLocalEvent((_, c, _) => StrapRemoveAll(c)); - SubscribeLocalEvent(OnStrapGetState); - SubscribeLocalEvent(OnStrapHandleState); - SubscribeLocalEvent(OnStrapEntModifiedFromContainer); SubscribeLocalEvent(OnStrapEntModifiedFromContainer); SubscribeLocalEvent>(AddStrapVerbs); @@ -50,24 +46,6 @@ private void OnStrapShutdown(EntityUid uid, StrapComponent component, ComponentS StrapRemoveAll(component); } - private void OnStrapGetState(EntityUid uid, StrapComponent component, ref ComponentGetState args) - { - args.State = new StrapComponentState(component.Position, component.BuckleOffset, GetNetEntitySet(component.BuckledEntities), component.MaxBuckleDistance, component.OccupiedSize); - } - - private void OnStrapHandleState(EntityUid uid, StrapComponent component, ref ComponentHandleState args) - { - if (args.Current is not StrapComponentState state) - return; - - component.Position = state.Position; - component.BuckleOffsetUnclamped = state.BuckleOffsetClamped; - component.BuckledEntities.Clear(); - component.BuckledEntities.UnionWith(EnsureEntitySet(state.BuckledEntities, uid)); - component.MaxBuckleDistance = state.MaxBuckleDistance; - component.OccupiedSize = state.OccupiedSize; - } - private void OnStrapEntModifiedFromContainer(EntityUid uid, StrapComponent component, ContainerModifiedMessage message) { if (_gameTiming.ApplyingState) diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 3c9cb1f9744..81d479ca34c 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -65,7 +65,7 @@ private void ReAttach( || !Resolve(buckleUid, ref buckleComp, false)) return; - _transform.SetCoordinates(buckleUid, new EntityCoordinates(strapUid, strapComp.BuckleOffset)); + _transform.SetCoordinates(buckleUid, new EntityCoordinates(strapUid, strapComp.BuckleOffsetClamped)); var buckleTransform = Transform(buckleUid); diff --git a/Content.Shared/Cabinet/ItemCabinetComponent.cs b/Content.Shared/Cabinet/ItemCabinetComponent.cs index 4f49badfa99..71367e8de68 100644 --- a/Content.Shared/Cabinet/ItemCabinetComponent.cs +++ b/Content.Shared/Cabinet/ItemCabinetComponent.cs @@ -1,65 +1,43 @@ using Content.Shared.Containers.ItemSlots; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Cabinet; /// /// Used for entities that can be opened, closed, and can hold one item. E.g., fire extinguisher cabinets. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ItemCabinetComponent : Component { /// /// Sound to be played when the cabinet door is opened. /// - [DataField("doorSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier? DoorSound; /// /// The that stores the actual item. The entity whitelist, sounds, and other /// behaviours are specified by this definition. /// - [DataField("cabinetSlot"), ViewVariables] + [DataField, ViewVariables] public ItemSlot CabinetSlot = new(); /// /// Whether the cabinet is currently open or not. /// - [DataField("opened")] + [DataField, AutoNetworkedField] public bool Opened; /// /// The state for when the cabinet is open /// - [DataField("openState"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] public string? OpenState; /// /// The state for when the cabinet is closed /// - [DataField("closedState"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] public string? ClosedState; } - -[Serializable, NetSerializable] -public sealed class ItemCabinetComponentState : ComponentState -{ - public SoundSpecifier? DoorSound; - - public bool Opened; - - public string? OpenState; - - public string? ClosedState; - - public ItemCabinetComponentState(SoundSpecifier? doorSound, bool opened, string? openState, string? closedState) - { - DoorSound = doorSound; - Opened = opened; - OpenState = openState; - ClosedState = closedState; - } -} - diff --git a/Content.Shared/Cabinet/SharedItemCabinetSystem.cs b/Content.Shared/Cabinet/SharedItemCabinetSystem.cs index 96461f22497..f2f03c13349 100644 --- a/Content.Shared/Cabinet/SharedItemCabinetSystem.cs +++ b/Content.Shared/Cabinet/SharedItemCabinetSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.Verbs; using Robust.Shared.Audio; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -19,9 +18,6 @@ public abstract class SharedItemCabinetSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnComponentRemove); SubscribeLocalEvent(OnComponentStartup); @@ -35,24 +31,6 @@ public override void Initialize() SubscribeLocalEvent(OnLockToggleAttempt); } - private void OnGetState(EntityUid uid, ItemCabinetComponent component, ref ComponentGetState args) - { - args.State = new ItemCabinetComponentState(component.DoorSound, - component.Opened, - component.OpenState, - component.ClosedState); - } - - private void OnHandleState(EntityUid uid, ItemCabinetComponent component, ref ComponentHandleState args) - { - if (args.Current is not ItemCabinetComponentState state) - return; - component.DoorSound = state.DoorSound; - component.Opened = state.Opened; - component.OpenState = state.OpenState; - component.ClosedState = state.ClosedState; - } - private void OnComponentInit(EntityUid uid, ItemCabinetComponent cabinet, ComponentInit args) { _itemSlots.AddItemSlot(uid, "ItemCabinet", cabinet.CabinetSlot); diff --git a/Content.Shared/CartridgeLoader/CartridgeComponent.cs b/Content.Shared/CartridgeLoader/CartridgeComponent.cs index 775cc33d810..ba7e6fe2d58 100644 --- a/Content.Shared/CartridgeLoader/CartridgeComponent.cs +++ b/Content.Shared/CartridgeLoader/CartridgeComponent.cs @@ -7,25 +7,19 @@ namespace Content.Shared.CartridgeLoader; /// /// This is used for defining values used for displaying in the program ui in yaml /// -[NetworkedComponent] -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class CartridgeComponent : Component { - [DataField("programName", required: true)] + [DataField(required: true)] public string ProgramName = "default-program-name"; - [DataField("icon")] + [DataField] public SpriteSpecifier? Icon; + [AutoNetworkedField] public InstallationStatus InstallationStatus = InstallationStatus.Cartridge; } -[Serializable, NetSerializable] -public sealed class CartridgeComponentState : ComponentState -{ - public InstallationStatus InstallationStatus; -} - [Serializable, NetSerializable] public enum InstallationStatus { diff --git a/Content.Shared/CartridgeLoader/SharedCartridgeLoaderSystem.cs b/Content.Shared/CartridgeLoader/SharedCartridgeLoaderSystem.cs index 15d29689b84..806723de1e6 100644 --- a/Content.Shared/CartridgeLoader/SharedCartridgeLoaderSystem.cs +++ b/Content.Shared/CartridgeLoader/SharedCartridgeLoaderSystem.cs @@ -1,7 +1,5 @@ using Content.Shared.Containers.ItemSlots; using Robust.Shared.Containers; -using Robust.Shared.GameStates; -using Robust.Shared.Map; using Robust.Shared.Network; namespace Content.Shared.CartridgeLoader; @@ -24,10 +22,6 @@ public override void Initialize() SubscribeLocalEvent(OnItemInserted); SubscribeLocalEvent(OnItemRemoved); - - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } private void OnComponentInit(EntityUid uid, CartridgeLoaderComponent loader, ComponentInit args) @@ -55,22 +49,6 @@ protected virtual void OnItemRemoved(EntityUid uid, CartridgeLoaderComponent loa UpdateAppearanceData(uid, loader); } - private void OnGetState(EntityUid uid, CartridgeComponent component, ref ComponentGetState args) - { - var state = new CartridgeComponentState(); - state.InstallationStatus = component.InstallationStatus; - - args.State = state; - } - - private void OnHandleState(EntityUid uid, CartridgeComponent component, ref ComponentHandleState args) - { - if (args.Current is not CartridgeComponentState state) - return; - - component.InstallationStatus = state.InstallationStatus; - } - private void UpdateAppearanceData(EntityUid uid, CartridgeLoaderComponent loader) { _appearanceSystem.SetData(uid, CartridgeLoaderVisuals.CartridgeInserted, loader.CartridgeSlot.HasItem); diff --git a/Content.Shared/Chemistry/Components/MovespeedModifierMetabolismComponent.cs b/Content.Shared/Chemistry/Components/MovespeedModifierMetabolismComponent.cs index f0a0c22ba57..62127ab5337 100644 --- a/Content.Shared/Chemistry/Components/MovespeedModifierMetabolismComponent.cs +++ b/Content.Shared/Chemistry/Components/MovespeedModifierMetabolismComponent.cs @@ -1,39 +1,22 @@ -using Robust.Shared.Serialization; using Robust.Shared.GameStates; namespace Content.Shared.Chemistry.Components { //TODO: refactor movement modifier component because this is a pretty poor solution - [RegisterComponent] - [NetworkedComponent] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MovespeedModifierMetabolismComponent : Component { - [ViewVariables] + [AutoNetworkedField, ViewVariables] public float WalkSpeedModifier { get; set; } - [ViewVariables] + [AutoNetworkedField, ViewVariables] public float SprintSpeedModifier { get; set; } /// /// When the current modifier is expected to end. /// - [ViewVariables] + [AutoNetworkedField, ViewVariables] public TimeSpan ModifierTimer { get; set; } = TimeSpan.Zero; - - [Serializable, NetSerializable] - public sealed class MovespeedModifierMetabolismComponentState : ComponentState - { - public float WalkSpeedModifier { get; } - public float SprintSpeedModifier { get; } - public TimeSpan ModifierTimer { get; } - - public MovespeedModifierMetabolismComponentState(float walkSpeedModifier, float sprintSpeedModifier, TimeSpan modifierTimer) - { - WalkSpeedModifier = walkSpeedModifier; - SprintSpeedModifier = sprintSpeedModifier; - ModifierTimer = modifierTimer; - } - } } } diff --git a/Content.Shared/Chemistry/MetabolismMovespeedModifierSystem.cs b/Content.Shared/Chemistry/MetabolismMovespeedModifierSystem.cs index cfa7446caa5..6b7c75514fc 100644 --- a/Content.Shared/Chemistry/MetabolismMovespeedModifierSystem.cs +++ b/Content.Shared/Chemistry/MetabolismMovespeedModifierSystem.cs @@ -1,9 +1,6 @@ using Content.Shared.Chemistry.Components; -using Robust.Shared.GameStates; -using Robust.Shared.Timing; -using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; -using static Content.Shared.Chemistry.Components.MovespeedModifierMetabolismComponent; +using Robust.Shared.Timing; namespace Content.Shared.Chemistry { @@ -21,30 +18,10 @@ public override void Initialize() UpdatesOutsidePrediction = true; - SubscribeLocalEvent(OnMovespeedHandleState); - SubscribeLocalEvent(OnGetState); SubscribeLocalEvent(AddComponent); SubscribeLocalEvent(OnRefreshMovespeed); } - private void OnGetState(EntityUid uid, MovespeedModifierMetabolismComponent component, ref ComponentGetState args) - { - args.State = new MovespeedModifierMetabolismComponentState( - component.WalkSpeedModifier, - component.SprintSpeedModifier, - component.ModifierTimer); - } - - private void OnMovespeedHandleState(EntityUid uid, MovespeedModifierMetabolismComponent component, ref ComponentHandleState args) - { - if (args.Current is not MovespeedModifierMetabolismComponentState cast) - return; - - component.WalkSpeedModifier = cast.WalkSpeedModifier; - component.SprintSpeedModifier = cast.SprintSpeedModifier; - component.ModifierTimer = cast.ModifierTimer; - } - private void OnRefreshMovespeed(EntityUid uid, MovespeedModifierMetabolismComponent component, RefreshMovementSpeedModifiersEvent args) { args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); diff --git a/Content.Shared/Climbing/ClimbingComponent.cs b/Content.Shared/Climbing/ClimbingComponent.cs index 40e192d8ef0..cd443af6aad 100644 --- a/Content.Shared/Climbing/ClimbingComponent.cs +++ b/Content.Shared/Climbing/ClimbingComponent.cs @@ -1,21 +1,20 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Climbing; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ClimbingComponent : Component { /// /// Whether the owner is climbing on a climbable entity. /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public bool IsClimbing { get; set; } /// /// Whether the owner is being moved onto the climbed entity. /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public bool OwnerIsTransitioning { get; set; } /// @@ -25,17 +24,4 @@ public sealed partial class ClimbingComponent : Component [ViewVariables] public Dictionary DisabledFixtureMasks { get; } = new(); - - [Serializable, NetSerializable] - public sealed class ClimbModeComponentState : ComponentState - { - public ClimbModeComponentState(bool climbing, bool isTransitioning) - { - Climbing = climbing; - IsTransitioning = isTransitioning; - } - - public bool Climbing { get; } - public bool IsTransitioning { get; } - } } diff --git a/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs b/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs index d2f2138670f..def4254304f 100644 --- a/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs +++ b/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs @@ -3,14 +3,13 @@ using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Clothing.Components; /// /// Allow players to change clothing sprite to any other clothing prototype. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] [Access(typeof(SharedChameleonClothingSystem))] public sealed partial class ChameleonClothingComponent : Component { @@ -18,15 +17,15 @@ public sealed partial class ChameleonClothingComponent : Component /// Filter possible chameleon options by their slot flag. /// [ViewVariables(VVAccess.ReadOnly)] - [DataField("slot", required: true)] + [DataField(required: true)] public SlotFlags Slot; /// /// EntityPrototype id that chameleon item is trying to mimic. /// [ViewVariables(VVAccess.ReadOnly)] - [DataField("default", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? SelectedId; + [DataField(required: true), AutoNetworkedField] + public EntProtoId? Default; /// /// Current user that wears chameleon clothing. @@ -35,12 +34,6 @@ public sealed partial class ChameleonClothingComponent : Component public EntityUid? User; } -[Serializable, NetSerializable] -public sealed class ChameleonClothingComponentState : ComponentState -{ - public string? SelectedId; -} - [Serializable, NetSerializable] public sealed class ChameleonBoundUserInterfaceState : BoundUserInterfaceState { diff --git a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs index 34b48bc2926..beac22270c8 100644 --- a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs @@ -38,8 +38,8 @@ private void OnGotUnequipped(EntityUid uid, ChameleonClothingComponent component // This 100% makes sure that server and client have exactly same data. protected void UpdateVisuals(EntityUid uid, ChameleonClothingComponent component) { - if (string.IsNullOrEmpty(component.SelectedId) || - !_proto.TryIndex(component.SelectedId, out EntityPrototype? proto)) + if (string.IsNullOrEmpty(component.Default) || + !_proto.TryIndex(component.Default, out EntityPrototype? proto)) return; // world sprite icon diff --git a/Content.Shared/Conveyor/ConveyorComponent.cs b/Content.Shared/Conveyor/ConveyorComponent.cs index 2af859b4a1d..6c95d68c982 100644 --- a/Content.Shared/Conveyor/ConveyorComponent.cs +++ b/Content.Shared/Conveyor/ConveyorComponent.cs @@ -1,66 +1,49 @@ using Content.Shared.DeviceLinking; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Conveyor; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ConveyorComponent : Component { /// /// The angle to move entities by in relation to the owner's rotation. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("angle")] + [DataField, AutoNetworkedField] public Angle Angle = Angle.Zero; /// /// The amount of units to move the entity by per second. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("speed")] + [DataField, AutoNetworkedField] public float Speed = 2f; /// /// The current state of this conveyor /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public ConveyorState State; - [ViewVariables] + [ViewVariables, AutoNetworkedField] public bool Powered; - [DataField("forwardPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ForwardPort = "Forward"; + [DataField] + public ProtoId ForwardPort = "Forward"; - [DataField("reversePort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ReversePort = "Reverse"; + [DataField] + public ProtoId ReversePort = "Reverse"; - [DataField("offPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string OffPort = "Off"; + [DataField] + public ProtoId OffPort = "Off"; [ViewVariables] public readonly HashSet Intersecting = new(); } -[Serializable, NetSerializable] -public sealed class ConveyorComponentState : ComponentState -{ - public bool Powered; - public Angle Angle; - public float Speed; - public ConveyorState State; - - public ConveyorComponentState(Angle angle, float speed, ConveyorState state, bool powered) - { - Angle = angle; - Speed = speed; - State = state; - Powered = powered; - } -} - [Serializable, NetSerializable] public enum ConveyorVisuals : byte { diff --git a/Content.Shared/Cuffs/Components/HandcuffComponent.cs b/Content.Shared/Cuffs/Components/HandcuffComponent.cs index da44ee01ff7..b43bf18bf8f 100644 --- a/Content.Shared/Cuffs/Components/HandcuffComponent.cs +++ b/Content.Shared/Cuffs/Components/HandcuffComponent.cs @@ -2,53 +2,50 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Utility; namespace Content.Shared.Cuffs.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedCuffableSystem))] public sealed partial class HandcuffComponent : Component { /// /// The time it takes to cuff an entity. /// - [DataField("cuffTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float CuffTime = 3.5f; /// /// The time it takes to uncuff an entity. /// - [DataField("uncuffTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float UncuffTime = 3.5f; /// /// The time it takes for a cuffed entity to uncuff itself. /// - [DataField("breakoutTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float BreakoutTime = 30f; /// /// If an entity being cuffed is stunned, this amount of time is subtracted from the time it takes to add/remove their cuffs. /// - [DataField("stunBonus"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float StunBonus = 2f; /// /// Will the cuffs break when removed? /// - [DataField("breakOnRemove"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool BreakOnRemove; /// /// Will the cuffs break when removed? /// - [DataField("brokenPrototype", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] - public string? BrokenPrototype; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public EntProtoId? BrokenPrototype; - [DataField("damageOnResist"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public DamageSpecifier DamageOnResist = new() { DamageDict = new() @@ -60,48 +57,37 @@ public sealed partial class HandcuffComponent : Component /// /// The path of the RSI file used for the player cuffed overlay. /// - [DataField("cuffedRSI"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string? CuffedRSI = "Objects/Misc/handcuffs.rsi"; /// /// The iconstate used with the RSI file for the player cuffed overlay. /// - [DataField("bodyIconState"), ViewVariables(VVAccess.ReadWrite)] - public string? OverlayIconState = "body-overlay"; + [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public string? BodyIconState = "body-overlay"; /// - /// An opptional color specification for + /// An opptional color specification for /// - [DataField("color"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public Color Color = Color.White; - [DataField("startCuffSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier StartCuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_start.ogg"); - [DataField("endCuffSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier EndCuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_end.ogg"); - [DataField("startBreakoutSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier StartBreakoutSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_breakout_start.ogg"); - [DataField("startUncuffSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier StartUncuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_takeoff_start.ogg"); - [DataField("endUncuffSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier EndUncuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_takeoff_end.ogg"); } -[Serializable, NetSerializable] -public sealed class HandcuffComponentState : ComponentState -{ - public readonly string? IconState; - - public HandcuffComponentState(string? iconState) - { - IconState = iconState; - } -} - /// /// Event fired on the User when the User attempts to cuff the Target. /// Should generate popups on the User. diff --git a/Content.Shared/Damage/Components/StaminaComponent.cs b/Content.Shared/Damage/Components/StaminaComponent.cs index 3cdc90ecb1e..74e0f6c8529 100644 --- a/Content.Shared/Damage/Components/StaminaComponent.cs +++ b/Content.Shared/Damage/Components/StaminaComponent.cs @@ -6,48 +6,48 @@ namespace Content.Shared.Damage.Components; /// /// Add to an entity to paralyze it whenever it reaches critical amounts of Stamina DamageType. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class StaminaComponent : Component { /// /// Have we reached peak stamina damage and been paralyzed? /// - [ViewVariables(VVAccess.ReadWrite), DataField("critical")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public bool Critical; /// /// How much stamina reduces per second. /// - [ViewVariables(VVAccess.ReadWrite), DataField("decay")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float Decay = 3f; /// /// How much time after receiving damage until stamina starts decreasing. /// - [ViewVariables(VVAccess.ReadWrite), DataField("cooldown")] - public float DecayCooldown = 3f; + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public float Cooldown = 3f; /// /// How much stamina damage this entity has taken. /// - [ViewVariables(VVAccess.ReadWrite), DataField("staminaDamage")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float StaminaDamage; /// /// How much stamina damage is required to entire stam crit. /// - [ViewVariables(VVAccess.ReadWrite), DataField("critThreshold")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float CritThreshold = 100f; /// /// How long will this mob be stunned for? /// - [ViewVariables(VVAccess.ReadWrite), DataField("stunTime")] + [ViewVariables(VVAccess.ReadWrite), DataField] public TimeSpan StunTime = TimeSpan.FromSeconds(6); /// /// To avoid continuously updating our data we track the last time we updated so we can extrapolate our current stamina. /// - [DataField("nextUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] public TimeSpan NextUpdate = TimeSpan.Zero; } diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index 7bf2941dacf..40c4f7eb8f2 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -16,11 +16,9 @@ using Content.Shared.Weapons.Melee.Events; using JetBrains.Annotations; using Robust.Shared.Audio; -using Robust.Shared.GameStates; using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Random; -using Robust.Shared.Serialization; using Robust.Shared.Timing; namespace Content.Shared.Damage.Systems; @@ -52,8 +50,7 @@ public override void Initialize() SubscribeLocalEvent(OnStamUnpaused); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnStamGetState); - SubscribeLocalEvent(OnStamHandleState); + SubscribeLocalEvent(OnStamHandleState); SubscribeLocalEvent(OnDisarmed); SubscribeLocalEvent(OnRejuvenate); @@ -67,31 +64,8 @@ private void OnStamUnpaused(EntityUid uid, StaminaComponent component, ref Entit component.NextUpdate += args.PausedTime; } - private void OnStamGetState(EntityUid uid, StaminaComponent component, ref ComponentGetState args) + private void OnStamHandleState(EntityUid uid, StaminaComponent component, ref AfterAutoHandleStateEvent args) { - args.State = new StaminaComponentState() - { - Critical = component.Critical, - Decay = component.Decay, - CritThreshold = component.CritThreshold, - DecayCooldown = component.DecayCooldown, - LastUpdate = component.NextUpdate, - StaminaDamage = component.StaminaDamage, - }; - } - - private void OnStamHandleState(EntityUid uid, StaminaComponent component, ref ComponentHandleState args) - { - if (args.Current is not StaminaComponentState state) - return; - - component.Critical = state.Critical; - component.Decay = state.Decay; - component.CritThreshold = state.CritThreshold; - component.DecayCooldown = state.DecayCooldown; - component.NextUpdate = state.LastUpdate; - component.StaminaDamage = state.StaminaDamage; - if (component.Critical) EnterStamCrit(uid, component); else @@ -283,7 +257,7 @@ public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? comp // Reset the decay cooldown upon taking damage. if (oldDamage < component.StaminaDamage) { - var nextUpdate = _timing.CurTime + TimeSpan.FromSeconds(component.DecayCooldown); + var nextUpdate = _timing.CurTime + TimeSpan.FromSeconds(component.Cooldown); if (component.NextUpdate < nextUpdate) component.NextUpdate = nextUpdate; @@ -419,18 +393,6 @@ private void ExitStamCrit(EntityUid uid, StaminaComponent? component = null) Dirty(component); _adminLogger.Add(LogType.Stamina, LogImpact.Low, $"{ToPrettyString(uid):user} recovered from stamina crit"); } - - [Serializable, NetSerializable] - private sealed class StaminaComponentState : ComponentState - { - public bool Critical; - public float Decay; - public float DecayCooldown; - public float StaminaDamage; - public float CritThreshold; - public TimeSpan LastUpdate; - } - } /// diff --git a/Content.Shared/DeviceNetwork/Components/DeviceListComponent.cs b/Content.Shared/DeviceNetwork/Components/DeviceListComponent.cs index e7fee450d12..82217102926 100644 --- a/Content.Shared/DeviceNetwork/Components/DeviceListComponent.cs +++ b/Content.Shared/DeviceNetwork/Components/DeviceListComponent.cs @@ -1,53 +1,36 @@ using Content.Shared.DeviceNetwork.Systems; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.DeviceNetwork.Components; -[RegisterComponent] -[NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedDeviceListSystem))] public sealed partial class DeviceListComponent : Component { /// /// The list of devices can or can't connect to, depending on the field. /// - [DataField("devices")] + [DataField, AutoNetworkedField] public HashSet Devices = new(); /// /// The limit of devices that can be linked to this device list. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("deviceLimit")] + [DataField] public int DeviceLimit = 32; /// /// Whether the device list is used as an allow or deny list /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("isAllowList")] + [DataField, AutoNetworkedField] public bool IsAllowList = true; /// /// Whether this device list also handles incoming device net packets /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("handleIncoming")] - public bool HandleIncomingPackets = false; -} - -[Serializable, NetSerializable] -public sealed class DeviceListComponentState : ComponentState -{ - public readonly HashSet Devices; - public readonly bool IsAllowList; - public readonly bool HandleIncomingPackets; - - public DeviceListComponentState(HashSet devices, bool isAllowList, bool handleIncomingPackets) - { - Devices = devices; - IsAllowList = isAllowList; - HandleIncomingPackets = handleIncomingPackets; - } + [DataField, AutoNetworkedField] + public bool HandleIncomingPackets; } diff --git a/Content.Shared/DeviceNetwork/Components/NetworkConfiguratorComponent.cs b/Content.Shared/DeviceNetwork/Components/NetworkConfiguratorComponent.cs index 910aff4a149..7202b803f81 100644 --- a/Content.Shared/DeviceNetwork/Components/NetworkConfiguratorComponent.cs +++ b/Content.Shared/DeviceNetwork/Components/NetworkConfiguratorComponent.cs @@ -2,72 +2,57 @@ using Content.Shared.DeviceNetwork.Systems; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.DeviceNetwork.Components; -[RegisterComponent] -[NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedNetworkConfiguratorSystem))] public sealed partial class NetworkConfiguratorComponent : Component { /// /// Determines whether the configurator is in linking mode or list mode /// - [DataField("linkModeActive")] + [DataField, AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] public bool LinkModeActive = true; /// /// The entity containing a this configurator is currently interacting with /// - [DataField("activeDeviceList")] - public EntityUid? ActiveDeviceList = null; + [DataField, AutoNetworkedField] + public EntityUid? ActiveDeviceList; /// /// The entity containing a or this configurator is currently interacting with.
/// If this is set the configurator is in linking mode. ///
- [DataField("activeDeviceLink")] - public EntityUid? ActiveDeviceLink = null; + [DataField] + public EntityUid? ActiveDeviceLink; /// /// The target device this configurator is currently linking with the /// - [DataField("deviceLinkTarget")] - public EntityUid? DeviceLinkTarget = null; + [DataField] + public EntityUid? DeviceLinkTarget; /// /// The list of devices stored in the configurator /// - [DataField("devices")] + [DataField] public Dictionary Devices = new(); - [DataField("useDelay")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public TimeSpan UseDelay = TimeSpan.FromSeconds(0.5); - [DataField("lastUseAttempt", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] [ViewVariables(VVAccess.ReadWrite)] public TimeSpan LastUseAttempt; - [DataField("soundNoAccess")] + [DataField] public SoundSpecifier SoundNoAccess = new SoundPathSpecifier("/Audio/Machines/custom_deny.ogg"); - [DataField("soundSwitchMode")] + [DataField] public SoundSpecifier SoundSwitchMode = new SoundPathSpecifier("/Audio/Machines/quickbeep.ogg"); } - -[Serializable, NetSerializable] -public sealed class NetworkConfiguratorComponentState : ComponentState -{ - public readonly NetEntity? ActiveDeviceList; - public readonly bool LinkModeActive; - - public NetworkConfiguratorComponentState(NetEntity? activeDeviceList, bool linkModeActive) - { - ActiveDeviceList = activeDeviceList; - LinkModeActive = linkModeActive; - } -} diff --git a/Content.Shared/DeviceNetwork/Systems/SharedDeviceListSystem.cs b/Content.Shared/DeviceNetwork/Systems/SharedDeviceListSystem.cs index c4d5d688c61..a15d942ad62 100644 --- a/Content.Shared/DeviceNetwork/Systems/SharedDeviceListSystem.cs +++ b/Content.Shared/DeviceNetwork/Systems/SharedDeviceListSystem.cs @@ -1,17 +1,10 @@ using System.Linq; using Content.Shared.DeviceNetwork.Components; -using Robust.Shared.GameStates; namespace Content.Shared.DeviceNetwork.Systems; public abstract class SharedDeviceListSystem : EntitySystem { - public override void Initialize() - { - SubscribeLocalEvent(GetDeviceListState); - SubscribeLocalEvent(HandleDeviceListState); - } - /// /// Updates the device list stored on this entity. /// @@ -57,23 +50,6 @@ public IEnumerable GetAllDevices(EntityUid uid, DeviceListComponent? protected virtual void UpdateShutdownSubscription(EntityUid uid, List devicesList, List oldDevices) { } - - private void GetDeviceListState(EntityUid uid, DeviceListComponent comp, ref ComponentGetState args) - { - args.State = new DeviceListComponentState(GetNetEntitySet(comp.Devices), comp.IsAllowList, comp.HandleIncomingPackets); - } - - private void HandleDeviceListState(EntityUid uid, DeviceListComponent comp, ref ComponentHandleState args) - { - if (args.Current is not DeviceListComponentState state) - { - return; - } - - comp.Devices = EnsureEntitySet(state.Devices, uid); - comp.HandleIncomingPackets = state.HandleIncomingPackets; - comp.IsAllowList = state.IsAllowList; - } } public sealed class DeviceListUpdateEvent : EntityEventArgs diff --git a/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs b/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs index 87f77c8f0a2..4aa9db199dc 100644 --- a/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs +++ b/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs @@ -1,37 +1,10 @@ using Content.Shared.Actions; -using Content.Shared.DeviceNetwork.Components; -using Robust.Shared.GameStates; using Robust.Shared.Serialization; namespace Content.Shared.DeviceNetwork.Systems; public abstract class SharedNetworkConfiguratorSystem : EntitySystem { - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(GetNetworkConfiguratorState); - SubscribeLocalEvent(HandleNetworkConfiguratorState); - } - - private void GetNetworkConfiguratorState(EntityUid uid, NetworkConfiguratorComponent comp, - ref ComponentGetState args) - { - args.State = new NetworkConfiguratorComponentState(GetNetEntity(comp.ActiveDeviceList), comp.LinkModeActive); - } - - private void HandleNetworkConfiguratorState(EntityUid uid, NetworkConfiguratorComponent comp, - ref ComponentHandleState args) - { - if (args.Current is not NetworkConfiguratorComponentState state) - { - return; - } - - comp.ActiveDeviceList = EnsureEntity(state.ActiveDeviceList, uid); - comp.LinkModeActive = state.LinkModeActive; - } } public sealed partial class ClearAllOverlaysEvent : InstantActionEvent diff --git a/Content.Shared/Doors/Components/AirlockComponent.cs b/Content.Shared/Doors/Components/AirlockComponent.cs index c64e1ac518d..486efa8c519 100644 --- a/Content.Shared/Doors/Components/AirlockComponent.cs +++ b/Content.Shared/Doors/Components/AirlockComponent.cs @@ -1,7 +1,6 @@ using Content.Shared.DeviceLinking; using Content.Shared.Doors.Systems; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Doors.Components; @@ -9,16 +8,17 @@ namespace Content.Shared.Doors.Components; /// /// Companion component to DoorComponent that handles airlock-specific behavior -- wires, requiring power to operate, bolts, and allowing automatic closing. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedAirlockSystem), Friend = AccessPermissions.ReadWriteExecute, Other = AccessPermissions.Read)] public sealed partial class AirlockComponent : Component { + // Need to network airlock safety state to avoid mis-predicts when a door auto-closes as the client walks through the door. [ViewVariables(VVAccess.ReadWrite)] - [DataField("safety")] + [DataField, AutoNetworkedField] public bool Safety = true; [ViewVariables(VVAccess.ReadWrite)] - [DataField("emergencyAccess")] + [DataField] public bool EmergencyAccess = false; /// @@ -26,20 +26,20 @@ public sealed partial class AirlockComponent : Component /// Most anything that can pry powered has a pry speed bonus, /// so this default is closer to 6 effectively on e.g. jaws (9 seconds when applied to other default.) /// - [DataField("poweredPryModifier")] + [DataField] public float PoweredPryModifier = 9f; /// /// Whether the maintenance panel should be visible even if the airlock is opened. /// - [DataField("openPanelVisible")] + [DataField] public bool OpenPanelVisible = false; /// /// Whether the airlock should stay open if the airlock was clicked. /// If the airlock was bumped into it will still auto close. /// - [DataField("keepOpenIfClicked")] + [DataField] public bool KeepOpenIfClicked = false; /// @@ -51,7 +51,7 @@ public sealed partial class AirlockComponent : Component /// /// Delay until an open door automatically closes. /// - [DataField("autoCloseDelay")] + [DataField] public TimeSpan AutoCloseDelay = TimeSpan.FromSeconds(5f); /// @@ -64,7 +64,7 @@ public sealed partial class AirlockComponent : Component /// /// The receiver port for turning off automatic closing. /// - [DataField("autoClosePort", customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string AutoClosePort = "AutoClose"; #region Graphics @@ -72,79 +72,68 @@ public sealed partial class AirlockComponent : Component /// /// Whether the door lights should be visible. /// - [DataField("openUnlitVisible")] + [DataField] public bool OpenUnlitVisible = false; /// /// Whether the door should display emergency access lights. /// - [DataField("emergencyAccessLayer")] + [DataField] public bool EmergencyAccessLayer = true; /// /// Whether or not to animate the panel when the door opens or closes. /// - [DataField("animatePanel")] + [DataField] public bool AnimatePanel = true; /// /// The sprite state used to animate the airlock frame when the airlock opens. /// - [DataField("openingSpriteState")] + [DataField] public string OpeningSpriteState = "opening_unlit"; /// /// The sprite state used to animate the airlock panel when the airlock opens. /// - [DataField("openingPanelSpriteState")] + [DataField] public string OpeningPanelSpriteState = "panel_opening"; /// /// The sprite state used to animate the airlock frame when the airlock closes. /// - [DataField("closingSpriteState")] + [DataField] public string ClosingSpriteState = "closing_unlit"; /// /// The sprite state used to animate the airlock panel when the airlock closes. /// - [DataField("closingPanelSpriteState")] + [DataField] public string ClosingPanelSpriteState = "panel_closing"; /// /// The sprite state used for the open airlock lights. /// - [DataField("openSpriteState")] + [DataField] public string OpenSpriteState = "open_unlit"; /// /// The sprite state used for the closed airlock lights. /// - [DataField("closedSpriteState")] + [DataField] public string ClosedSpriteState = "closed_unlit"; /// /// The sprite state used for the 'access denied' lights animation. /// - [DataField("denySpriteState")] + [DataField] public string DenySpriteState = "deny_unlit"; /// /// How long the animation played when the airlock denies access is in seconds. /// - [DataField("denyAnimationTime")] + [DataField] public float DenyAnimationTime = 0.3f; #endregion Graphics } - -[Serializable, NetSerializable] -public sealed class AirlockComponentState : ComponentState -{ - public readonly bool Safety; - - public AirlockComponentState(bool safety) - { - Safety = safety; - } -} diff --git a/Content.Shared/Doors/Components/DoorComponent.cs b/Content.Shared/Doors/Components/DoorComponent.cs index 7cfcba8c5b6..d4d121a87a6 100644 --- a/Content.Shared/Doors/Components/DoorComponent.cs +++ b/Content.Shared/Doors/Components/DoorComponent.cs @@ -1,20 +1,18 @@ -using System.Runtime.InteropServices; using Content.Shared.Damage; using Content.Shared.Doors.Systems; using Content.Shared.Tools; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Timing; using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth; namespace Content.Shared.Doors.Components; -[NetworkedComponent] -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class DoorComponent : Component { /// @@ -24,7 +22,7 @@ public sealed partial class DoorComponent : Component /// This should never be set directly, use instead. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("state")] + [DataField, AutoNetworkedField] [Access(typeof(SharedDoorSystem))] public DoorState State = DoorState.Closed; @@ -35,46 +33,47 @@ public sealed partial class DoorComponent : Component /// /// Closing time until impassable. Total time is this plus . /// - [DataField("closeTimeOne")] + [DataField] public TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.4f); /// /// Closing time until fully closed. Total time is this plus . /// - [DataField("closeTimeTwo")] + [DataField] public TimeSpan CloseTimeTwo = TimeSpan.FromSeconds(0.2f); /// /// Opening time until passable. Total time is this plus . /// - [DataField("openTimeOne")] + [DataField] public TimeSpan OpenTimeOne = TimeSpan.FromSeconds(0.4f); /// /// Opening time until fully open. Total time is this plus . /// - [DataField("openTimeTwo")] + [DataField] public TimeSpan OpenTimeTwo = TimeSpan.FromSeconds(0.2f); /// /// Interval between deny sounds & visuals; /// - [DataField("denyDuration")] + [DataField] public TimeSpan DenyDuration = TimeSpan.FromSeconds(0.45f); - [DataField("emagDuration")] + [DataField] public TimeSpan EmagDuration = TimeSpan.FromSeconds(0.8f); /// /// When the door is active, this is the time when the state will next update. /// + [AutoNetworkedField] public TimeSpan? NextStateChange; /// /// Whether the door is currently partially closed or open. I.e., when the door is "closing" and is already opaque, /// but not yet actually closed. /// - [DataField("partial")] + [DataField, AutoNetworkedField] public bool Partial; #endregion @@ -115,30 +114,30 @@ public sealed partial class DoorComponent : Component /// This is how long a door-crush will stun you. This also determines how long it takes the door to open up /// again. Total stun time is actually given by this plus . /// - [DataField("doorStunTime")] + [DataField] public TimeSpan DoorStunTime = TimeSpan.FromSeconds(2f); - [DataField("crushDamage")] + [DataField] public DamageSpecifier? CrushDamage; /// /// If false, this door is incapable of crushing entities. This just determines whether it will apply damage and /// stun, not whether it can close despite entities being in the way. /// - [DataField("canCrush")] + [DataField] public bool CanCrush = true; /// /// Whether to check for colliding entities before closing. This may be overridden by other system by subscribing to /// . For example, hacked airlocks will set this to false. /// - [DataField("performCollisionCheck")] + [DataField] public bool PerformCollisionCheck = true; /// /// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen(). /// - [DataField("currentlyCrushing")] + [DataField, AutoNetworkedField] public HashSet CurrentlyCrushing = new(); #endregion @@ -152,7 +151,7 @@ public sealed partial class DoorComponent : Component /// /// The sprite state used for the door when it's open. /// - [DataField("openSpriteState")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public string OpenSpriteState = "open"; @@ -165,7 +164,7 @@ public sealed partial class DoorComponent : Component /// /// The sprite state used for the door when it's closed. /// - [DataField("closedSpriteState")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public string ClosedSpriteState = "closed"; @@ -178,37 +177,37 @@ public sealed partial class DoorComponent : Component /// /// The sprite state used for the door when it's opening. /// - [DataField("openingSpriteState")] + [DataField] public string OpeningSpriteState = "opening"; /// /// The sprite state used for the door when it's closing. /// - [DataField("closingSpriteState")] + [DataField] public string ClosingSpriteState = "closing"; /// /// The sprite state used for the door when it's being emagged. /// - [DataField("emaggingSpriteState")] + [DataField] public string EmaggingSpriteState = "emagging"; /// /// The sprite state used for the door when it's open. /// - [DataField("openingAnimationTime")] + [DataField] public float OpeningAnimationTime = 0.8f; /// /// The sprite state used for the door when it's open. /// - [DataField("closingAnimationTime")] + [DataField] public float ClosingAnimationTime = 0.8f; /// /// The sprite state used for the door when it's open. /// - [DataField("emaggingAnimationTime")] + [DataField] public float EmaggingAnimationTime = 1.5f; /// @@ -237,7 +236,7 @@ public sealed partial class DoorComponent : Component /// /// Time until next state change. Because apparently might not get saved/restored. /// - [DataField("SecondsUntilStateChange")] + [DataField] private float? SecondsUntilStateChange { [UsedImplicitly] @@ -262,47 +261,47 @@ private float? SecondsUntilStateChange } #endregion - [DataField("canPry"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool CanPry = true; - [DataField("pryingQuality", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string PryingQuality = "Prying"; + [DataField] + public ProtoId PryingQuality = "Prying"; /// /// Default time that the door should take to pry open. /// - [DataField("pryTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float PryTime = 1.5f; - [DataField("changeAirtight")] + [DataField] public bool ChangeAirtight = true; /// /// Whether the door blocks light. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("occludes")] + [DataField] public bool Occludes = true; /// /// Whether the door will open when it is bumped into. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("bumpOpen")] + [DataField] public bool BumpOpen = true; /// /// Whether the door will open when it is activated or clicked. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("clickOpen")] + [DataField] public bool ClickOpen = true; - [DataField("openDrawDepth", customTypeSerializer: typeof(ConstantSerializer))] - public int OpenDrawDepth = (int)DrawDepth.DrawDepth.Doors; + [DataField(customTypeSerializer: typeof(ConstantSerializer))] + public int OpenDrawDepth = (int) DrawDepth.DrawDepth.Doors; - [DataField("closedDrawDepth", customTypeSerializer: typeof(ConstantSerializer))] - public int ClosedDrawDepth = (int)DrawDepth.DrawDepth.Doors; + [DataField(customTypeSerializer: typeof(ConstantSerializer))] + public int ClosedDrawDepth = (int) DrawDepth.DrawDepth.Doors; } [Serializable, NetSerializable] @@ -335,20 +334,3 @@ public enum DoorVisualLayers : byte BaseBolted, BaseEmergencyAccess, } - -[Serializable, NetSerializable] -public sealed class DoorComponentState : ComponentState -{ - public readonly DoorState DoorState; - public readonly HashSet CurrentlyCrushing; - public readonly TimeSpan? NextStateChange; - public readonly bool Partial; - - public DoorComponentState(DoorComponent door, HashSet currentlyCrushing) - { - DoorState = door.State; - CurrentlyCrushing = currentlyCrushing; - NextStateChange = door.NextStateChange; - Partial = door.Partial; - } -} diff --git a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs index 1274e339859..9e1273b7843 100644 --- a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs +++ b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Doors.Components; using Content.Shared.Popups; -using Robust.Shared.GameStates; namespace Content.Shared.Doors.Systems; @@ -14,32 +13,15 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnBeforeDoorClosed); } - private void OnGetState(EntityUid uid, AirlockComponent airlock, ref ComponentGetState args) - { - // Need to network airlock safety state to avoid mis-predicts when a door auto-closes as the client walks through the door. - args.State = new AirlockComponentState(airlock.Safety); - } - - private void OnHandleState(EntityUid uid, AirlockComponent airlock, ref ComponentHandleState args) - { - if (args.Current is not AirlockComponentState state) - return; - - airlock.Safety = state.Safety; - } - protected virtual void OnBeforeDoorClosed(EntityUid uid, AirlockComponent airlock, BeforeDoorClosedEvent args) { if (!airlock.Safety) args.PerformCollisionCheck = false; } - public void UpdateEmergencyLightStatus(EntityUid uid, AirlockComponent component) { Appearance.SetData(uid, DoorVisuals.EmergencyLights, component.EmergencyAccess); diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index e5515171496..4a241ba3763 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -10,7 +10,6 @@ using Content.Shared.Stunnable; using Content.Shared.Tag; using Robust.Shared.Audio; -using Robust.Shared.GameStates; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; @@ -55,8 +54,7 @@ public override void Initialize() SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnRemove); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnActivate); @@ -102,29 +100,14 @@ private void OnRemove(EntityUid uid, DoorComponent door, ComponentRemove args) } #region StateManagement - private void OnGetState(EntityUid uid, DoorComponent door, ref ComponentGetState args) + private void OnHandleState(EntityUid uid, DoorComponent door, ref AfterAutoHandleStateEvent args) { - args.State = new DoorComponentState(door, GetNetEntitySet(door.CurrentlyCrushing)); - } - - private void OnHandleState(EntityUid uid, DoorComponent door, ref ComponentHandleState args) - { - if (args.Current is not DoorComponentState state) - return; - - door.CurrentlyCrushing.Clear(); - door.CurrentlyCrushing.UnionWith(EnsureEntitySet(state.CurrentlyCrushing, uid)); - - door.State = state.DoorState; - door.NextStateChange = state.NextStateChange; - door.Partial = state.Partial; - - if (state.NextStateChange == null) + if (door.NextStateChange == null) _activeDoors.Remove(door); else _activeDoors.Add(door); - RaiseLocalEvent(uid, new DoorStateChangedEvent(door.State), false); + RaiseLocalEvent(uid, new DoorStateChangedEvent(door.State)); AppearanceSystem.SetData(uid, DoorVisuals.State, door.State); } diff --git a/Content.Shared/Electrocution/InsulatedComponent.cs b/Content.Shared/Electrocution/InsulatedComponent.cs index cd4e5e32c5c..72c6ebcef0c 100644 --- a/Content.Shared/Electrocution/InsulatedComponent.cs +++ b/Content.Shared/Electrocution/InsulatedComponent.cs @@ -1,29 +1,17 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Electrocution { + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedElectrocutionSystem))] - [RegisterComponent, NetworkedComponent] public sealed partial class InsulatedComponent : Component { + // Technically, people could cheat and figure out which budget insulated gloves are gud and which ones are bad. + // We might want to rethink this a little bit. /// /// Siemens coefficient. Zero means completely insulated. /// - [DataField("coefficient")] - public float SiemensCoefficient { get; set; } = 0f; - } - - // Technically, people could cheat and figure out which budget insulated gloves are gud and which ones are bad. - // We might want to rethink this a little bit. - [NetSerializable, Serializable] - public sealed class InsulatedComponentState : ComponentState - { - public float SiemensCoefficient { get; private set; } - - public InsulatedComponentState(float siemensCoefficient) - { - SiemensCoefficient = siemensCoefficient; - } + [DataField, AutoNetworkedField] + public float Coefficient { get; set; } = 0f; } } diff --git a/Content.Shared/Electrocution/SharedElectrocutionSystem.cs b/Content.Shared/Electrocution/SharedElectrocutionSystem.cs index 67a395bb81c..5031d8a9115 100644 --- a/Content.Shared/Electrocution/SharedElectrocutionSystem.cs +++ b/Content.Shared/Electrocution/SharedElectrocutionSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Inventory; using Content.Shared.StatusEffect; -using Robust.Shared.GameStates; namespace Content.Shared.Electrocution { @@ -13,8 +12,6 @@ public override void Initialize() SubscribeLocalEvent(OnInsulatedElectrocutionAttempt); // as long as legally distinct electric-mice are never added, this should be fine (otherwise a mouse-hat will transfer it's power to the wearer). SubscribeLocalEvent>((e, c, ev) => OnInsulatedElectrocutionAttempt(e, c, ev.Args)); - SubscribeLocalEvent(OnInsulatedGetState); - SubscribeLocalEvent(OnInsulatedHandleState); } public void SetInsulatedSiemensCoefficient(EntityUid uid, float siemensCoefficient, InsulatedComponent? insulated = null) @@ -22,7 +19,7 @@ public void SetInsulatedSiemensCoefficient(EntityUid uid, float siemensCoefficie if (!Resolve(uid, ref insulated)) return; - insulated.SiemensCoefficient = siemensCoefficient; + insulated.Coefficient = siemensCoefficient; Dirty(insulated); } @@ -45,21 +42,7 @@ public virtual bool TryDoElectrocution( private void OnInsulatedElectrocutionAttempt(EntityUid uid, InsulatedComponent insulated, ElectrocutionAttemptEvent args) { - args.SiemensCoefficient *= insulated.SiemensCoefficient; + args.SiemensCoefficient *= insulated.Coefficient; } - - private void OnInsulatedGetState(EntityUid uid, InsulatedComponent insulated, ref ComponentGetState args) - { - args.State = new InsulatedComponentState(insulated.SiemensCoefficient); - } - - private void OnInsulatedHandleState(EntityUid uid, InsulatedComponent insulated, ref ComponentHandleState args) - { - if (args.Current is not InsulatedComponentState state) - return; - - insulated.SiemensCoefficient = state.SiemensCoefficient; - } - } } diff --git a/Content.Shared/Emoting/EmoteSystem.cs b/Content.Shared/Emoting/EmoteSystem.cs index 942c6b9de02..fd6361245b1 100644 --- a/Content.Shared/Emoting/EmoteSystem.cs +++ b/Content.Shared/Emoting/EmoteSystem.cs @@ -1,60 +1,30 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; +namespace Content.Shared.Emoting; -namespace Content.Shared.Emoting +public sealed class EmoteSystem : EntitySystem { - public sealed class EmoteSystem : EntitySystem + public override void Initialize() { - public override void Initialize() - { - base.Initialize(); + base.Initialize(); - SubscribeLocalEvent(OnEmoteAttempt); - SubscribeLocalEvent(OnEmotingGetState); - SubscribeLocalEvent(OnEmotingHandleState); - } - - public void SetEmoting(EntityUid uid, bool value, EmotingComponent? component = null) - { - if (value && !Resolve(uid, ref component)) - return; - - component = EnsureComp(uid); - - if (component.Enabled == value) - return; - - Dirty(component); - } - - private void OnEmotingHandleState(EntityUid uid, EmotingComponent component, ref ComponentHandleState args) - { - if (args.Current is not EmotingComponentState state) - return; + SubscribeLocalEvent(OnEmoteAttempt); + } - component.Enabled = state.Enabled; - } + public void SetEmoting(EntityUid uid, bool value, EmotingComponent? component = null) + { + if (value && !Resolve(uid, ref component)) + return; - private void OnEmotingGetState(EntityUid uid, EmotingComponent component, ref ComponentGetState args) - { - args.State = new EmotingComponentState(component.Enabled); - } + component = EnsureComp(uid); - private void OnEmoteAttempt(EmoteAttemptEvent args) - { - if (!TryComp(args.Uid, out EmotingComponent? emote) || !emote.Enabled) - args.Cancel(); - } + if (component.Enabled == value) + return; - [Serializable, NetSerializable] - private sealed class EmotingComponentState : ComponentState - { - public bool Enabled { get; } + Dirty(component); + } - public EmotingComponentState(bool enabled) - { - Enabled = enabled; - } - } + private void OnEmoteAttempt(EmoteAttemptEvent args) + { + if (!TryComp(args.Uid, out EmotingComponent? emote) || !emote.Enabled) + args.Cancel(); } } diff --git a/Content.Shared/Emoting/EmotingComponent.cs b/Content.Shared/Emoting/EmotingComponent.cs index a7a1542a91d..873f906f4b8 100644 --- a/Content.Shared/Emoting/EmotingComponent.cs +++ b/Content.Shared/Emoting/EmotingComponent.cs @@ -1,12 +1,11 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Emoting +namespace Content.Shared.Emoting; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class EmotingComponent : Component { - [RegisterComponent, NetworkedComponent] - public sealed partial class EmotingComponent : Component - { - [DataField("enabled"), Access(typeof(EmoteSystem), - Friend = AccessPermissions.ReadWrite, - Other = AccessPermissions.Read)] public bool Enabled = true; - } + [DataField, AutoNetworkedField] + [Access(typeof(EmoteSystem), Friend = AccessPermissions.ReadWrite, Other = AccessPermissions.Read)] + public bool Enabled = true; } diff --git a/Content.Shared/Follower/Components/FollowedComponent.cs b/Content.Shared/Follower/Components/FollowedComponent.cs index 83e486668eb..7c2ca0efbfe 100644 --- a/Content.Shared/Follower/Components/FollowedComponent.cs +++ b/Content.Shared/Follower/Components/FollowedComponent.cs @@ -6,10 +6,10 @@ namespace Content.Shared.Follower.Components; /// /// Attached to entities that are currently being followed by a ghost. /// -[RegisterComponent, Access(typeof(FollowerSystem))] -[NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(FollowerSystem))] public sealed partial class FollowedComponent : Component { - [DataField("following")] + [DataField, AutoNetworkedField] public HashSet Following = new(); } diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index 10e7a7be1d0..339136ffe81 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -8,14 +8,12 @@ using Content.Shared.Tag; using Content.Shared.Verbs; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Map.Events; using Robust.Shared.Network; -using Robust.Shared.Utility; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; -using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared.Follower; @@ -38,25 +36,6 @@ public override void Initialize() SubscribeLocalEvent(OnGotEquippedHand); SubscribeLocalEvent(OnFollowedTerminating); SubscribeLocalEvent(OnBeforeSave); - - SubscribeLocalEvent(OnFollowedGetState); - SubscribeLocalEvent(OnFollowedHandleState); - } - - private void OnFollowedGetState(EntityUid uid, FollowedComponent component, ref ComponentGetState args) - { - args.State = new FollowedComponentState() - { - Following = GetNetEntitySet(component.Following), - }; - } - - private void OnFollowedHandleState(EntityUid uid, FollowedComponent component, ref ComponentHandleState args) - { - if (args.Current is not FollowedComponentState state) - return; - - component.Following = EnsureEntitySet(state.Following, uid); } private void OnBeforeSave(BeforeSaveEvent ev) @@ -242,12 +221,6 @@ public void StopAllFollowers(EntityUid uid, StopFollowingEntity(player, uid, followed); } } - - [Serializable, NetSerializable] - private sealed class FollowedComponentState : ComponentState - { - public HashSet Following = new(); - } } public abstract class FollowEvent : EntityEventArgs diff --git a/Content.Shared/Gravity/FloatingVisualsComponent.cs b/Content.Shared/Gravity/FloatingVisualsComponent.cs index 7cf6331e9ef..67650baecda 100644 --- a/Content.Shared/Gravity/FloatingVisualsComponent.cs +++ b/Content.Shared/Gravity/FloatingVisualsComponent.cs @@ -1,10 +1,9 @@ using System.Numerics; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Gravity; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedFloatingVisualizerSystem))] public sealed partial class FloatingVisualsComponent : Component { @@ -12,33 +11,19 @@ public sealed partial class FloatingVisualsComponent : Component /// How long it takes to go from the bottom of the animation to the top. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("animationTime")] + [DataField, AutoNetworkedField] public float AnimationTime = 2f; /// /// How far it goes in any direction. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("offset")] + [DataField, AutoNetworkedField] public Vector2 Offset = new(0, 0.2f); [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public bool CanFloat = false; - public readonly string AnimationKey = "gravity"; -} - -[Serializable, NetSerializable] -public sealed class SharedFloatingVisualsComponentState : ComponentState -{ - public float AnimationTime; - public Vector2 Offset; - public bool HasGravity; - - public SharedFloatingVisualsComponentState(float animationTime, Vector2 offset, bool hasGravity) - { - AnimationTime = animationTime; - Offset = offset; - HasGravity = hasGravity; - } + public readonly string AnimationKey = "gravity"; } diff --git a/Content.Shared/Gravity/GravityShakeComponent.cs b/Content.Shared/Gravity/GravityShakeComponent.cs index 5fc1e902304..e8608a9681c 100644 --- a/Content.Shared/Gravity/GravityShakeComponent.cs +++ b/Content.Shared/Gravity/GravityShakeComponent.cs @@ -6,12 +6,12 @@ namespace Content.Shared.Gravity; /// /// Indicates this entity is shaking due to gravity changes. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class GravityShakeComponent : Component { - [ViewVariables(VVAccess.ReadWrite), DataField("shakeTimes")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public int ShakeTimes; - [DataField("nextShake", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] public TimeSpan NextShake; } diff --git a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs index 204f3978011..0f06d72192e 100644 --- a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs +++ b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs @@ -1,5 +1,4 @@ using System.Numerics; -using Robust.Shared.GameStates; using Robust.Shared.Map; namespace Content.Shared.Gravity; @@ -18,8 +17,6 @@ public override void Initialize() SubscribeLocalEvent(OnComponentStartup); SubscribeLocalEvent(OnGravityChanged); SubscribeLocalEvent(OnEntParentChanged); - SubscribeLocalEvent(OnComponentGetState); - SubscribeLocalEvent(OnComponentHandleState); } /// @@ -71,19 +68,4 @@ private void OnEntParentChanged(EntityUid uid, FloatingVisualsComponent componen if (CanFloat(uid, component, transform)) FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime); } - - private void OnComponentGetState(EntityUid uid, FloatingVisualsComponent component, ref ComponentGetState args) - { - args.State = new SharedFloatingVisualsComponentState(component.AnimationTime, component.Offset, component.CanFloat); - } - - private void OnComponentHandleState(EntityUid uid, FloatingVisualsComponent component, ref ComponentHandleState args) - { - if (args.Current is not SharedFloatingVisualsComponentState state) - return; - - component.AnimationTime = state.AnimationTime; - component.Offset = state.Offset; - component.CanFloat = state.HasGravity; - } } diff --git a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs index f265dedc150..e590baae44c 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs @@ -1,6 +1,3 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - namespace Content.Shared.Gravity; public abstract partial class SharedGravitySystem @@ -11,8 +8,6 @@ public abstract partial class SharedGravitySystem private void InitializeShake() { SubscribeLocalEvent(OnShakeUnpaused); - SubscribeLocalEvent(OnShakeGetState); - SubscribeLocalEvent(OnShakeHandleState); } private void OnShakeUnpaused(EntityUid uid, GravityShakeComponent component, ref EntityUnpausedEvent args) @@ -63,29 +58,4 @@ public void StartGridShake(EntityUid uid, GravityComponent? gravity = null) } protected virtual void ShakeGrid(EntityUid uid, GravityComponent? comp = null) {} - - private void OnShakeHandleState(EntityUid uid, GravityShakeComponent component, ref ComponentHandleState args) - { - if (args.Current is not GravityShakeComponentState state) - return; - - component.ShakeTimes = state.ShakeTimes; - component.NextShake = state.NextShake; - } - - private void OnShakeGetState(EntityUid uid, GravityShakeComponent component, ref ComponentGetState args) - { - args.State = new GravityShakeComponentState() - { - ShakeTimes = component.ShakeTimes, - NextShake = component.NextShake, - }; - } - - [Serializable, NetSerializable] - protected sealed class GravityShakeComponentState : ComponentState - { - public int ShakeTimes; - public TimeSpan NextShake; - } } diff --git a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs index 82d5750aa5c..296545f0b4f 100644 --- a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs +++ b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs @@ -4,31 +4,31 @@ using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Utility; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Shared.Humanoid; -[NetworkedComponent, RegisterComponent] +[NetworkedComponent, RegisterComponent, AutoGenerateComponentState(true)] public sealed partial class HumanoidAppearanceComponent : Component { - [DataField("markingSet")] + public MarkingSet ClientOldMarkings = new(); + + [DataField] public MarkingSet MarkingSet = new(); - [DataField("baseLayers")] + [DataField] public Dictionary BaseLayers = new(); - [DataField("permanentlyHidden")] + [DataField, AutoNetworkedField(true)] public HashSet PermanentlyHidden = new(); // Couldn't these be somewhere else? - [DataField("gender")] - [ViewVariables] public Gender Gender = default!; + [DataField, AutoNetworkedField] + public Gender Gender; - [DataField("age")] - [ViewVariables] public int Age = 18; + [DataField, AutoNetworkedField] + public int Age = 18; /// /// Any custom base layers this humanoid might have. See: @@ -36,39 +36,39 @@ public sealed partial class HumanoidAppearanceComponent : Component /// Stored on the server, this is merged in the client into /// all layer settings. /// - [DataField("customBaseLayers")] + [DataField, AutoNetworkedField(true)] public Dictionary CustomBaseLayers = new(); /// /// Current species. Dictates things like base body sprites, /// base humanoid to spawn, etc. /// - [DataField("species", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] - public string Species { get; set; } = default!; + [DataField(required: true), AutoNetworkedField] + public ProtoId Species { get; set; } /// /// The initial profile and base layers to apply to this humanoid. /// - [DataField("initial", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? Initial { get; private set; } + [DataField] + public ProtoId? Initial { get; private set; } /// /// Skin color of this humanoid. /// - [DataField("skinColor")] + [DataField, AutoNetworkedField] public Color SkinColor { get; set; } = Color.FromHex("#C0967F"); /// /// Visual layers currently hidden. This will affect the base sprite /// on this humanoid layer, and any markings that sit above it. /// - [DataField("hiddenLayers")] + [DataField, AutoNetworkedField(true)] public HashSet HiddenLayers = new(); - [DataField("sex")] + [DataField, AutoNetworkedField] public Sex Sex = Sex.Male; - [DataField("eyeColor")] + [DataField, AutoNetworkedField] public Color EyeColor = Color.Brown; /// @@ -84,65 +84,26 @@ public sealed partial class HumanoidAppearanceComponent : Component public Color? CachedFacialHairColor; } +[DataDefinition] [Serializable, NetSerializable] -public sealed partial class HumanoidAppearanceState : ComponentState +public readonly partial struct CustomBaseLayerInfo { - public readonly MarkingSet Markings; - public readonly HashSet PermanentlyHidden; - public readonly HashSet HiddenLayers; - public readonly Dictionary CustomBaseLayers; - public readonly Sex Sex; - public readonly Gender Gender; - public readonly int Age = 18; - public readonly string Species; - public readonly Color SkinColor; - public readonly Color EyeColor; - - public HumanoidAppearanceState( - MarkingSet currentMarkings, - HashSet permanentlyHidden, - HashSet hiddenLayers, - Dictionary customBaseLayers, - Sex sex, - Gender gender, - int age, - string species, - Color skinColor, - Color eyeColor) + public CustomBaseLayerInfo(string? id, Color? color = null) { - Markings = currentMarkings; - PermanentlyHidden = permanentlyHidden; - HiddenLayers = hiddenLayers; - CustomBaseLayers = customBaseLayers; - Sex = sex; - Gender = gender; - Age = age; - Species = species; - SkinColor = skinColor; - EyeColor = eyeColor; + DebugTools.Assert(id == null || IoCManager.Resolve().HasIndex(id)); + Id = id; + Color = color; } - [DataDefinition] - [Serializable, NetSerializable] - public readonly partial struct CustomBaseLayerInfo - { - public CustomBaseLayerInfo(string? id, Color? color = null) - { - DebugTools.Assert(id == null || IoCManager.Resolve().HasIndex(id)); - ID = id; - Color = color; - } - - /// - /// ID of this custom base layer. Must be a . - /// - [DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? ID { init; get; } - - /// - /// Color of this custom base layer. Null implies skin colour if the corresponding is set to match skin. - /// - [DataField("color")] - public Color? Color { init; get; } - } + /// + /// ID of this custom base layer. Must be a . + /// + [DataField] + public ProtoId? Id { get; init; } + + /// + /// Color of this custom base layer. Null implies skin colour if the corresponding is set to match skin. + /// + [DataField] + public Color? Color { get; init; } } diff --git a/Content.Shared/Humanoid/Prototypes/HumanoidProfilePrototype.cs b/Content.Shared/Humanoid/Prototypes/HumanoidProfilePrototype.cs index 5752e57c93b..7755e3113c0 100644 --- a/Content.Shared/Humanoid/Prototypes/HumanoidProfilePrototype.cs +++ b/Content.Shared/Humanoid/Prototypes/HumanoidProfilePrototype.cs @@ -1,6 +1,5 @@ using Content.Shared.Preferences; using Robust.Shared.Prototypes; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Shared.Humanoid.Prototypes; diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index e7e7b5a6728..a61470bfdfb 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -1,11 +1,10 @@ +using System.Linq; using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Prototypes; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; -using System.Linq; using Content.Shared.Preferences; using Robust.Shared.GameObjects.Components.Localization; using Robust.Shared.Network; +using Robust.Shared.Prototypes; namespace Content.Shared.Humanoid; @@ -31,7 +30,6 @@ public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnGetState); } private void OnInit(EntityUid uid, HumanoidAppearanceComponent humanoid, ComponentInit args) @@ -57,20 +55,6 @@ private void OnInit(EntityUid uid, HumanoidAppearanceComponent humanoid, Compone LoadProfile(uid, startingSet.Profile, humanoid); } - private void OnGetState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentGetState args) - { - args.State = new HumanoidAppearanceState(component.MarkingSet, - component.PermanentlyHidden, - component.HiddenLayers, - component.CustomBaseLayers, - component.Sex, - component.Gender, - component.Age, - component.Species, - component.SkinColor, - component.EyeColor); - } - /// /// Toggles a humanoid's sprite layer visibility. /// @@ -211,7 +195,7 @@ public void SetBaseLayerId(EntityUid uid, HumanoidVisualLayers layer, string? id return; if (humanoid.CustomBaseLayers.TryGetValue(layer, out var info)) - humanoid.CustomBaseLayers[layer] = info with { ID = id }; + humanoid.CustomBaseLayers[layer] = info with { Id = id }; else humanoid.CustomBaseLayers[layer] = new(id); diff --git a/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs b/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs index bd0bad96703..68b3533bd4d 100644 --- a/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidMarkingModifierSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Humanoid.Markings; using Robust.Shared.Serialization; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Shared.Humanoid; diff --git a/Content.Shared/Implants/Components/ImplanterComponent.cs b/Content.Shared/Implants/Components/ImplanterComponent.cs index e681cab0473..85891826f90 100644 --- a/Content.Shared/Implants/Components/ImplanterComponent.cs +++ b/Content.Shared/Implants/Components/ImplanterComponent.cs @@ -1,10 +1,7 @@ -using System.Threading; -using Content.Shared.Containers.ItemSlots; -using Content.Shared.DoAfter; +using Content.Shared.Containers.ItemSlots; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Implants.Components; /// @@ -12,7 +9,7 @@ namespace Content.Shared.Implants.Components; /// Some can be single use (implant only) or some can draw out an implant /// //TODO: Rework drawing to work with implant cases when surgery is in -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class ImplanterComponent : Component { public const string ImplanterSlotId = "implanter_slot"; @@ -21,15 +18,14 @@ public sealed partial class ImplanterComponent : Component /// /// Used for implanters that start with specific implants /// - [ViewVariables] - [DataField("implant", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? Implant; + [DataField] + public EntProtoId? Implant; /// /// The time it takes to implant someone else /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("implantTime")] + [DataField] public float ImplantTime = 5f; //TODO: Remove when surgery is a thing @@ -38,54 +34,37 @@ public sealed partial class ImplanterComponent : Component /// It's excessively long to deter from implant checking any antag /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("drawTime")] + [DataField] public float DrawTime = 60f; /// /// Good for single-use injectors /// - [ViewVariables] - [DataField("implantOnly")] - public bool ImplantOnly = false; + [DataField, AutoNetworkedField] + public bool ImplantOnly; /// /// The current mode of the implanter /// Mode is changed automatically depending if it implants or draws /// - [ViewVariables] - [DataField("currentMode")] + [DataField, AutoNetworkedField] public ImplanterToggleMode CurrentMode; /// /// The name and description of the implant to show on the implanter /// - [ViewVariables] - [DataField("implantData")] + [DataField] public (string, string) ImplantData; /// /// The for this implanter /// - [ViewVariables] - [DataField("implanterSlot", required:true)] + [DataField(required: true)] public ItemSlot ImplanterSlot = new(); public bool UiUpdateNeeded; } -[Serializable, NetSerializable] -public sealed class ImplanterComponentState : ComponentState -{ - public ImplanterToggleMode CurrentMode; - public bool ImplantOnly; - - public ImplanterComponentState(ImplanterToggleMode currentMode, bool implantOnly) - { - CurrentMode = currentMode; - ImplantOnly = implantOnly; - } -} - [Serializable, NetSerializable] public enum ImplanterToggleMode : byte { diff --git a/Content.Shared/Interaction/Components/InteractionRelayComponent.cs b/Content.Shared/Interaction/Components/InteractionRelayComponent.cs index 1f8b4468ad1..2ac9c1e4ef1 100644 --- a/Content.Shared/Interaction/Components/InteractionRelayComponent.cs +++ b/Content.Shared/Interaction/Components/InteractionRelayComponent.cs @@ -1,5 +1,4 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Interaction.Components; @@ -10,27 +9,13 @@ namespace Content.Shared.Interaction.Components; /// /// Note that extreme caution should be taken when using this, as this will probably bypass many normal can-interact checks. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedInteractionSystem))] public sealed partial class InteractionRelayComponent : Component { /// /// The entity the interactions are being relayed to. /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public EntityUid? RelayEntity; } - -/// -/// Contains network state for -/// -[Serializable, NetSerializable] -public sealed class InteractionRelayComponentState : ComponentState -{ - public NetEntity? RelayEntity; - - public InteractionRelayComponentState(NetEntity? relayEntity) - { - RelayEntity = relayEntity; - } -} diff --git a/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs b/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs index f82b8f78760..77e283b93d1 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs @@ -1,35 +1,15 @@ using Content.Shared.Interaction.Components; -using Robust.Shared.GameStates; namespace Content.Shared.Interaction; public abstract partial class SharedInteractionSystem { - public void InitializeRelay() - { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnGetState(EntityUid uid, InteractionRelayComponent component, ref ComponentGetState args) - { - args.State = new InteractionRelayComponentState(GetNetEntity(component.RelayEntity)); - } - - private void OnHandleState(EntityUid uid, InteractionRelayComponent component, ref ComponentHandleState args) - { - if (args.Current is not InteractionRelayComponentState state) - return; - - component.RelayEntity = EnsureEntity(state.RelayEntity, uid); - } - public void SetRelay(EntityUid uid, EntityUid? relayEntity, InteractionRelayComponent? component = null) { if (!Resolve(uid, ref component)) return; component.RelayEntity = relayEntity; - Dirty(component); + Dirty(uid, component); } } diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 00c357814d7..d79a892c711 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -1,4 +1,3 @@ -using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.ActionBlocker; @@ -7,7 +6,6 @@ using Content.Shared.Administration.Managers; using Content.Shared.CombatMode; using Content.Shared.Database; -using Content.Shared.Ghost; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Input; @@ -28,7 +26,6 @@ using Content.Shared.Wall; using JetBrains.Annotations; using Robust.Shared.Containers; -using Robust.Shared.GameObjects; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Map; @@ -99,7 +96,6 @@ public override void Initialize() new PointerInputCmdHandler(HandleTryPullObject)) .Register(); - InitializeRelay(); InitializeBlocking(); } diff --git a/Content.Shared/Jittering/JitteringComponent.cs b/Content.Shared/Jittering/JitteringComponent.cs index cd8e3aeea79..237629f291b 100644 --- a/Content.Shared/Jittering/JitteringComponent.cs +++ b/Content.Shared/Jittering/JitteringComponent.cs @@ -1,33 +1,20 @@ using System.Numerics; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; -namespace Content.Shared.Jittering -{ - [Access(typeof(SharedJitteringSystem))] - [RegisterComponent, NetworkedComponent] - public sealed partial class JitteringComponent : Component - { - [ViewVariables(VVAccess.ReadWrite)] - public float Amplitude { get; set; } - - [ViewVariables(VVAccess.ReadWrite)] - public float Frequency { get; set; } +namespace Content.Shared.Jittering; - [ViewVariables(VVAccess.ReadWrite)] - public Vector2 LastJitter { get; set; } - } +[Access(typeof(SharedJitteringSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class JitteringComponent : Component +{ + [AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] + public float Amplitude { get; set; } - [Serializable, NetSerializable] - public sealed class JitteringComponentState : ComponentState - { - public float Amplitude { get; } - public float Frequency { get; } + [AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] + public float Frequency { get; set; } - public JitteringComponentState(float amplitude, float frequency) - { - Amplitude = amplitude; - Frequency = frequency; - } - } + [ViewVariables(VVAccess.ReadWrite)] + public Vector2 LastJitter { get; set; } } diff --git a/Content.Shared/Jittering/SharedJitteringSystem.cs b/Content.Shared/Jittering/SharedJitteringSystem.cs index e0cb2463f98..327a4521752 100644 --- a/Content.Shared/Jittering/SharedJitteringSystem.cs +++ b/Content.Shared/Jittering/SharedJitteringSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Rejuvenate; using Content.Shared.StatusEffect; -using Robust.Shared.GameStates; using Robust.Shared.Timing; namespace Content.Shared.Jittering @@ -21,25 +20,9 @@ public abstract class SharedJitteringSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnRejuvenate); } - private void OnGetState(EntityUid uid, JitteringComponent component, ref ComponentGetState args) - { - args.State = new JitteringComponentState(component.Amplitude, component.Frequency); - } - - private void OnHandleState(EntityUid uid, JitteringComponent component, ref ComponentHandleState args) - { - if (args.Current is not JitteringComponentState jitteringState) - return; - - component.Amplitude = jitteringState.Amplitude; - component.Frequency = jitteringState.Frequency; - } - private void OnRejuvenate(EntityUid uid, JitteringComponent component, RejuvenateEvent args) { EntityManager.RemoveComponentDeferred(uid); diff --git a/Content.Shared/Lathe/LatheComponent.cs b/Content.Shared/Lathe/LatheComponent.cs index 411695b46d5..410db3c86f9 100644 --- a/Content.Shared/Lathe/LatheComponent.cs +++ b/Content.Shared/Lathe/LatheComponent.cs @@ -2,42 +2,42 @@ using Content.Shared.Research.Prototypes; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Prototypes; namespace Content.Shared.Lathe { - [RegisterComponent, NetworkedComponent] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class LatheComponent : Component { /// /// All of the recipes that the lathe has by default /// - [DataField("staticRecipes", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List StaticRecipes = new(); + [DataField] + public List> StaticRecipes = new(); /// /// All of the recipes that the lathe is capable of researching /// - [DataField("dynamicRecipes", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List DynamicRecipes = new(); + [DataField] + public List> DynamicRecipes = new(); /// /// The lathe's construction queue /// - [DataField("queue")] + [DataField] public List Queue = new(); /// /// The sound that plays when the lathe is producing an item, if any /// - [DataField("producingSound")] + [DataField] public SoundSpecifier? ProducingSound; + #region Visualizer info - [DataField("idleState", required: true)] + [DataField(required: true)] public string IdleState = default!; - [DataField("runningState", required: true)] + [DataField(required: true)] public string RunningState = default!; #endregion @@ -50,7 +50,7 @@ public sealed partial class LatheComponent : Component /// /// Whether the lathe can eject the materials stored within it /// - [DataField("canEjectStoredMaterials")] + [DataField] public bool CanEjectStoredMaterials = true; #region MachineUpgrading @@ -63,31 +63,31 @@ public sealed partial class LatheComponent : Component /// /// The machine part that reduces how long it takes to print a recipe. /// - [DataField("machinePartPrintSpeed", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MachinePartPrintTime = "Manipulator"; + [DataField] + public ProtoId MachinePartPrintSpeed = "Manipulator"; /// /// The value that is used to calculate the modified /// - [DataField("partRatingPrintTimeMultiplier")] + [DataField] public float PartRatingPrintTimeMultiplier = 0.5f; /// /// A modifier that changes how much of a material is needed to print a recipe /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float MaterialUseMultiplier = 1; /// /// The machine part that reduces how much material it takes to print a recipe. /// - [DataField("machinePartMaterialUse", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MachinePartMaterialUse = "MatterBin"; + [DataField] + public ProtoId MachinePartMaterialUse = "MatterBin"; /// /// The value that is used to calculate the modifier /// - [DataField("partRatingMaterialUseMultiplier")] + [DataField] public float PartRatingMaterialUseMultiplier = DefaultPartRatingMaterialUseMultiplier; public const float DefaultPartRatingMaterialUseMultiplier = 0.85f; @@ -98,7 +98,7 @@ public sealed class LatheGetRecipesEvent : EntityEventArgs { public readonly EntityUid Lathe; - public List Recipes = new(); + public List> Recipes = new(); public LatheGetRecipesEvent(EntityUid lathe) { diff --git a/Content.Shared/Lathe/LatheMessages.cs b/Content.Shared/Lathe/LatheMessages.cs index 7b28c3f5b09..820c496d30c 100644 --- a/Content.Shared/Lathe/LatheMessages.cs +++ b/Content.Shared/Lathe/LatheMessages.cs @@ -1,4 +1,5 @@ using Content.Shared.Research.Prototypes; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Lathe; @@ -6,13 +7,13 @@ namespace Content.Shared.Lathe; [Serializable, NetSerializable] public sealed class LatheUpdateState : BoundUserInterfaceState { - public List Recipes; + public List> Recipes; public List Queue; public LatheRecipePrototype? CurrentlyProducing; - public LatheUpdateState(List recipes, List queue, LatheRecipePrototype? currentlyProducing = null) + public LatheUpdateState(List> recipes, List queue, LatheRecipePrototype? currentlyProducing = null) { Recipes = recipes; Queue = queue; diff --git a/Content.Shared/Lathe/SharedLatheSystem.cs b/Content.Shared/Lathe/SharedLatheSystem.cs index e31925ec6d8..e9482d24d15 100644 --- a/Content.Shared/Lathe/SharedLatheSystem.cs +++ b/Content.Shared/Lathe/SharedLatheSystem.cs @@ -2,10 +2,7 @@ using Content.Shared.Materials; using Content.Shared.Research.Prototypes; using JetBrains.Annotations; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using System.Net.Mail; namespace Content.Shared.Lathe; @@ -21,23 +18,9 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnEmagged); } - private void OnGetState(EntityUid uid, LatheComponent component, ref ComponentGetState args) - { - args.State = new LatheComponentState(component.MaterialUseMultiplier); - } - - private void OnHandleState(EntityUid uid, LatheComponent component, ref ComponentHandleState args) - { - if (args.Current is not LatheComponentState state) - return; - component.MaterialUseMultiplier = state.MaterialUseMultiplier; - } - [PublicAPI] public bool CanProduce(EntityUid uid, string recipe, int amount = 1, LatheComponent? component = null) { @@ -71,14 +54,3 @@ public static int AdjustMaterial(int original, bool reduce, float multiplier) protected abstract bool HasRecipe(EntityUid uid, LatheRecipePrototype recipe, LatheComponent component); } - -[Serializable, NetSerializable] -public sealed class LatheComponentState : ComponentState -{ - public float MaterialUseMultiplier; - - public LatheComponentState(float materialUseMultiplier) - { - MaterialUseMultiplier = materialUseMultiplier; - } -} diff --git a/Content.Shared/Materials/InsertingMaterialStorageComponent.cs b/Content.Shared/Materials/InsertingMaterialStorageComponent.cs index e841853c8e1..007dc73345d 100644 --- a/Content.Shared/Materials/InsertingMaterialStorageComponent.cs +++ b/Content.Shared/Materials/InsertingMaterialStorageComponent.cs @@ -1,31 +1,18 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Materials; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class InsertingMaterialStorageComponent : Component { /// /// The time when insertion ends. /// - [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] public TimeSpan EndTime; - [ViewVariables] + [ViewVariables, AutoNetworkedField] public Color? MaterialColor; } - -[Serializable, NetSerializable] -public sealed class InsertingMaterialStorageComponentState : ComponentState -{ - public TimeSpan EndTime; - public Color? MaterialColor; - - public InsertingMaterialStorageComponentState(TimeSpan endTime, Color? materialColor) - { - EndTime = endTime; - MaterialColor = materialColor; - } -} diff --git a/Content.Shared/Materials/MaterialReclaimerComponent.cs b/Content.Shared/Materials/MaterialReclaimerComponent.cs index 61081763528..761469f99aa 100644 --- a/Content.Shared/Materials/MaterialReclaimerComponent.cs +++ b/Content.Shared/Materials/MaterialReclaimerComponent.cs @@ -3,9 +3,9 @@ using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Materials; @@ -13,27 +13,28 @@ namespace Content.Shared.Materials; /// This is a machine that handles converting entities /// into the raw materials and chemicals that make them up. /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedMaterialReclaimerSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedMaterialReclaimerSystem))] public sealed partial class MaterialReclaimerComponent : Component { /// /// Whether or not the machine has power. We put it here /// so we can network and predict it. /// - [DataField("powered"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] public bool Powered; /// /// An "enable" toggle for things like interfacing with machine linking /// - [DataField("enabled"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] public bool Enabled = true; /// /// How efficiently the materials are reclaimed. /// In practice, a multiplier per material when calculating the output of the reclaimer. /// - [DataField("efficiency"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float Efficiency = 1f; /// @@ -41,46 +42,46 @@ public sealed partial class MaterialReclaimerComponent : Component /// speed scales with the amount of materials being processed /// or if it's just /// - [DataField("scaleProcessSpeed")] + [DataField] public bool ScaleProcessSpeed = true; /// /// How quickly it takes to consume X amount of materials per second. /// For example, with a rate of 50, an entity with 100 total material takes 2 seconds to process. /// - [DataField("baseMaterialProcessRate"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float BaseMaterialProcessRate = 100f; /// /// How quickly it takes to consume X amount of materials per second. /// For example, with a rate of 50, an entity with 100 total material takes 2 seconds to process. /// - [DataField("materialProcessRate"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] public float MaterialProcessRate = 100f; /// /// Machine part whose rating modifies /// - [DataField("machinePartProcessRate", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] - public string MachinePartProcessRate = "Manipulator"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public ProtoId MachinePartProcessRate = "Manipulator"; /// /// How much the machine part quality affects the /// - [DataField("partRatingProcessRateMultiplier"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float PartRatingProcessRateMultiplier = 1.5f; /// /// The minimum amount fo time it can take to process an entity. /// this value supercedes the calculated one using /// - [DataField("minimumProcessDuration"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan MinimumProcessDuration = TimeSpan.FromSeconds(0.5f); /// /// The id of our output solution /// - [DataField("solutionContainerId"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string SolutionContainerId = "output"; /// @@ -92,37 +93,37 @@ public sealed partial class MaterialReclaimerComponent : Component /// /// a whitelist for what entities can be inserted into this reclaimer /// - [DataField("whitelist")] + [DataField] public EntityWhitelist? Whitelist; /// /// a blacklist for what entities cannot be inserted into this reclaimer /// - [DataField("blacklist")] + [DataField] public EntityWhitelist? Blacklist; /// /// The sound played when something is being processed. /// - [DataField("sound")] + [DataField] public SoundSpecifier? Sound; /// /// whether or not we cut off the sound early when the reclaiming ends. /// - [DataField("cutOffSound")] + [DataField] public bool CutOffSound = true; /// /// When the next sound will be allowed to be played. Used to prevent spam. /// - [DataField("nextSound", customTypeSerializer: typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan NextSound; /// /// Minimum time inbetween each /// - [DataField("soundCooldown")] + [DataField] public TimeSpan SoundCooldown = TimeSpan.FromSeconds(0.8f); public IPlayingAudioStream? Stream; @@ -133,30 +134,10 @@ public sealed partial class MaterialReclaimerComponent : Component /// /// I saw this on the recycler and i'm porting it because it's cute af /// - [DataField("itemsProcessed")] + [DataField, AutoNetworkedField] public int ItemsProcessed; } -[Serializable, NetSerializable] -public sealed class MaterialReclaimerComponentState : ComponentState -{ - public bool Powered; - - public bool Enabled; - - public float MaterialProcessRate; - - public int ItemsProcessed; - - public MaterialReclaimerComponentState(bool powered, bool enabled, float materialProcessRate, int itemsProcessed) - { - Powered = powered; - Enabled = enabled; - MaterialProcessRate = materialProcessRate; - ItemsProcessed = itemsProcessed; - } -} - [NetSerializable, Serializable] public enum RecyclerVisuals { diff --git a/Content.Shared/Materials/MaterialStorageComponent.cs b/Content.Shared/Materials/MaterialStorageComponent.cs index 50935bcd474..c905478bca3 100644 --- a/Content.Shared/Materials/MaterialStorageComponent.cs +++ b/Content.Shared/Materials/MaterialStorageComponent.cs @@ -1,67 +1,65 @@ using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Materials; +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedMaterialStorageSystem))] -[RegisterComponent, NetworkedComponent] public sealed partial class MaterialStorageComponent : Component { - [DataField("storage", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] - public Dictionary Storage { get; set; } = new(); + [DataField, AutoNetworkedField] + public Dictionary, int> Storage { get; set; } = new(); /// /// Whether or not interacting with the materialstorage inserts the material in hand. /// - [DataField("insertOnInteract")] + [DataField] public bool InsertOnInteract = true; /// /// How much material the storage can store in total. /// - [ViewVariables(VVAccess.ReadWrite), DataField("storageLimit")] + [ViewVariables(VVAccess.ReadWrite), DataField] public int? StorageLimit; /// /// Whitelist for specifying the kind of items that can be insert into this entity. /// - [DataField("whitelist")] - public EntityWhitelist? EntityWhitelist; + [DataField] + public EntityWhitelist? Whitelist; /// /// Whether or not to drop contained materials when deconstructed. /// - [DataField("dropOnDeconstruct")] + [DataField] public bool DropOnDeconstruct = true; /// /// Whitelist generated on runtime for what specific materials can be inserted into this entity. /// - [DataField("materialWhiteList", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List? MaterialWhiteList; + [DataField, AutoNetworkedField] + public List>? MaterialWhiteList; /// /// Whether or not the visualization for the insertion animation /// should ignore the color of the material being inserted. /// - [DataField("ignoreColor")] + [DataField] public bool IgnoreColor; /// /// The sound that plays when inserting an item into the storage /// - [DataField("insertingSound")] + [DataField] public SoundSpecifier? InsertingSound; /// /// How long the inserting animation will play /// - [DataField("insertionTime")] + [DataField] public TimeSpan InsertionTime = TimeSpan.FromSeconds(0.79f); // 0.01 off for animation timing } @@ -94,19 +92,5 @@ public record struct GetMaterialWhitelistEvent(EntityUid Storage) { public readonly EntityUid Storage = Storage; - public List Whitelist = new(); -} - -[Serializable, NetSerializable] -public sealed class MaterialStorageComponentState : ComponentState -{ - public Dictionary Storage; - - public List? MaterialWhitelist; - - public MaterialStorageComponentState(Dictionary storage, List? materialWhitelist) - { - Storage = storage; - MaterialWhitelist = materialWhitelist; - } + public List> Whitelist = new(); } diff --git a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs index 54ddc912896..3f5832f69a9 100644 --- a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs +++ b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs @@ -9,7 +9,6 @@ using Content.Shared.Mobs.Components; using Content.Shared.Stacks; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Physics.Events; using Robust.Shared.Timing; @@ -32,8 +31,6 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnExamined); @@ -43,24 +40,6 @@ public override void Initialize() SubscribeLocalEvent(OnActiveUnpaused); } - private void OnGetState(EntityUid uid, MaterialReclaimerComponent component, ref ComponentGetState args) - { - args.State = new MaterialReclaimerComponentState(component.Powered, - component.Enabled, - component.MaterialProcessRate, - component.ItemsProcessed); - } - - private void OnHandleState(EntityUid uid, MaterialReclaimerComponent component, ref ComponentHandleState args) - { - if (args.Current is not MaterialReclaimerComponentState state) - return; - component.Powered = state.Powered; - component.Enabled = state.Enabled; - component.MaterialProcessRate = state.MaterialProcessRate; - component.ItemsProcessed = state.ItemsProcessed; - } - private void OnShutdown(EntityUid uid, MaterialReclaimerComponent component, ComponentShutdown args) { component.Stream?.Stop(); diff --git a/Content.Shared/Materials/SharedMaterialStorageSystem.cs b/Content.Shared/Materials/SharedMaterialStorageSystem.cs index e54ff3faa3e..9e6e000d622 100644 --- a/Content.Shared/Materials/SharedMaterialStorageSystem.cs +++ b/Content.Shared/Materials/SharedMaterialStorageSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Interaction.Components; using Content.Shared.Stacks; using JetBrains.Annotations; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -26,10 +25,6 @@ public override void Initialize() SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - SubscribeLocalEvent(OnGetInsertingState); - SubscribeLocalEvent(OnHandleInsertingState); SubscribeLocalEvent(OnUnpaused); } @@ -52,36 +47,6 @@ private void OnMapInit(EntityUid uid, MaterialStorageComponent component, MapIni _appearance.SetData(uid, MaterialStorageVisuals.Inserting, false); } - private void OnGetState(EntityUid uid, MaterialStorageComponent component, ref ComponentGetState args) - { - args.State = new MaterialStorageComponentState(component.Storage, component.MaterialWhiteList); - } - - private void OnHandleState(EntityUid uid, MaterialStorageComponent component, ref ComponentHandleState args) - { - if (args.Current is not MaterialStorageComponentState state) - return; - - component.Storage = new Dictionary(state.Storage); - - if (state.MaterialWhitelist != null) - component.MaterialWhiteList = new List(state.MaterialWhitelist); - } - - private void OnGetInsertingState(EntityUid uid, InsertingMaterialStorageComponent component, ref ComponentGetState args) - { - args.State = new InsertingMaterialStorageComponentState(component.EndTime, component.MaterialColor); - } - - private void OnHandleInsertingState(EntityUid uid, InsertingMaterialStorageComponent component, ref ComponentHandleState args) - { - if (args.Current is not InsertingMaterialStorageComponentState state) - return; - - component.EndTime = state.EndTime; - component.MaterialColor = state.MaterialColor; - } - private void OnUnpaused(EntityUid uid, InsertingMaterialStorageComponent component, ref EntityUnpausedEvent args) { component.EndTime += args.PausedTime; @@ -222,7 +187,7 @@ public virtual bool TryInsertMaterialEntity(EntityUid user, if (!Resolve(toInsert, ref material, ref composition, false)) return false; - if (storage.EntityWhitelist?.IsValid(toInsert) == false) + if (storage.Whitelist?.IsValid(toInsert) == false) return false; if (HasComp(toInsert)) diff --git a/Content.Shared/Mech/Components/MechComponent.cs b/Content.Shared/Mech/Components/MechComponent.cs index ec8fc62dfba..9bf25f41644 100644 --- a/Content.Shared/Mech/Components/MechComponent.cs +++ b/Content.Shared/Mech/Components/MechComponent.cs @@ -3,9 +3,6 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Mech.Components; @@ -13,33 +10,33 @@ namespace Content.Shared.Mech.Components; /// A large, pilotable machine that has equipment that is /// powered via an internal battery. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MechComponent : Component { /// /// How much "health" the mech has left. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public FixedPoint2 Integrity; /// /// The maximum amount of damage the mech can take. /// - [DataField("maxIntegrity")] + [DataField, AutoNetworkedField] public FixedPoint2 MaxIntegrity = 250; /// /// How much energy the mech has. /// Derived from the currently inserted battery. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public FixedPoint2 Energy = 0; /// /// The maximum amount of energy the mech can have. /// Derived from the currently inserted battery. /// - [DataField("maxEnergy")] + [DataField, AutoNetworkedField] public FixedPoint2 MaxEnergy = 0; /// @@ -55,13 +52,13 @@ public sealed partial class MechComponent : Component /// A multiplier used to calculate how much of the damage done to a mech /// is transfered to the pilot /// - [DataField("mechToPilotDamageMultiplier")] + [DataField] public float MechToPilotDamageMultiplier; /// /// Whether the mech has been destroyed and is no longer pilotable. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool Broken = false; /// @@ -77,7 +74,7 @@ public sealed partial class MechComponent : Component /// The current selected equipment of the mech. /// If null, the mech is using just its fists. /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public EntityUid? CurrentSelectedEquipment; /// @@ -89,10 +86,10 @@ public sealed partial class MechComponent : Component /// /// A whitelist for inserting equipment items. /// - [DataField("equipmentWhitelist")] + [DataField] public EntityWhitelist? EquipmentWhitelist; - [DataField("pilotWhitelist")] + [DataField] public EntityWhitelist? PilotWhitelist; /// @@ -107,20 +104,20 @@ public sealed partial class MechComponent : Component /// /// How long it takes to enter the mech. /// - [DataField("entryDelay")] + [DataField] public float EntryDelay = 3; /// /// How long it takes to pull *another person* /// outside of the mech. You can exit instantly yourself. /// - [DataField("exitDelay")] + [DataField] public float ExitDelay = 3; /// /// How long it takes to pull out the battery. /// - [DataField("batteryRemovalDelay")] + [DataField] public float BatteryRemovalDelay = 2; /// @@ -130,31 +127,31 @@ public sealed partial class MechComponent : Component /// This needs to be redone /// when mech internals are added /// - [DataField("airtight"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool Airtight; /// /// The equipment that the mech initially has when it spawns. /// Good for things like nukie mechs that start with guns. /// - [DataField("startingEquipment", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List StartingEquipment = new(); + [DataField] + public List StartingEquipment = new(); #region Action Prototypes - [DataField("mechCycleAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MechCycleAction = "ActionMechCycleEquipment"; - [DataField("mechUiAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MechUiAction = "ActionMechOpenUI"; - [DataField("mechEjectAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MechEjectAction = "ActionMechEject"; + [DataField] + public EntProtoId MechCycleAction = "ActionMechCycleEquipment"; + [DataField] + public EntProtoId MechUiAction = "ActionMechOpenUI"; + [DataField] + public EntProtoId MechEjectAction = "ActionMechEject"; #endregion #region Visualizer States - [DataField("baseState")] + [DataField] public string? BaseState; - [DataField("openState")] + [DataField] public string? OpenState; - [DataField("brokenState")] + [DataField] public string? BrokenState; #endregion @@ -162,17 +159,3 @@ public sealed partial class MechComponent : Component [DataField] public EntityUid? MechUiActionEntity; [DataField] public EntityUid? MechEjectActionEntity; } - -/// -/// Contains network state for . -/// -[Serializable, NetSerializable] -public sealed class MechComponentState : ComponentState -{ - public FixedPoint2 Integrity; - public FixedPoint2 MaxIntegrity; - public FixedPoint2 Energy; - public FixedPoint2 MaxEnergy; - public NetEntity? CurrentSelectedEquipment; - public bool Broken; -} diff --git a/Content.Shared/Mech/Components/MechPilotComponent.cs b/Content.Shared/Mech/Components/MechPilotComponent.cs index 364bd0bf14b..64bf7082b71 100644 --- a/Content.Shared/Mech/Components/MechPilotComponent.cs +++ b/Content.Shared/Mech/Components/MechPilotComponent.cs @@ -1,5 +1,4 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Mech.Components; @@ -9,18 +8,12 @@ namespace Content.Shared.Mech.Components; /// /// Get in the robot, Shinji /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MechPilotComponent : Component { /// /// The mech being piloted /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public EntityUid Mech; } - -[Serializable, NetSerializable] -public sealed class MechPilotComponentState : ComponentState -{ - public NetEntity Mech; -} diff --git a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs index 7111c67779a..1cb08e1a253 100644 --- a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs +++ b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs @@ -16,7 +16,6 @@ using Content.Shared.Popups; using Content.Shared.Weapons.Melee; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Network; using Robust.Shared.Serialization; using Robust.Shared.Timing; @@ -42,11 +41,6 @@ public abstract class SharedMechSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - SubscribeLocalEvent(OnPilotGetState); - SubscribeLocalEvent(OnPilotHandleState); - SubscribeLocalEvent(OnToggleEquipmentAction); SubscribeLocalEvent(OnEjectPilotEvent); SubscribeLocalEvent(RelayInteractionEvent); @@ -59,52 +53,6 @@ public override void Initialize() SubscribeLocalEvent(OnAttackAttempt); } - #region State Handling - - private void OnGetState(EntityUid uid, MechComponent component, ref ComponentGetState args) - { - args.State = new MechComponentState - { - Integrity = component.Integrity, - MaxIntegrity = component.MaxIntegrity, - Energy = component.Energy, - MaxEnergy = component.MaxEnergy, - CurrentSelectedEquipment = GetNetEntity(component.CurrentSelectedEquipment), - Broken = component.Broken - }; - } - - private void OnHandleState(EntityUid uid, MechComponent component, ref ComponentHandleState args) - { - if (args.Current is not MechComponentState state) - return; - - component.Integrity = state.Integrity; - component.MaxIntegrity = state.MaxIntegrity; - component.Energy = state.Energy; - component.MaxEnergy = state.MaxEnergy; - component.CurrentSelectedEquipment = EnsureEntity(state.CurrentSelectedEquipment, uid); - component.Broken = state.Broken; - } - - private void OnPilotGetState(EntityUid uid, MechPilotComponent component, ref ComponentGetState args) - { - args.State = new MechPilotComponentState - { - Mech = GetNetEntity(component.Mech) - }; - } - - private void OnPilotHandleState(EntityUid uid, MechPilotComponent component, ref ComponentHandleState args) - { - if (args.Current is not MechPilotComponentState state) - return; - - component.Mech = EnsureEntity(state.Mech, uid); - } - - #endregion - private void OnToggleEquipmentAction(EntityUid uid, MechComponent component, MechToggleEquipmentEvent args) { if (args.Handled) diff --git a/Content.Shared/Movement/Components/FootstepModifierComponent.cs b/Content.Shared/Movement/Components/FootstepModifierComponent.cs index 88563276336..bd7b5377bd4 100644 --- a/Content.Shared/Movement/Components/FootstepModifierComponent.cs +++ b/Content.Shared/Movement/Components/FootstepModifierComponent.cs @@ -1,15 +1,14 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; -namespace Content.Shared.Movement.Components +namespace Content.Shared.Movement.Components; + +/// +/// Changes footstep sound +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FootstepModifierComponent : Component { - /// - /// Changes footstep sound - /// - [RegisterComponent, NetworkedComponent] - public sealed partial class FootstepModifierComponent : Component - { - [DataField("footstepSoundCollection", required: true)] - public SoundSpecifier Sound = default!; - } + [DataField(required: true), AutoNetworkedField] + public SoundSpecifier FootstepSoundCollection = default!; } diff --git a/Content.Shared/Movement/Components/InputMoverComponent.cs b/Content.Shared/Movement/Components/InputMoverComponent.cs index 1a987a9b29f..5562bfaee40 100644 --- a/Content.Shared/Movement/Components/InputMoverComponent.cs +++ b/Content.Shared/Movement/Components/InputMoverComponent.cs @@ -6,8 +6,7 @@ namespace Content.Shared.Movement.Components { - [RegisterComponent] - [NetworkedComponent] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class InputMoverComponent : Component { // This class has to be able to handle server TPS being lower than client FPS. @@ -41,36 +40,40 @@ public sealed partial class InputMoverComponent : Component public Vector2 CurTickWalkMovement; public Vector2 CurTickSprintMovement; + [AutoNetworkedField] public MoveButtons HeldMoveButtons = MoveButtons.None; /// /// Entity our movement is relative to. /// + [AutoNetworkedField] public EntityUid? RelativeEntity; /// /// Although our movement might be relative to a particular entity we may have an additional relative rotation /// e.g. if we've snapped to a different cardinal direction /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public Angle TargetRelativeRotation = Angle.Zero; /// /// The current relative rotation. This will lerp towards the . /// - [ViewVariables] public Angle RelativeRotation; + [ViewVariables, AutoNetworkedField] + public Angle RelativeRotation; /// /// If we traverse on / off a grid then set a timer to update our relative inputs. /// - [ViewVariables(VVAccess.ReadWrite), DataField("lerpTarget", customTypeSerializer: typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] public TimeSpan LerpTarget; public const float LerpTime = 1.0f; public bool Sprinting => (HeldMoveButtons & MoveButtons.Walk) == 0x0; - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool CanMove { get; set; } = true; } } diff --git a/Content.Shared/Movement/Components/JetpackUserComponent.cs b/Content.Shared/Movement/Components/JetpackUserComponent.cs index b59b677b62e..972f8c69c6a 100644 --- a/Content.Shared/Movement/Components/JetpackUserComponent.cs +++ b/Content.Shared/Movement/Components/JetpackUserComponent.cs @@ -5,8 +5,9 @@ namespace Content.Shared.Movement.Components; /// /// Added to someone using a jetpack for movement purposes /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class JetpackUserComponent : Component { + [AutoNetworkedField] public EntityUid Jetpack; } diff --git a/Content.Shared/Movement/Components/MobMoverComponent.cs b/Content.Shared/Movement/Components/MobMoverComponent.cs index e833f2d4b7d..a77f415b938 100644 --- a/Content.Shared/Movement/Components/MobMoverComponent.cs +++ b/Content.Shared/Movement/Components/MobMoverComponent.cs @@ -6,14 +6,13 @@ namespace Content.Shared.Movement.Components /// /// Has additional movement data such as footsteps and weightless grab range for an entity. /// - [RegisterComponent] - [NetworkedComponent()] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MobMoverComponent : Component { private float _stepSoundDistance; - [DataField("grabRange")] public float GrabRange = 1.0f; + [DataField] public float GrabRange = 1.0f; - [DataField("pushStrength")] public float PushStrength = 600f; + [DataField] public float PushStrength = 600f; [ViewVariables(VVAccess.ReadWrite)] public EntityCoordinates LastPosition { get; set; } @@ -32,7 +31,7 @@ public float StepSoundDistance } } - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float GrabRangeVV { get => GrabRange; @@ -44,7 +43,7 @@ public float GrabRangeVV } } - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float PushStrengthVV { get => PushStrength; diff --git a/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs b/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs index 33270c2034b..7efc12a7316 100644 --- a/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs +++ b/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs @@ -7,8 +7,8 @@ namespace Content.Shared.Movement.Components /// Applies basic movement speed and movement modifiers for an entity. /// If this is not present on the entity then they will use defaults for movement. /// - [RegisterComponent] - [NetworkedComponent, Access(typeof(MovementSpeedModifierSystem))] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] + [Access(typeof(MovementSpeedModifierSystem))] public sealed partial class MovementSpeedModifierComponent : Component { // Weightless @@ -25,10 +25,10 @@ public sealed partial class MovementSpeedModifierComponent : Component public const float DefaultBaseWalkSpeed = 2.5f; public const float DefaultBaseSprintSpeed = 4.5f; - [ViewVariables] + [AutoNetworkedField, ViewVariables] public float WalkSpeedModifier = 1.0f; - [ViewVariables] + [AutoNetworkedField, ViewVariables] public float SprintSpeedModifier = 1.0f; [ViewVariables(VVAccess.ReadWrite)] @@ -56,55 +56,56 @@ private float _baseSprintSpeedVV /// /// Minimum speed a mob has to be moving before applying movement friction. /// - [ViewVariables(VVAccess.ReadWrite), DataField("minimumFrictionSpeed")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float MinimumFrictionSpeed = DefaultMinimumFrictionSpeed; /// /// The negative velocity applied for friction when weightless and providing inputs. /// - [ViewVariables(VVAccess.ReadWrite), DataField("weightlessFriction")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float WeightlessFriction = DefaultWeightlessFriction; /// /// The negative velocity applied for friction when weightless and not providing inputs. /// This is essentially how much their speed decreases per second. /// - [ViewVariables(VVAccess.ReadWrite), DataField("weightlessFrictionNoInput")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float WeightlessFrictionNoInput = DefaultWeightlessFrictionNoInput; /// /// The movement speed modifier applied to a mob's total input velocity when weightless. /// - [ViewVariables(VVAccess.ReadWrite), DataField("weightlessModifier")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float WeightlessModifier = DefaultWeightlessModifier; /// /// The acceleration applied to mobs when moving and weightless. /// - [ViewVariables(VVAccess.ReadWrite), DataField("weightlessAcceleration")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float WeightlessAcceleration = DefaultWeightlessAcceleration; /// /// The acceleration applied to mobs when moving. /// - [ViewVariables(VVAccess.ReadWrite), DataField("acceleration")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float Acceleration = DefaultAcceleration; /// /// The negative velocity applied for friction. /// - [ViewVariables(VVAccess.ReadWrite), DataField("friction")] + [ViewVariables(VVAccess.ReadWrite), DataField] public float Friction = DefaultFriction; /// /// The negative velocity applied for friction. /// - [ViewVariables(VVAccess.ReadWrite), DataField("frictionNoInput")] public float? FrictionNoInput = null; + [ViewVariables(VVAccess.ReadWrite), DataField] + public float? FrictionNoInput; - [ViewVariables(VVAccess.ReadWrite), DataField("baseWalkSpeed")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float BaseWalkSpeed { get; set; } = DefaultBaseWalkSpeed; - [ViewVariables(VVAccess.ReadWrite), DataField("baseSprintSpeed")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float BaseSprintSpeed { get; set; } = DefaultBaseSprintSpeed; [ViewVariables] diff --git a/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs b/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs index a83fcf78b2c..c95ab379c6b 100644 --- a/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs +++ b/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs @@ -1,9 +1,6 @@ using Content.Shared.Inventory; using Content.Shared.Movement.Components; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Timing; -using Robust.Shared.Utility; namespace Content.Shared.Movement.Systems { @@ -11,33 +8,6 @@ public sealed class MovementSpeedModifierSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnGetState(EntityUid uid, MovementSpeedModifierComponent component, ref ComponentGetState args) - { - args.State = new MovementSpeedModifierComponentState - { - BaseWalkSpeed = component.BaseWalkSpeed, - BaseSprintSpeed = component.BaseSprintSpeed, - WalkSpeedModifier = component.WalkSpeedModifier, - SprintSpeedModifier = component.SprintSpeedModifier, - }; - } - - private void OnHandleState(EntityUid uid, MovementSpeedModifierComponent component, ref ComponentHandleState args) - { - if (args.Current is not MovementSpeedModifierComponentState state) return; - component.BaseWalkSpeed = state.BaseWalkSpeed; - component.BaseSprintSpeed = state.BaseSprintSpeed; - component.WalkSpeedModifier = state.WalkSpeedModifier; - component.SprintSpeedModifier = state.SprintSpeedModifier; - } - public void RefreshMovementSpeedModifiers(EntityUid uid, MovementSpeedModifierComponent? move = null) { if (!Resolve(uid, ref move, false)) @@ -68,15 +38,6 @@ public void ChangeBaseSpeed(EntityUid uid, float baseWalkSpeed, float baseSprint move.Acceleration = acceleration; Dirty(move); } - - [Serializable, NetSerializable] - private sealed class MovementSpeedModifierComponentState : ComponentState - { - public float BaseWalkSpeed; - public float BaseSprintSpeed; - public float WalkSpeedModifier; - public float SprintSpeedModifier; - } } /// diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index 26373da2567..f624f6c4ce4 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -5,7 +5,6 @@ using Content.Shared.Movement.Events; using Content.Shared.Popups; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Serialization; @@ -31,8 +30,6 @@ public override void Initialize() SubscribeLocalEvent(OnJetpackUserCanWeightless); SubscribeLocalEvent(OnJetpackUserEntParentChanged); - SubscribeLocalEvent(OnJetpackUserGetState); - SubscribeLocalEvent(OnJetpackUserHandleState); SubscribeLocalEvent(OnJetpackUserGravityChanged); } @@ -60,22 +57,6 @@ private void OnJetpackUserGravityChanged(ref GravityChangedEvent ev) } } - private void OnJetpackUserHandleState(EntityUid uid, JetpackUserComponent component, ref ComponentHandleState args) - { - if (args.Current is not JetpackUserComponentState state) - return; - - component.Jetpack = EnsureEntity(state.Jetpack, uid); - } - - private void OnJetpackUserGetState(EntityUid uid, JetpackUserComponent component, ref ComponentGetState args) - { - args.State = new JetpackUserComponentState() - { - Jetpack = GetNetEntity(component.Jetpack), - }; - } - private void OnJetpackDropped(EntityUid uid, JetpackComponent component, DroppedEvent args) { SetEnabled(uid, component, false, args.User); @@ -204,12 +185,6 @@ protected virtual bool CanEnable(EntityUid uid, JetpackComponent component) { return true; } - - [Serializable, NetSerializable] - protected sealed class JetpackUserComponentState : ComponentState - { - public NetEntity Jetpack; - } } [Serializable, NetSerializable] diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Footsteps.cs b/Content.Shared/Movement/Systems/SharedMoverController.Footsteps.cs deleted file mode 100644 index bbaf2250ecb..00000000000 --- a/Content.Shared/Movement/Systems/SharedMoverController.Footsteps.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Content.Shared.Movement.Components; -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Movement.Systems; - -public abstract partial class SharedMoverController -{ - private void InitializeFootsteps() - { - SubscribeLocalEvent(OnFootGetState); - SubscribeLocalEvent(OnFootHandleState); - } - - private void OnFootHandleState(EntityUid uid, FootstepModifierComponent component, ref ComponentHandleState args) - { - if (args.Current is not FootstepModifierComponentState state) return; - component.Sound = state.Sound; - } - - private void OnFootGetState(EntityUid uid, FootstepModifierComponent component, ref ComponentGetState args) - { - args.State = new FootstepModifierComponentState() - { - Sound = component.Sound, - }; - } - - [Serializable, NetSerializable] - private sealed class FootstepModifierComponentState : ComponentState - { - public SoundSpecifier Sound = default!; - } -} diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs index 9d150a0652b..425322408ef 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs @@ -4,7 +4,6 @@ using Content.Shared.Input; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; -using Robust.Shared.GameStates; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Players; @@ -49,8 +48,7 @@ private void InitializeInput() .Register(); SubscribeLocalEvent(OnInputInit); - SubscribeLocalEvent(OnInputGetState); - SubscribeLocalEvent(OnInputHandleState); + SubscribeLocalEvent(OnInputHandleState); SubscribeLocalEvent(OnInputParentChange); SubscribeLocalEvent(OnAutoParentChange); @@ -75,31 +73,10 @@ protected void SetMoveInput(InputMoverComponent component, MoveButtons buttons) Dirty(component); } - private void OnInputHandleState(EntityUid uid, InputMoverComponent component, ref ComponentHandleState args) + private void OnInputHandleState(EntityUid uid, InputMoverComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not InputMoverComponentState state) - return; - - component.HeldMoveButtons = state.Buttons; component.LastInputTick = GameTick.Zero; component.LastInputSubTick = 0; - component.CanMove = state.CanMove; - - component.RelativeRotation = state.RelativeRotation; - component.TargetRelativeRotation = state.TargetRelativeRotation; - component.RelativeEntity = EnsureEntity(state.RelativeEntity, uid); - component.LerpTarget = state.LerpAccumulator; - } - - private void OnInputGetState(EntityUid uid, InputMoverComponent component, ref ComponentGetState args) - { - args.State = new InputMoverComponentState( - component.HeldMoveButtons, - component.CanMove, - component.RelativeRotation, - component.TargetRelativeRotation, - GetNetEntity(component.RelativeEntity), - component.LerpTarget); } private void ShutdownInput() @@ -564,35 +541,6 @@ public override bool HandleCmdMessage(IEntityManager entManager, ICommonSession? } } - [Serializable, NetSerializable] - private sealed class InputMoverComponentState : ComponentState - { - public MoveButtons Buttons { get; } - public readonly bool CanMove; - - /// - /// Our current rotation for movement purposes. This is lerping towards - /// - public Angle RelativeRotation; - - /// - /// Target rotation relative to the . Typically 0 - /// - public Angle TargetRelativeRotation; - public NetEntity? RelativeEntity; - public TimeSpan LerpAccumulator; - - public InputMoverComponentState(MoveButtons buttons, bool canMove, Angle relativeRotation, Angle targetRelativeRotation, NetEntity? relativeEntity, TimeSpan lerpTarget) - { - Buttons = buttons; - CanMove = canMove; - RelativeRotation = relativeRotation; - TargetRelativeRotation = targetRelativeRotation; - RelativeEntity = relativeEntity; - LerpAccumulator = lerpTarget; - } - } - private sealed class ShuttleInputCmdHandler : InputCmdHandler { private readonly SharedMoverController _controller; @@ -615,6 +563,7 @@ public override bool HandleCmdMessage(IEntityManager entManager, ICommonSession? } [Flags] + [Serializable, NetSerializable] public enum MoveButtons : byte { None = 0, diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Mob.cs b/Content.Shared/Movement/Systems/SharedMoverController.Mob.cs deleted file mode 100644 index 9f6c2f4a486..00000000000 --- a/Content.Shared/Movement/Systems/SharedMoverController.Mob.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Content.Shared.Movement.Components; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Movement.Systems; - -public abstract partial class SharedMoverController -{ - private void InitializeMob() - { - SubscribeLocalEvent(OnMobGetState); - SubscribeLocalEvent(OnMobHandleState); - } - - private void OnMobHandleState(EntityUid uid, MobMoverComponent component, ref ComponentHandleState args) - { - if (args.Current is not MobMoverComponentState state) return; - component.GrabRangeVV = state.GrabRange; - component.PushStrengthVV = state.PushStrength; - } - - private void OnMobGetState(EntityUid uid, MobMoverComponent component, ref ComponentGetState args) - { - args.State = new MobMoverComponentState(component.GrabRange, component.PushStrength); - } - - [Serializable, NetSerializable] - private sealed class MobMoverComponentState : ComponentState - { - public float GrabRange; - public float PushStrength; - - public MobMoverComponentState(float grabRange, float pushStrength) - { - GrabRange = grabRange; - PushStrength = pushStrength; - } - } -} diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index a9297b94110..af065d0dec8 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -1,8 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using Content.Shared.Bed.Sleep; using Content.Shared.CCVar; using Content.Shared.Friction; using Content.Shared.Gravity; using Content.Shared.Inventory; using Content.Shared.Maps; +using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; using Content.Shared.Pulling.Components; @@ -12,15 +16,11 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Controllers; +using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; using Robust.Shared.Utility; -using System.Diagnostics.CodeAnalysis; -using System.Numerics; -using Content.Shared.Mobs.Systems; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; -using Content.Shared.Bed.Sleep; namespace Content.Shared.Movement.Systems { @@ -88,9 +88,7 @@ public override void Initialize() NoRotateQuery = GetEntityQuery(); CanMoveInAirQuery = GetEntityQuery(); - InitializeFootsteps(); InitializeInput(); - InitializeMob(); InitializeRelay(); _configManager.OnValueChanged(CCVars.RelativeMovement, SetRelativeMovement, true); _configManager.OnValueChanged(CCVars.StopSpeed, SetStopSpeed, true); @@ -440,14 +438,14 @@ private bool TryGetSound( if (TryComp(uid, out var moverModifier)) { - sound = moverModifier.Sound; + sound = moverModifier.FootstepSoundCollection; return true; } if (_inventory.TryGetSlotEntity(uid, "shoes", out var shoes) && TryComp(shoes, out var modifier)) { - sound = modifier.Sound; + sound = modifier.FootstepSoundCollection; return true; } @@ -468,7 +466,7 @@ private bool TryGetFootstepSound( { if (TryComp(xform.MapUid, out var modifier)) { - sound = modifier.Sound; + sound = modifier.FootstepSoundCollection; return true; } @@ -494,7 +492,7 @@ private bool TryGetFootstepSound( if (TryComp(maybeFootstep, out var footstep)) { - sound = footstep.Sound; + sound = footstep.FootstepSoundCollection; return true; } } diff --git a/Content.Shared/Physics/Controllers/SharedConveyorController.cs b/Content.Shared/Physics/Controllers/SharedConveyorController.cs index 1ba66aa1a37..8ec6ddbefe5 100644 --- a/Content.Shared/Physics/Controllers/SharedConveyorController.cs +++ b/Content.Shared/Physics/Controllers/SharedConveyorController.cs @@ -2,7 +2,6 @@ using Content.Shared.Conveyor; using Content.Shared.Gravity; using Content.Shared.Movement.Systems; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; @@ -26,8 +25,6 @@ public abstract class SharedConveyorController : VirtualController public override void Initialize() { UpdatesAfter.Add(typeof(SharedMoverController)); - SubscribeLocalEvent(OnConveyorGetState); - SubscribeLocalEvent(OnConveyorHandleState); SubscribeLocalEvent(OnConveyorStartCollide); SubscribeLocalEvent(OnConveyorEndCollide); @@ -35,22 +32,6 @@ public override void Initialize() base.Initialize(); } - private void OnConveyorGetState(EntityUid uid, ConveyorComponent component, ref ComponentGetState args) - { - args.State = new ConveyorComponentState(component.Angle, component.Speed, component.State, component.Powered); - } - - private void OnConveyorHandleState(EntityUid uid, ConveyorComponent component, ref ComponentHandleState args) - { - if (args.Current is not ConveyorComponentState state) - return; - - component.Powered = state.Powered; - component.Angle = state.Angle; - component.Speed = state.Speed; - component.State = state.State; - } - private void OnConveyorStartCollide(EntityUid uid, ConveyorComponent component, ref StartCollideEvent args) { var otherUid = args.OtherEntity; diff --git a/Content.Shared/Physics/PreventCollideComponent.cs b/Content.Shared/Physics/PreventCollideComponent.cs index 429b7b56b3f..af59d367735 100644 --- a/Content.Shared/Physics/PreventCollideComponent.cs +++ b/Content.Shared/Physics/PreventCollideComponent.cs @@ -1,24 +1,14 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Physics; /// /// Use this to allow a specific UID to prevent collides /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class PreventCollideComponent : Component { + [AutoNetworkedField] public EntityUid Uid; } -[Serializable, NetSerializable] -public sealed class PreventCollideComponentState : ComponentState -{ - public NetEntity Uid; - - public PreventCollideComponentState(NetEntity netEntity) - { - Uid = netEntity; - } -} diff --git a/Content.Shared/Physics/SharedPreventCollideSystem.cs b/Content.Shared/Physics/SharedPreventCollideSystem.cs index 408125e1409..83d3a918e87 100644 --- a/Content.Shared/Physics/SharedPreventCollideSystem.cs +++ b/Content.Shared/Physics/SharedPreventCollideSystem.cs @@ -1,6 +1,4 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Physics.Dynamics; -using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Events; namespace Content.Shared.Physics; @@ -10,24 +8,9 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnPreventCollide); } - private void OnGetState(EntityUid uid, PreventCollideComponent component, ref ComponentGetState args) - { - args.State = new PreventCollideComponentState(GetNetEntity(component.Uid)); - } - - private void OnHandleState(EntityUid uid, PreventCollideComponent component, ref ComponentHandleState args) - { - if (args.Current is not PreventCollideComponentState state) - return; - - component.Uid = EnsureEntity(state.Uid, uid); - } - private void OnPreventCollide(EntityUid uid, PreventCollideComponent component, ref PreventCollideEvent args) { if (component.Uid == args.OtherEntity) diff --git a/Content.Shared/Placeable/ItemPlacerComponent.cs b/Content.Shared/Placeable/ItemPlacerComponent.cs index c4fb6079cfb..84df2e395a8 100644 --- a/Content.Shared/Placeable/ItemPlacerComponent.cs +++ b/Content.Shared/Placeable/ItemPlacerComponent.cs @@ -6,26 +6,27 @@ namespace Content.Shared.Placeable; /// /// Detects items placed on it that match a whitelist. /// -[RegisterComponent, NetworkedComponent, Access(typeof(ItemPlacerSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(ItemPlacerSystem))] public sealed partial class ItemPlacerComponent : Component { /// /// The entities that are currently on top of the placer. /// Guaranteed to have less than enitities if it is set. /// - [DataField("placedEntities")] + [DataField, AutoNetworkedField] public HashSet PlacedEntities = new(); /// /// Whitelist for entities that can be placed. /// - [DataField("whitelist"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public EntityWhitelist? Whitelist; /// /// The max amount of entities that can be placed at the same time. /// If 0, there is no limit. /// - [ViewVariables(VVAccess.ReadWrite), DataField("maxEntities")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public uint MaxEntities = 1; } diff --git a/Content.Shared/Placeable/ItemPlacerSystem.cs b/Content.Shared/Placeable/ItemPlacerSystem.cs index ccce286214e..92dc8eb74b7 100644 --- a/Content.Shared/Placeable/ItemPlacerSystem.cs +++ b/Content.Shared/Placeable/ItemPlacerSystem.cs @@ -1,8 +1,5 @@ using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; -using System.Linq; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Placeable; @@ -21,28 +18,6 @@ public override void Initialize() SubscribeLocalEvent(OnStartCollide); SubscribeLocalEvent(OnEndCollide); - SubscribeLocalEvent(OnPlacerGetState); - SubscribeLocalEvent(OnPlacerHandleState); - } - - private void OnPlacerHandleState(EntityUid uid, ItemPlacerComponent component, ref ComponentHandleState args) - { - if (args.Current is not ItemPlacerComponentState state) - return; - - component.MaxEntities = state.MaxEntities; - component.PlacedEntities.Clear(); - var ents = EnsureEntitySet(state.Entities, uid); - component.PlacedEntities.UnionWith(ents); - } - - private void OnPlacerGetState(EntityUid uid, ItemPlacerComponent component, ref ComponentGetState args) - { - args.State = new ItemPlacerComponentState() - { - MaxEntities = component.MaxEntities, - Entities = GetNetEntitySet(component.PlacedEntities), - }; } private void OnStartCollide(EntityUid uid, ItemPlacerComponent comp, ref StartCollideEvent args) @@ -81,13 +56,6 @@ private void OnEndCollide(EntityUid uid, ItemPlacerComponent comp, ref EndCollid _placeableSurface.SetPlaceable(uid, true); } - - [Serializable, NetSerializable] - private sealed class ItemPlacerComponentState : ComponentState - { - public uint MaxEntities; - public HashSet Entities = default!; - } } /// diff --git a/Content.Shared/Placeable/PlaceableSurfaceComponent.cs b/Content.Shared/Placeable/PlaceableSurfaceComponent.cs index b30bcedcdbd..40fa282ab5f 100644 --- a/Content.Shared/Placeable/PlaceableSurfaceComponent.cs +++ b/Content.Shared/Placeable/PlaceableSurfaceComponent.cs @@ -1,35 +1,18 @@ using System.Numerics; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; -namespace Content.Shared.Placeable -{ - [RegisterComponent, NetworkedComponent] - [Access(typeof(PlaceableSurfaceSystem))] - public sealed partial class PlaceableSurfaceComponent : Component - { - [DataField("isPlaceable")] - public bool IsPlaceable { get; set; } = true; - - [DataField("placeCentered")] - public bool PlaceCentered { get; set; } +namespace Content.Shared.Placeable; - [DataField("positionOffset")] - public Vector2 PositionOffset { get; set; } - } +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(PlaceableSurfaceSystem))] +public sealed partial class PlaceableSurfaceComponent : Component +{ + [DataField, AutoNetworkedField] + public bool IsPlaceable { get; set; } = true; - [Serializable, NetSerializable] - public sealed class PlaceableSurfaceComponentState : ComponentState - { - public readonly bool IsPlaceable; - public readonly bool PlaceCentered; - public readonly Vector2 PositionOffset; + [DataField, AutoNetworkedField] + public bool PlaceCentered { get; set; } - public PlaceableSurfaceComponentState(bool placeable, bool centered, Vector2 offset) - { - IsPlaceable = placeable; - PlaceCentered = centered; - PositionOffset = offset; - } - } + [DataField, AutoNetworkedField] + public Vector2 PositionOffset { get; set; } } diff --git a/Content.Shared/Placeable/PlaceableSurfaceSystem.cs b/Content.Shared/Placeable/PlaceableSurfaceSystem.cs index 7464c8890c1..b0031cfa33f 100644 --- a/Content.Shared/Placeable/PlaceableSurfaceSystem.cs +++ b/Content.Shared/Placeable/PlaceableSurfaceSystem.cs @@ -1,8 +1,7 @@ using System.Numerics; -using Content.Shared.Storage.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; -using Robust.Shared.GameStates; +using Content.Shared.Storage.Components; namespace Content.Shared.Placeable { @@ -15,13 +14,6 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnAfterInteractUsing); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnGetState(EntityUid uid, PlaceableSurfaceComponent component, ref ComponentGetState args) - { - args.State = new PlaceableSurfaceComponentState(component.IsPlaceable, component.PlaceCentered, component.PositionOffset); } public void SetPlaceable(EntityUid uid, bool isPlaceable, PlaceableSurfaceComponent? surface = null) @@ -30,7 +22,7 @@ public void SetPlaceable(EntityUid uid, bool isPlaceable, PlaceableSurfaceCompon return; surface.IsPlaceable = isPlaceable; - Dirty(surface); + Dirty(uid, surface); } public void SetPlaceCentered(EntityUid uid, bool placeCentered, PlaceableSurfaceComponent? surface = null) @@ -39,7 +31,7 @@ public void SetPlaceCentered(EntityUid uid, bool placeCentered, PlaceableSurface return; surface.PlaceCentered = placeCentered; - Dirty(surface); + Dirty(uid, surface); } public void SetPositionOffset(EntityUid uid, Vector2 offset, PlaceableSurfaceComponent? surface = null) @@ -48,7 +40,7 @@ public void SetPositionOffset(EntityUid uid, Vector2 offset, PlaceableSurfaceCom return; surface.PositionOffset = offset; - Dirty(surface); + Dirty(uid, surface); } private void OnAfterInteractUsing(EntityUid uid, PlaceableSurfaceComponent surface, AfterInteractUsingEvent args) @@ -74,15 +66,5 @@ private void OnAfterInteractUsing(EntityUid uid, PlaceableSurfaceComponent surfa args.Handled = true; } - - private void OnHandleState(EntityUid uid, PlaceableSurfaceComponent component, ref ComponentHandleState args) - { - if (args.Current is not PlaceableSurfaceComponentState state) - return; - - component.IsPlaceable = state.IsPlaceable; - component.PlaceCentered = state.PlaceCentered; - component.PositionOffset = state.PositionOffset; - } } } diff --git a/Content.Shared/Points/PointManagerComponent.cs b/Content.Shared/Points/PointManagerComponent.cs index 4250d44dc12..91dfef6a4e3 100644 --- a/Content.Shared/Points/PointManagerComponent.cs +++ b/Content.Shared/Points/PointManagerComponent.cs @@ -1,7 +1,6 @@ using Content.Shared.FixedPoint; using Robust.Shared.GameStates; using Robust.Shared.Network; -using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Points; @@ -9,32 +8,19 @@ namespace Content.Shared.Points; /// /// This is a component that generically stores points for all players. /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedPointSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[Access(typeof(SharedPointSystem))] public sealed partial class PointManagerComponent : Component { /// /// A dictionary of a player's netuserID to the amount of points they have. /// - [DataField("points")] + [DataField, AutoNetworkedField(true)] public Dictionary Points = new(); /// /// A text-only version of the scoreboard used by the client. /// - [DataField("scoreboard")] + [DataField, AutoNetworkedField] public FormattedMessage Scoreboard = new(); } - -[Serializable, NetSerializable] -public sealed class PointManagerComponentState : ComponentState -{ - public Dictionary Points; - - public FormattedMessage Scoreboard; - - public PointManagerComponentState(Dictionary points, FormattedMessage scoreboard) - { - Points = points; - Scoreboard = scoreboard; - } -} diff --git a/Content.Shared/Radiation/Components/GeigerComponent.cs b/Content.Shared/Radiation/Components/GeigerComponent.cs index ebcd84b3a3c..585c1a51dcb 100644 --- a/Content.Shared/Radiation/Components/GeigerComponent.cs +++ b/Content.Shared/Radiation/Components/GeigerComponent.cs @@ -9,41 +9,41 @@ namespace Content.Shared.Radiation.Components; /// Geiger counter that shows current radiation level. /// Can be added as a component to clothes. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] [Access(typeof(SharedGeigerSystem))] public sealed partial class GeigerComponent : Component { /// /// If true it will be active only when player equipped it. /// - [DataField("attachedToSuit")] + [DataField] public bool AttachedToSuit; /// /// Is geiger counter currently active? /// If false attached entity will ignore any radiation rays. /// - [DataField("isEnabled")] + [DataField, AutoNetworkedField] public bool IsEnabled; /// /// Should it shows examine message with current radiation level? /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("showExamine")] + [DataField] public bool ShowExamine; /// /// Should it shows item control when equipped by player? /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("showControl")] + [DataField] public bool ShowControl; /// /// Map of sounds that should be play on loop for different radiation levels. /// - [DataField("sounds")] + [DataField] public Dictionary Sounds = new() { {GeigerDangerLevel.Low, new SoundPathSpecifier("/Audio/Items/Geiger/low.ogg")}, @@ -55,13 +55,13 @@ public sealed partial class GeigerComponent : Component /// /// Current radiation level in rad per second. /// - [ViewVariables(VVAccess.ReadOnly)] + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] public float CurrentRadiation; /// /// Estimated radiation danger level. /// - [ViewVariables(VVAccess.ReadOnly)] + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] public GeigerDangerLevel DangerLevel = GeigerDangerLevel.None; /// @@ -69,7 +69,7 @@ public sealed partial class GeigerComponent : Component /// Because sound is annoying, geiger counter clicks will play /// only for player that equipped it. /// - [ViewVariables(VVAccess.ReadOnly)] + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] public EntityUid? User; /// @@ -85,15 +85,6 @@ public sealed partial class GeigerComponent : Component public IPlayingAudioStream? Stream; } -[Serializable, NetSerializable] -public sealed class GeigerComponentState : ComponentState -{ - public float CurrentRadiation; - public GeigerDangerLevel DangerLevel; - public bool IsEnabled; - public NetEntity? User; -} - [Serializable, NetSerializable] public enum GeigerDangerLevel : byte { diff --git a/Content.Shared/Shuttles/Components/IFFComponent.cs b/Content.Shared/Shuttles/Components/IFFComponent.cs index dc834aebf2f..24f06e93d4f 100644 --- a/Content.Shared/Shuttles/Components/IFFComponent.cs +++ b/Content.Shared/Shuttles/Components/IFFComponent.cs @@ -6,7 +6,8 @@ namespace Content.Shared.Shuttles.Components; /// /// Handles what a grid should look like on radar. /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedShuttleSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedShuttleSystem))] public sealed partial class IFFComponent : Component { /// @@ -19,13 +20,13 @@ public sealed partial class IFFComponent : Component /// public static readonly Color IFFColor = Color.Aquamarine; - [ViewVariables(VVAccess.ReadWrite), DataField("flags")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public IFFFlags Flags = IFFFlags.None; /// /// Color for this to show up on IFF. /// - [ViewVariables(VVAccess.ReadWrite), DataField("color")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public Color Color = IFFColor; } diff --git a/Content.Shared/Shuttles/Components/RadarConsoleComponent.cs b/Content.Shared/Shuttles/Components/RadarConsoleComponent.cs index 952f4798225..96018480f1b 100644 --- a/Content.Shared/Shuttles/Components/RadarConsoleComponent.cs +++ b/Content.Shared/Shuttles/Components/RadarConsoleComponent.cs @@ -3,7 +3,8 @@ namespace Content.Shared.Shuttles.Components; -[RegisterComponent, NetworkedComponent, Access(typeof(SharedRadarConsoleSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRadarConsoleSystem))] public sealed partial class RadarConsoleComponent : Component { [ViewVariables(VVAccess.ReadWrite)] @@ -16,6 +17,6 @@ public float RangeVV .SetRange(Owner, value, this); } - [DataField("maxRange")] + [DataField, AutoNetworkedField] public float MaxRange = 256f; } diff --git a/Content.Shared/Shuttles/Systems/SharedRadarConsoleSystem.cs b/Content.Shared/Shuttles/Systems/SharedRadarConsoleSystem.cs index 2e98e899231..a069a2d2e25 100644 --- a/Content.Shared/Shuttles/Systems/SharedRadarConsoleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedRadarConsoleSystem.cs @@ -1,6 +1,4 @@ using Content.Shared.Shuttles.Components; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Shuttles.Systems; @@ -9,29 +7,6 @@ public abstract class SharedRadarConsoleSystem : EntitySystem public const float DefaultMinRange = 64f; public const float DefaultMaxRange = 256f; - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnHandleState(EntityUid uid, RadarConsoleComponent component, ref ComponentHandleState args) - { - if (args.Current is not RadarConsoleComponentState state) - return; - - component.MaxRange = state.Range; - } - - private void OnGetState(EntityUid uid, RadarConsoleComponent component, ref ComponentGetState args) - { - args.State = new RadarConsoleComponentState() - { - Range = component.MaxRange - }; - } - protected virtual void UpdateState(EntityUid uid, RadarConsoleComponent component) { } @@ -45,10 +20,4 @@ public void SetRange(EntityUid uid, float value, RadarConsoleComponent component Dirty(uid, component); UpdateState(uid, component); } - - [Serializable, NetSerializable] - protected sealed class RadarConsoleComponentState : ComponentState - { - public float Range; - } } diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs index a128d763382..587b5fafe04 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs @@ -1,7 +1,5 @@ using Content.Shared.Shuttles.Components; using JetBrains.Annotations; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Shuttles.Systems; @@ -11,12 +9,6 @@ public abstract partial class SharedShuttleSystem * Handles the label visibility on radar controls. This can be hiding the label or applying other effects. */ - private void InitializeIFF() - { - SubscribeLocalEvent(OnIFFGetState); - SubscribeLocalEvent(OnIFFHandleState); - } - protected virtual void UpdateIFFInterfaces(EntityUid gridUid, IFFComponent component) {} /// @@ -61,29 +53,4 @@ public void RemoveIFFFlag(EntityUid gridUid, IFFFlags flags, IFFComponent? compo Dirty(component); UpdateIFFInterfaces(gridUid, component); } - - private void OnIFFHandleState(EntityUid uid, IFFComponent component, ref ComponentHandleState args) - { - if (args.Current is not IFFComponentState state) - return; - - component.Flags = state.Flags; - component.Color = state.Color; - } - - private void OnIFFGetState(EntityUid uid, IFFComponent component, ref ComponentGetState args) - { - args.State = new IFFComponentState() - { - Flags = component.Flags, - Color = component.Color, - }; - } - - [Serializable, NetSerializable] - private sealed class IFFComponentState : ComponentState - { - public IFFFlags Flags; - public Color Color; - } } diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs index e75976c585d..8471e83df51 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs @@ -2,11 +2,6 @@ namespace Content.Shared.Shuttles.Systems; public abstract partial class SharedShuttleSystem : EntitySystem { - public override void Initialize() - { - base.Initialize(); - InitializeIFF(); - } } [Flags] diff --git a/Content.Shared/Slippery/SlipperyComponent.cs b/Content.Shared/Slippery/SlipperyComponent.cs index ff395176ed0..b470e2cbbd5 100644 --- a/Content.Shared/Slippery/SlipperyComponent.cs +++ b/Content.Shared/Slippery/SlipperyComponent.cs @@ -1,7 +1,6 @@ using Content.Shared.StepTrigger.Components; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Slippery { @@ -11,14 +10,13 @@ namespace Content.Shared.Slippery /// /// Requires , see that component for some additional properties. /// - [RegisterComponent] - [NetworkedComponent] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class SlipperyComponent : Component { /// /// Path to the sound to be played when a mob slips. /// - [DataField("slipSound")] + [DataField, AutoNetworkedField] [Access(Other = AccessPermissions.ReadWriteExecute)] public SoundSpecifier SlipSound = new SoundPathSpecifier("/Audio/Effects/slip.ogg"); @@ -26,7 +24,7 @@ public sealed partial class SlipperyComponent : Component /// How many seconds the mob will be paralyzed for. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("paralyzeTime")] + [DataField, AutoNetworkedField] [Access(Other = AccessPermissions.ReadWrite)] public float ParalyzeTime = 3f; @@ -34,23 +32,8 @@ public sealed partial class SlipperyComponent : Component /// The entity's speed will be multiplied by this to slip it forwards. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("launchForwardsMultiplier")] + [DataField, AutoNetworkedField] [Access(Other = AccessPermissions.ReadWrite)] public float LaunchForwardsMultiplier = 1f; } - - [Serializable, NetSerializable] - public sealed class SlipperyComponentState : ComponentState - { - public float ParalyzeTime { get; } - public float LaunchForwardsMultiplier { get; } - public string SlipSound { get; } - - public SlipperyComponentState(float paralyzeTime, float launchForwardsMultiplier, string slipSound) - { - ParalyzeTime = paralyzeTime; - LaunchForwardsMultiplier = launchForwardsMultiplier; - SlipSound = slipSound; - } - } } diff --git a/Content.Shared/Slippery/SlipperySystem.cs b/Content.Shared/Slippery/SlipperySystem.cs index a89291aea49..00f023f9a3a 100644 --- a/Content.Shared/Slippery/SlipperySystem.cs +++ b/Content.Shared/Slippery/SlipperySystem.cs @@ -5,9 +5,7 @@ using Content.Shared.StepTrigger.Systems; using Content.Shared.Stunnable; using JetBrains.Annotations; -using Robust.Shared.Audio; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; @@ -32,22 +30,6 @@ public override void Initialize() SubscribeLocalEvent(OnNoSlipAttempt); // as long as slip-resistant mice are never added, this should be fine (otherwise a mouse-hat will transfer it's power to the wearer). SubscribeLocalEvent>((e, c, ev) => OnNoSlipAttempt(e, c, ev.Args)); - SubscribeLocalEvent(OnSlipperyGetState); - SubscribeLocalEvent(OnSlipperyHandleState); - } - - private void OnSlipperyHandleState(EntityUid uid, SlipperyComponent component, ref ComponentHandleState args) - { - if (args.Current is not SlipperyComponentState state) return; - - component.ParalyzeTime = state.ParalyzeTime; - component.LaunchForwardsMultiplier = state.LaunchForwardsMultiplier; - component.SlipSound = new SoundPathSpecifier(state.SlipSound); - } - - private void OnSlipperyGetState(EntityUid uid, SlipperyComponent component, ref ComponentGetState args) - { - args.State = new SlipperyComponentState(component.ParalyzeTime, component.LaunchForwardsMultiplier, _audio.GetSound(component.SlipSound)); } private void HandleStepTrigger(EntityUid uid, SlipperyComponent component, ref StepTriggeredEvent args) diff --git a/Content.Shared/Speech/SpeechComponent.cs b/Content.Shared/Speech/SpeechComponent.cs index f5ef0e0d678..96e05502ad6 100644 --- a/Content.Shared/Speech/SpeechComponent.cs +++ b/Content.Shared/Speech/SpeechComponent.cs @@ -1,8 +1,6 @@ -using System.Collections.Specialized; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; +using Robust.Shared.Prototypes; namespace Content.Shared.Speech { @@ -10,31 +8,30 @@ namespace Content.Shared.Speech /// Component required for entities to be able to speak. (TODO: Entities can speak fine without this, this only forbids them speak if they have it and enabled is false.) /// Contains the option to let entities make noise when speaking, change speech verbs, datafields for the sounds in question, and relevant AudioParams. /// - [RegisterComponent, NetworkedComponent] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class SpeechComponent : Component { - [DataField("enabled"), Access(typeof(SpeechSystem), - Friend = AccessPermissions.ReadWrite, - Other = AccessPermissions.Read)] + [DataField, AutoNetworkedField] + [Access(typeof(SpeechSystem), Friend = AccessPermissions.ReadWrite, Other = AccessPermissions.Read)] public bool Enabled = true; [ViewVariables(VVAccess.ReadWrite)] - [DataField("speechSounds", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string? SpeechSounds; + [DataField] + public ProtoId? SpeechSounds; /// /// What speech verb prototype should be used by default for displaying this entity's messages? /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("speechVerb", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string SpeechVerb = "Default"; + [DataField] + public ProtoId SpeechVerb = "Default"; /// /// A mapping from chat suffixes loc strings to speech verb prototypes that should be conditionally used. /// For things like '?' changing to 'asks' or '!!' making text bold and changing to 'yells'. Can be overridden if necessary. /// - [DataField("suffixSpeechVerbs", customTypeSerializer:typeof(PrototypeIdValueDictionarySerializer))] - public Dictionary SuffixSpeechVerbs = new() + [DataField] + public Dictionary> SuffixSpeechVerbs = new() { { "chat-speech-verb-suffix-exclamation-strong", "DefaultExclamationStrong" }, { "chat-speech-verb-suffix-exclamation", "DefaultExclamation" }, @@ -43,11 +40,11 @@ public sealed partial class SpeechComponent : Component { "chat-speech-verb-suffix-mumble", "DefaultMumble" }, }; - [DataField("audioParams")] + [DataField] public AudioParams AudioParams = AudioParams.Default.WithVolume(6f).WithRolloffFactor(4.5f); [ViewVariables(VVAccess.ReadWrite)] - [DataField("soundCooldownTime")] + [DataField] public float SoundCooldownTime { get; set; } = 0.5f; public TimeSpan LastTimeSoundPlayed = TimeSpan.Zero; diff --git a/Content.Shared/Speech/SpeechSystem.cs b/Content.Shared/Speech/SpeechSystem.cs index a21158aa9e3..4ce408b91a6 100644 --- a/Content.Shared/Speech/SpeechSystem.cs +++ b/Content.Shared/Speech/SpeechSystem.cs @@ -1,6 +1,3 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - namespace Content.Shared.Speech { public sealed class SpeechSystem : EntitySystem @@ -10,8 +7,6 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnSpeakAttempt); - SubscribeLocalEvent(OnSpeechGetState); - SubscribeLocalEvent(OnSpeechHandleState); } public void SetSpeech(EntityUid uid, bool value, SpeechComponent? component = null) @@ -27,34 +22,10 @@ public void SetSpeech(EntityUid uid, bool value, SpeechComponent? component = nu Dirty(component); } - private void OnSpeechHandleState(EntityUid uid, SpeechComponent component, ref ComponentHandleState args) - { - if (args.Current is not SpeechComponentState state) - return; - - component.Enabled = state.Enabled; - } - - private void OnSpeechGetState(EntityUid uid, SpeechComponent component, ref ComponentGetState args) - { - args.State = new SpeechComponentState(component.Enabled); - } - private void OnSpeakAttempt(SpeakAttemptEvent args) { if (!TryComp(args.Uid, out SpeechComponent? speech) || !speech.Enabled) args.Cancel(); } - - [Serializable, NetSerializable] - private sealed class SpeechComponentState : ComponentState - { - public readonly bool Enabled; - - public SpeechComponentState(bool enabled) - { - Enabled = enabled; - } - } } } diff --git a/Content.Shared/Standing/StandingStateComponent.cs b/Content.Shared/Standing/StandingStateComponent.cs index 583839fa105..b1ec6d8668b 100644 --- a/Content.Shared/Standing/StandingStateComponent.cs +++ b/Content.Shared/Standing/StandingStateComponent.cs @@ -3,22 +3,22 @@ namespace Content.Shared.Standing { + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(StandingStateSystem))] - [RegisterComponent, NetworkedComponent] public sealed partial class StandingStateComponent : Component { [ViewVariables(VVAccess.ReadWrite)] - [DataField("downSound")] + [DataField] public SoundSpecifier DownSound { get; private set; } = new SoundCollectionSpecifier("BodyFall"); - [DataField("standing")] + [DataField, AutoNetworkedField] public bool Standing { get; set; } = true; /// /// List of fixtures that had their collision mask changed when the entity was downed. /// Required for re-adding the collision mask. /// - [DataField("changedFixtures")] + [DataField, AutoNetworkedField(true)] public List ChangedFixtures = new(); } } diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs index 2716ed02df2..bb74a088b3e 100644 --- a/Content.Shared/Standing/StandingStateSystem.cs +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -2,10 +2,8 @@ using Content.Shared.Physics; using Content.Shared.Rotation; using Robust.Shared.Audio; -using Robust.Shared.GameStates; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; -using Robust.Shared.Serialization; namespace Content.Shared.Standing { @@ -18,26 +16,6 @@ public sealed class StandingStateSystem : EntitySystem // If StandingCollisionLayer value is ever changed to more than one layer, the logic needs to be edited. private const int StandingCollisionLayer = (int) CollisionGroup.MidImpassable; - public override void Initialize() - { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnHandleState(EntityUid uid, StandingStateComponent component, ref ComponentHandleState args) - { - if (args.Current is not StandingComponentState state) - return; - - component.Standing = state.Standing; - component.ChangedFixtures = new List(state.ChangedFixtures); - } - - private void OnGetState(EntityUid uid, StandingStateComponent component, ref ComponentGetState args) - { - args.State = new StandingComponentState(component.Standing, component.ChangedFixtures); - } - public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null) { if (!Resolve(uid, ref standingState, false)) @@ -151,20 +129,6 @@ public bool Stand(EntityUid uid, return true; } - - // I'm not calling it StandingStateComponentState - [Serializable, NetSerializable] - private sealed class StandingComponentState : ComponentState - { - public bool Standing { get; } - public List ChangedFixtures { get; } - - public StandingComponentState(bool standing, List changedFixtures) - { - Standing = standing; - ChangedFixtures = changedFixtures; - } - } } public sealed class DropHandItemsEvent : EventArgs diff --git a/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs b/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs index 21cf5397a1f..c4457179a97 100644 --- a/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs +++ b/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs @@ -1,58 +1,56 @@ using Content.Shared.StepTrigger.Systems; using Content.Shared.Whitelist; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.StepTrigger.Components; -[RegisterComponent] -[NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] [Access(typeof(StepTriggerSystem))] public sealed partial class StepTriggerComponent : Component { /// /// List of entities that are currently colliding with the entity. /// - [ViewVariables] - public readonly HashSet Colliding = new(); + [ViewVariables, AutoNetworkedField(true)] + public HashSet Colliding = new(); /// /// The list of entities that are standing on this entity, /// which shouldn't be able to trigger it again until stepping off. /// - [ViewVariables] - public readonly HashSet CurrentlySteppedOn = new(); + [ViewVariables, AutoNetworkedField(true)] + public HashSet CurrentlySteppedOn = new(); /// /// Whether or not this component will currently try to trigger for entities. /// - [DataField("active")] + [DataField, AutoNetworkedField] public bool Active = true; /// /// Ratio of shape intersection for a trigger to occur. /// - [DataField("intersectRatio")] + [DataField, AutoNetworkedField] public float IntersectRatio = 0.3f; /// /// Entities will only be triggered if their speed exceeds this limit. /// - [DataField("requiredTriggeredSpeed")] - public float RequiredTriggerSpeed = 3.5f; + [DataField, AutoNetworkedField] + public float RequiredTriggeredSpeed = 3.5f; /// /// If any entities occupy the blacklist on the same tile then steptrigger won't work. /// - [DataField("blacklist")] + [DataField] public EntityWhitelist? Blacklist; /// /// If this is true, steptrigger will still occur on entities that are in air / weightless. They do not /// by default. /// - [DataField("ignoreWeightless")] - public bool IgnoreWeightless = false; + [DataField] + public bool IgnoreWeightless; } [RegisterComponent] @@ -61,23 +59,3 @@ public sealed partial class StepTriggerActiveComponent : Component { } - -[Serializable, NetSerializable] -public sealed class StepTriggerComponentState : ComponentState -{ - public float IntersectRatio { get; } - public float RequiredTriggerSpeed { get; } - public readonly HashSet CurrentlySteppedOn; - public readonly HashSet Colliding; - public readonly bool Active; - - public StepTriggerComponentState(float intersectRatio, HashSet currentlySteppedOn, HashSet colliding, float requiredTriggerSpeed, bool active) - { - IntersectRatio = intersectRatio; - CurrentlySteppedOn = currentlySteppedOn; - RequiredTriggerSpeed = requiredTriggerSpeed; - Active = active; - Colliding = colliding; - } -} - diff --git a/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs b/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs index 335d9bea9f4..ede39b2aa97 100644 --- a/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs +++ b/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Gravity; using Content.Shared.StepTrigger.Components; -using Robust.Shared.GameStates; using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; @@ -16,8 +15,7 @@ public sealed class StepTriggerSystem : EntitySystem public override void Initialize() { UpdatesOutsidePrediction = true; - SubscribeLocalEvent(TriggerGetState); - SubscribeLocalEvent(TriggerHandleState); + SubscribeLocalEvent(TriggerHandleState); SubscribeLocalEvent(OnStartCollide); SubscribeLocalEvent(OnEndCollide); @@ -103,7 +101,7 @@ private void UpdateColliding(EntityUid uid, StepTriggerComponent component, Tran // this is hard to explain var intersect = Box2.Area(otherAabb.Intersect(ourAabb)); var ratio = Math.Max(intersect / Box2.Area(otherAabb), intersect / Box2.Area(ourAabb)); - if (otherPhysics.LinearVelocity.Length() < component.RequiredTriggerSpeed + if (otherPhysics.LinearVelocity.Length() < component.RequiredTriggeredSpeed || component.CurrentlySteppedOn.Contains(otherUid) || ratio < component.IntersectRatio || !CanTrigger(uid, otherUid, component)) @@ -171,24 +169,8 @@ private void OnEndCollide(EntityUid uid, StepTriggerComponent component, ref End } } - - private void TriggerHandleState(EntityUid uid, StepTriggerComponent component, ref ComponentHandleState args) + private void TriggerHandleState(EntityUid uid, StepTriggerComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not StepTriggerComponentState state) - return; - - component.RequiredTriggerSpeed = state.RequiredTriggerSpeed; - component.IntersectRatio = state.IntersectRatio; - component.Active = state.Active; - var stepped = EnsureEntitySet(state.CurrentlySteppedOn, uid); - var colliding = EnsureEntitySet(state.CurrentlySteppedOn, uid); - - component.CurrentlySteppedOn.Clear(); - component.CurrentlySteppedOn.UnionWith(stepped); - - component.Colliding.Clear(); - component.Colliding.UnionWith(colliding); - if (component.Colliding.Count > 0) { EnsureComp(uid); @@ -199,16 +181,6 @@ private void TriggerHandleState(EntityUid uid, StepTriggerComponent component, r } } - private void TriggerGetState(EntityUid uid, StepTriggerComponent component, ref ComponentGetState args) - { - args.State = new StepTriggerComponentState( - component.IntersectRatio, - GetNetEntitySet(component.CurrentlySteppedOn), - GetNetEntitySet(component.Colliding), - component.RequiredTriggerSpeed, - component.Active); - } - public void SetIntersectRatio(EntityUid uid, float ratio, StepTriggerComponent? component = null) { if (!Resolve(uid, ref component)) @@ -226,10 +198,10 @@ public void SetRequiredTriggerSpeed(EntityUid uid, float speed, StepTriggerCompo if (!Resolve(uid, ref component)) return; - if (MathHelper.CloseToPercent(component.RequiredTriggerSpeed, speed)) + if (MathHelper.CloseToPercent(component.RequiredTriggeredSpeed, speed)) return; - component.RequiredTriggerSpeed = speed; + component.RequiredTriggeredSpeed = speed; Dirty(uid, component); } diff --git a/Content.Shared/Storage/Components/BinComponent.cs b/Content.Shared/Storage/Components/BinComponent.cs index 4294ce1e790..99e2a9844a4 100644 --- a/Content.Shared/Storage/Components/BinComponent.cs +++ b/Content.Shared/Storage/Components/BinComponent.cs @@ -3,8 +3,6 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Storage.Components; @@ -12,7 +10,8 @@ namespace Content.Shared.Storage.Components; /// This is used for things like paper bins, in which /// you can only take off of the top of the bin. /// -[RegisterComponent, NetworkedComponent, Access(typeof(BinSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(BinSystem))] public sealed partial class BinComponent : Component { /// @@ -30,42 +29,25 @@ public sealed partial class BinComponent : Component /// i can handle entities being deleted and removed /// out of order by other systems /// - [DataField("items")] + [DataField, AutoNetworkedField] public List Items = new(); /// /// The items that start in the bin. Sorted in order. /// - [DataField("initialContents", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List InitialContents = new(); + [DataField] + public List InitialContents = new(); /// /// A whitelist governing what items can be inserted into the bin. /// - [DataField("whitelist")] + [DataField, AutoNetworkedField] public EntityWhitelist? Whitelist; /// /// The maximum amount of items /// that can be stored in the bin. /// - [DataField("maxItems")] + [DataField, AutoNetworkedField] public int MaxItems = 20; } - -[Serializable, NetSerializable] -public sealed class BinComponentState : ComponentState -{ - public List Items; - - public EntityWhitelist? Whitelist; - - public int MaxItems; - - public BinComponentState(List items, EntityWhitelist? whitelist, int maxItems) - { - Items = items; - Whitelist = whitelist; - MaxItems = maxItems; - } -} diff --git a/Content.Shared/Storage/EntitySystems/BinSystem.cs b/Content.Shared/Storage/EntitySystems/BinSystem.cs index e82861f4e15..86726587f01 100644 --- a/Content.Shared/Storage/EntitySystems/BinSystem.cs +++ b/Content.Shared/Storage/EntitySystems/BinSystem.cs @@ -5,7 +5,6 @@ using Content.Shared.Interaction; using Content.Shared.Storage.Components; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Network; using Robust.Shared.Timing; @@ -27,8 +26,6 @@ public sealed class BinSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnEntRemoved); @@ -36,21 +33,6 @@ public override void Initialize() SubscribeLocalEvent(OnAfterInteractUsing); } - private void OnGetState(EntityUid uid, BinComponent component, ref ComponentGetState args) - { - args.State = new BinComponentState(GetNetEntityList(component.Items), component.Whitelist, component.MaxItems); - } - - private void OnHandleState(EntityUid uid, BinComponent component, ref ComponentHandleState args) - { - if (args.Current is not BinComponentState state) - return; - - component.Items = EnsureEntityList(state.Items, uid); - component.Whitelist = state.Whitelist; - component.MaxItems = state.MaxItems; - } - private void OnStartup(EntityUid uid, BinComponent component, ComponentStartup args) { component.ItemContainer = _container.EnsureContainer(uid, BinContainerId); diff --git a/Content.Shared/Tabletop/Components/TabletopDraggableComponent.cs b/Content.Shared/Tabletop/Components/TabletopDraggableComponent.cs index e1aa281d17d..eb8ab36243c 100644 --- a/Content.Shared/Tabletop/Components/TabletopDraggableComponent.cs +++ b/Content.Shared/Tabletop/Components/TabletopDraggableComponent.cs @@ -6,11 +6,10 @@ namespace Content.Shared.Tabletop.Components; /// /// Allows an entity to be dragged around by the mouse. The position is updated for all player while dragging. /// -[NetworkedComponent] -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class TabletopDraggableComponent : Component { // The player dragging the piece - [ViewVariables] + [ViewVariables, AutoNetworkedField] public NetUserId? DraggingPlayer; } diff --git a/Content.Shared/Tabletop/SharedTabletopSystem.cs b/Content.Shared/Tabletop/SharedTabletopSystem.cs index 1ff90303411..7bfd9d34572 100644 --- a/Content.Shared/Tabletop/SharedTabletopSystem.cs +++ b/Content.Shared/Tabletop/SharedTabletopSystem.cs @@ -5,7 +5,6 @@ using Content.Shared.Interaction; using Content.Shared.Tabletop.Components; using Content.Shared.Tabletop.Events; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Serialization; @@ -22,7 +21,6 @@ public abstract class SharedTabletopSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(GetDraggableState); SubscribeAllEvent(OnDraggingPlayerChanged); SubscribeAllEvent(OnTabletopMove); } @@ -47,11 +45,6 @@ protected virtual void OnTabletopMove(TabletopMoveEvent msg, EntitySessionEventA _transforms.SetLocalPositionNoLerp(transform, msg.Coordinates.Position); } - private void GetDraggableState(EntityUid uid, TabletopDraggableComponent component, ref ComponentGetState args) - { - args.State = new TabletopDraggableComponentState(component.DraggingPlayer); - } - private void OnDraggingPlayerChanged(TabletopDraggingPlayerChangedEvent msg, EntitySessionEventArgs args) { var dragged = GetEntity(msg.DraggedEntityUid); diff --git a/Content.Shared/Teleportation/Components/LinkedEntityComponent.cs b/Content.Shared/Teleportation/Components/LinkedEntityComponent.cs index ae9a1a03d0d..f9ad509d1fe 100644 --- a/Content.Shared/Teleportation/Components/LinkedEntityComponent.cs +++ b/Content.Shared/Teleportation/Components/LinkedEntityComponent.cs @@ -8,31 +8,21 @@ namespace Content.Shared.Teleportation.Components; /// Represents an entity which is linked to other entities (perhaps portals), and which can be walked through/ /// thrown into to teleport an entity. /// -[RegisterComponent, Access(typeof(LinkedEntitySystem)), NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(LinkedEntitySystem))] public sealed partial class LinkedEntityComponent : Component { /// /// The entities that this entity is linked to. /// - [DataField("linkedEntities")] + [DataField, AutoNetworkedField] public HashSet LinkedEntities = new(); /// /// Should this entity be deleted if all of its links are removed? /// - [DataField("deleteOnEmptyLinks")] - public bool DeleteOnEmptyLinks = false; -} - -[Serializable, NetSerializable] -public sealed class LinkedEntityComponentState : ComponentState -{ - public HashSet LinkedEntities; - - public LinkedEntityComponentState(HashSet linkedEntities) - { - LinkedEntities = linkedEntities; - } + [DataField] + public bool DeleteOnEmptyLinks; } [Serializable, NetSerializable] diff --git a/Content.Shared/Teleportation/Components/PortalTimeoutComponent.cs b/Content.Shared/Teleportation/Components/PortalTimeoutComponent.cs index 37441508e11..341c68d7c86 100644 --- a/Content.Shared/Teleportation/Components/PortalTimeoutComponent.cs +++ b/Content.Shared/Teleportation/Components/PortalTimeoutComponent.cs @@ -1,5 +1,4 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Teleportation.Components; @@ -7,23 +6,12 @@ namespace Content.Shared.Teleportation.Components; /// Attached to an entity after portal transit to mark that they should not immediately be portaled back /// at the end destination. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class PortalTimeoutComponent : Component { /// /// The portal that was entered. Null if coming from a hand teleporter, etc. /// - [ViewVariables, DataField("enteredPortal")] - public EntityUid? EnteredPortal = null; -} - -[Serializable, NetSerializable] -public sealed class PortalTimeoutComponentState : ComponentState -{ - public NetEntity? EnteredPortal; - - public PortalTimeoutComponentState(NetEntity? enteredPortal) - { - EnteredPortal = enteredPortal; - } + [ViewVariables, DataField, AutoNetworkedField] + public EntityUid? EnteredPortal; } diff --git a/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs b/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs index 73e686e8bdc..ed979754527 100644 --- a/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs +++ b/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs @@ -1,7 +1,6 @@ -using Content.Shared.Teleportation.Components; -using Robust.Shared.GameStates; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Content.Shared.Teleportation.Components; namespace Content.Shared.Teleportation.Systems; @@ -20,22 +19,6 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnLinkShutdown); - - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - private void OnGetState(EntityUid uid, LinkedEntityComponent component, ref ComponentGetState args) - { - args.State = new LinkedEntityComponentState(GetNetEntitySet(component.LinkedEntities)); - } - - private void OnHandleState(EntityUid uid, LinkedEntityComponent component, ref ComponentHandleState args) - { - if (args.Current is LinkedEntityComponentState state) - { - component.LinkedEntities = EnsureEntitySet(state.LinkedEntities, uid); - } } private void OnLinkShutdown(EntityUid uid, LinkedEntityComponent component, ComponentShutdown args) diff --git a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs index 1ecaca57c3c..e614a2c040f 100644 --- a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs +++ b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs @@ -1,13 +1,11 @@ using System.Linq; using Content.Shared.Ghost; -using Content.Shared.Pinpointer; using Content.Shared.Popups; using Content.Shared.Projectiles; using Content.Shared.Pulling; using Content.Shared.Pulling.Components; using Content.Shared.Teleportation.Components; using Content.Shared.Verbs; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Physics.Dynamics; @@ -42,9 +40,6 @@ public override void Initialize() SubscribeLocalEvent(OnCollide); SubscribeLocalEvent(OnEndCollide); SubscribeLocalEvent>(OnGetVerbs); - - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); } private void OnGetVerbs(EntityUid uid, PortalComponent component, GetVerbsEvent args) @@ -77,17 +72,6 @@ private void OnGetVerbs(EntityUid uid, PortalComponent component, GetVerbsEvent< }); } - private void OnGetState(EntityUid uid, PortalTimeoutComponent component, ref ComponentGetState args) - { - args.State = new PortalTimeoutComponentState(GetNetEntity(component.EnteredPortal)); - } - - private void OnHandleState(EntityUid uid, PortalTimeoutComponent component, ref ComponentHandleState args) - { - if (args.Current is PortalTimeoutComponentState state) - component.EnteredPortal = EnsureEntity(state.EnteredPortal, uid); - } - private bool ShouldCollide(string ourId, string otherId, Fixture our, Fixture other) { // most non-hard fixtures shouldn't pass through portals, but projectiles are non-hard as well diff --git a/Content.Shared/Timing/UseDelayComponent.cs b/Content.Shared/Timing/UseDelayComponent.cs index aa12f04847a..4135bf26fe1 100644 --- a/Content.Shared/Timing/UseDelayComponent.cs +++ b/Content.Shared/Timing/UseDelayComponent.cs @@ -1,45 +1,28 @@ -using System.Threading; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; -namespace Content.Shared.Timing -{ - /// - /// Timer that creates a cooldown each time an object is activated/used - /// - [RegisterComponent] - [NetworkedComponent] - public sealed partial class UseDelayComponent : Component - { - public TimeSpan LastUseTime; - - public TimeSpan? DelayEndTime; +namespace Content.Shared.Timing; - [DataField("delay")] - [ViewVariables(VVAccess.ReadWrite)] - public TimeSpan Delay = TimeSpan.FromSeconds(1); +/// +/// Timer that creates a cooldown each time an object is activated/used +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class UseDelayComponent : Component +{ + [AutoNetworkedField] + public TimeSpan LastUseTime; - /// - /// Stores remaining delay pausing (and eventually, serialization). - /// - [DataField("remainingDelay")] - public TimeSpan? RemainingDelay; + [AutoNetworkedField] + public TimeSpan? DelayEndTime; - public bool ActiveDelay => DelayEndTime != null; - } + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] + public TimeSpan Delay = TimeSpan.FromSeconds(1); - [Serializable, NetSerializable] - public sealed class UseDelayComponentState : ComponentState - { - public readonly TimeSpan LastUseTime; - public readonly TimeSpan Delay; - public readonly TimeSpan? DelayEndTime; + /// + /// Stores remaining delay pausing (and eventually, serialization). + /// + [DataField] + public TimeSpan? RemainingDelay; - public UseDelayComponentState(TimeSpan lastUseTime, TimeSpan delay, TimeSpan? delayEndTime) - { - LastUseTime = lastUseTime; - Delay = delay; - DelayEndTime = delayEndTime; - } - } + public bool ActiveDelay => DelayEndTime != null; } diff --git a/Content.Shared/Timing/UseDelaySystem.cs b/Content.Shared/Timing/UseDelaySystem.cs index f6dcdafe41d..1d1d636b89f 100644 --- a/Content.Shared/Timing/UseDelaySystem.cs +++ b/Content.Shared/Timing/UseDelaySystem.cs @@ -1,6 +1,4 @@ -using System.Threading; using Content.Shared.Cooldown; -using Robust.Shared.GameStates; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -16,8 +14,7 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnPaused); SubscribeLocalEvent(OnUnpaused); @@ -45,26 +42,14 @@ private void OnUnpaused(EntityUid uid, UseDelayComponent component, ref EntityUn _activeDelays.Add(component); } - private void OnHandleState(EntityUid uid, UseDelayComponent component, ref ComponentHandleState args) + private void OnHandleState(EntityUid uid, UseDelayComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not UseDelayComponentState state) - return; - - component.LastUseTime = state.LastUseTime; - component.Delay = state.Delay; - component.DelayEndTime = state.DelayEndTime; - if (component.DelayEndTime == null) _activeDelays.Remove(component); else _activeDelays.Add(component); } - private void OnGetState(EntityUid uid, UseDelayComponent component, ref ComponentGetState args) - { - args.State = new UseDelayComponentState(component.LastUseTime, component.Delay, component.DelayEndTime); - } - public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Shared/Tools/Components/MultipleToolComponent.cs b/Content.Shared/Tools/Components/MultipleToolComponent.cs index 87fa4ad1750..4e30abb5ad8 100644 --- a/Content.Shared/Tools/Components/MultipleToolComponent.cs +++ b/Content.Shared/Tools/Components/MultipleToolComponent.cs @@ -1,53 +1,41 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; using Robust.Shared.Utility; -namespace Content.Shared.Tools.Components +namespace Content.Shared.Tools.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class MultipleToolComponent : Component { - [RegisterComponent, NetworkedComponent] - public sealed partial class MultipleToolComponent : Component + [DataDefinition] + public sealed partial class ToolEntry { - [DataDefinition] - public sealed partial class ToolEntry - { - [DataField("behavior", required: true)] - public PrototypeFlags Behavior = new(); - - [DataField("useSound")] - public SoundSpecifier? Sound; + [DataField(required: true)] + public PrototypeFlags Behavior = new(); - [DataField("changeSound")] - public SoundSpecifier? ChangeSound; + [DataField] + public SoundSpecifier? UseSound; - [DataField("sprite")] - public SpriteSpecifier? Sprite; - } + [DataField] + public SoundSpecifier? ChangeSound; - [DataField("entries", required: true)] - public ToolEntry[] Entries { get; private set; } = Array.Empty(); + [DataField] + public SpriteSpecifier? Sprite; + } - [ViewVariables] - public uint CurrentEntry = 0; + [DataField(required: true)] + public ToolEntry[] Entries { get; private set; } = Array.Empty(); - [ViewVariables] - public string CurrentQualityName = string.Empty; + [ViewVariables] + [AutoNetworkedField] + public uint CurrentEntry = 0; - [ViewVariables(VVAccess.ReadWrite)] - public bool UiUpdateNeeded; + [ViewVariables] + public string CurrentQualityName = string.Empty; - [DataField("statusShowBehavior")] - public bool StatusShowBehavior = true; - } + [ViewVariables(VVAccess.ReadWrite)] + public bool UiUpdateNeeded; - [NetSerializable, Serializable] - public sealed class MultipleToolComponentState : ComponentState - { - public readonly uint Selected; - - public MultipleToolComponentState(uint selected) - { - Selected = selected; - } - } + [DataField] + public bool StatusShowBehavior = true; } diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs b/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs index d528c1be7dd..39a1dc50f32 100644 --- a/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs +++ b/Content.Shared/Tools/Systems/SharedToolSystem.MultipleTool.cs @@ -1,7 +1,6 @@ using System.Linq; using Content.Shared.Interaction; using Content.Shared.Tools.Components; -using Robust.Shared.GameStates; using Content.Shared.Prying.Components; namespace Content.Shared.Tools; @@ -12,16 +11,11 @@ public void InitializeMultipleTool() { SubscribeLocalEvent(OnMultipleToolStartup); SubscribeLocalEvent(OnMultipleToolActivated); - SubscribeLocalEvent(OnMultipleToolGetState); - SubscribeLocalEvent(OnMultipleToolHandleState); + SubscribeLocalEvent(OnMultipleToolHandleState); } - private void OnMultipleToolHandleState(EntityUid uid, MultipleToolComponent component, ref ComponentHandleState args) + private void OnMultipleToolHandleState(EntityUid uid, MultipleToolComponent component, ref AfterAutoHandleStateEvent args) { - if (args.Current is not MultipleToolComponentState state) - return; - - component.CurrentEntry = state.Selected; SetMultipleTool(uid, component); } @@ -40,11 +34,6 @@ private void OnMultipleToolActivated(EntityUid uid, MultipleToolComponent multip args.Handled = CycleMultipleTool(uid, multiple, args.User); } - private void OnMultipleToolGetState(EntityUid uid, MultipleToolComponent multiple, ref ComponentGetState args) - { - args.State = new MultipleToolComponentState(multiple.CurrentEntry); - } - public bool CycleMultipleTool(EntityUid uid, MultipleToolComponent? multiple = null, EntityUid? user = null) { if (!Resolve(uid, ref multiple)) @@ -77,7 +66,7 @@ public virtual void SetMultipleTool(EntityUid uid, } var current = multiple.Entries[multiple.CurrentEntry]; - tool.UseSound = current.Sound; + tool.UseSound = current.UseSound; tool.Qualities = current.Behavior; // TODO: Replace this with a better solution later diff --git a/Content.Shared/Vehicle/SharedVehicleSystem.cs b/Content.Shared/Vehicle/SharedVehicleSystem.cs index 9ba22d644a4..334c115ba8d 100644 --- a/Content.Shared/Vehicle/SharedVehicleSystem.cs +++ b/Content.Shared/Vehicle/SharedVehicleSystem.cs @@ -91,8 +91,8 @@ private void OnVehicleStartup(EntityUid uid, VehicleComponent component, Compone // This code should be purged anyway but with that being said this doesn't handle components being changed. if (TryComp(uid, out var strap)) { - component.BaseBuckleOffset = strap.BuckleOffset; - strap.BuckleOffsetUnclamped = Vector2.Zero; + component.BaseBuckleOffset = strap.BuckleOffsetClamped; + strap.BuckleOffset = Vector2.Zero; } _modifier.RefreshMovementSpeedModifiers(uid); @@ -301,9 +301,9 @@ private void UpdateBuckleOffset(EntityUid uid, TransformComponent xform, Vehicle return; // TODO: Strap should handle this but buckle E/C moment. - var oldOffset = strap.BuckleOffsetUnclamped; + var oldOffset = strap.BuckleOffset; - strap.BuckleOffsetUnclamped = xform.LocalRotation.Degrees switch + strap.BuckleOffset = xform.LocalRotation.Degrees switch { < 45f => new(0, component.SouthOverride), <= 135f => component.BaseBuckleOffset, @@ -312,13 +312,13 @@ private void UpdateBuckleOffset(EntityUid uid, TransformComponent xform, Vehicle _ => new(0, component.SouthOverride) }; - if (!oldOffset.Equals(strap.BuckleOffsetUnclamped)) + if (!oldOffset.Equals(strap.BuckleOffset)) Dirty(strap); foreach (var buckledEntity in strap.BuckledEntities) { var buckleXform = Transform(buckledEntity); - _transform.SetLocalPositionNoLerp(buckleXform, strap.BuckleOffset); + _transform.SetLocalPositionNoLerp(buckleXform, strap.BuckleOffsetClamped); } } diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index 9e7ad7e3a79..ddc060e558b 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -3,16 +3,14 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Weapons.Melee; /// /// When given to a mob lets them do unarmed attacks, or when given to an item lets someone wield it to do attacks. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MeleeWeaponComponent : Component { // TODO: This is becoming bloated as shit. @@ -20,26 +18,27 @@ public sealed partial class MeleeWeaponComponent : Component /// /// Does this entity do a disarm on alt attack. /// - [DataField("altDisarm"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool AltDisarm = true; /// /// Should the melee weapon's damage stats be examinable. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("hidden")] - public bool HideFromExamine; + [DataField] + public bool Hidden; /// /// Next time this component is allowed to light attack. Heavy attacks are wound up and never have a cooldown. /// - [ViewVariables(VVAccess.ReadWrite), DataField("nextAttack", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] public TimeSpan NextAttack; /// /// Starts attack cooldown when equipped if true. /// - [ViewVariables(VVAccess.ReadWrite), DataField("resetOnHandSelected")] + [ViewVariables(VVAccess.ReadWrite), DataField] public bool ResetOnHandSelected = true; /* @@ -51,50 +50,51 @@ public sealed partial class MeleeWeaponComponent : Component /// /// How many times we can attack per second. /// - [ViewVariables(VVAccess.ReadWrite), DataField("attackRate")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float AttackRate = 1f; /// /// Are we currently holding down the mouse for an attack. /// Used so we can't just hold the mouse button and attack constantly. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool Attacking = false; /// /// Base damage for this weapon. Can be modified via heavy damage or other means. /// - [DataField("damage", required:true)] + [DataField(required:true)] [ViewVariables(VVAccess.ReadWrite)] public DamageSpecifier Damage = default!; - [DataField("bluntStaminaDamageFactor")] [ViewVariables(VVAccess.ReadWrite)] + [DataField] + [ViewVariables(VVAccess.ReadWrite)] public FixedPoint2 BluntStaminaDamageFactor = FixedPoint2.New(0.5f); /// /// Multiplies damage by this amount for single-target attacks. /// - [ViewVariables(VVAccess.ReadWrite), DataField("clickDamageModifier")] + [ViewVariables(VVAccess.ReadWrite), DataField] public FixedPoint2 ClickDamageModifier = FixedPoint2.New(1); // TODO: Temporarily 1.5 until interactionoutline is adjusted to use melee, then probably drop to 1.2 /// /// Nearest edge range to hit an entity. /// - [ViewVariables(VVAccess.ReadWrite), DataField("range")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float Range = 1.5f; /// /// Total width of the angle for wide attacks. /// - [ViewVariables(VVAccess.ReadWrite), DataField("angle")] + [ViewVariables(VVAccess.ReadWrite), DataField] public Angle Angle = Angle.FromDegrees(60); - [ViewVariables(VVAccess.ReadWrite), DataField("animation", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ClickAnimation = "WeaponArcPunch"; + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public EntProtoId Animation = "WeaponArcPunch"; - [ViewVariables(VVAccess.ReadWrite), DataField("wideAnimation", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string WideAnimation = "WeaponArcSlash"; + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public EntProtoId WideAnimation = "WeaponArcSlash"; // Sounds @@ -132,27 +132,3 @@ public sealed class GetMeleeWeaponEvent : HandledEntityEventArgs { public EntityUid? Weapon; } - -[Serializable, NetSerializable] -public sealed class MeleeWeaponComponentState : ComponentState -{ - // None of the other data matters for client as they're not predicted. - - public float AttackRate; - public bool Attacking; - public TimeSpan NextAttack; - - public string ClickAnimation; - public string WideAnimation; - public float Range; - - public MeleeWeaponComponentState(float attackRate, bool attacking, TimeSpan nextAttack, string clickAnimation, string wideAnimation, float range) - { - AttackRate = attackRate; - Attacking = attacking; - NextAttack = nextAttack; - ClickAnimation = clickAnimation; - WideAnimation = wideAnimation; - Range = range; - } -} diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 08ecea43263..9b61fd03b7d 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -20,7 +20,6 @@ using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Systems; using Robust.Shared.Audio; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; @@ -65,8 +64,6 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnMeleeUnpaused); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnMeleeSelected); SubscribeLocalEvent(OnMeleeShotAttempted); SubscribeLocalEvent(OnMeleeShot); @@ -223,25 +220,6 @@ private void OnDisarmAttack(DisarmAttackEvent msg, EntitySessionEventArgs args) AttemptAttack(args.SenderSession.AttachedEntity.Value, weaponUid, weapon, msg, args.SenderSession); } - private void OnGetState(EntityUid uid, MeleeWeaponComponent component, ref ComponentGetState args) - { - args.State = new MeleeWeaponComponentState(component.AttackRate, component.Attacking, component.NextAttack, component.ClickAnimation, component.WideAnimation, component.Range); - } - - private void OnHandleState(EntityUid uid, MeleeWeaponComponent component, ref ComponentHandleState args) - { - if (args.Current is not MeleeWeaponComponentState state) - return; - - component.Attacking = state.Attacking; - component.AttackRate = state.AttackRate; - component.NextAttack = state.NextAttack; - - component.ClickAnimation = state.ClickAnimation; - component.WideAnimation = state.WideAnimation; - component.Range = state.Range; - } - /// /// Gets the total damage a weapon does, including modifiers like wielding and enablind/disabling /// @@ -427,13 +405,13 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo { case LightAttackEvent light: DoLightAttack(user, light, weaponUid, weapon, session); - animation = weapon.ClickAnimation; + animation = weapon.Animation; break; case DisarmAttackEvent disarm: if (!DoDisarm(user, disarm, weaponUid, weapon, session)) return false; - animation = weapon.ClickAnimation; + animation = weapon.Animation; break; case HeavyAttackEvent heavy: if (!DoHeavyAttack(user, heavy, weaponUid, weapon, session)) diff --git a/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs b/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs index 8d0f6a52838..eb04d3227db 100644 --- a/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs @@ -3,37 +3,36 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Weapons.Ranged.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class BallisticAmmoProviderComponent : Component { - [ViewVariables(VVAccess.ReadWrite), DataField("soundRack")] + [ViewVariables(VVAccess.ReadWrite), DataField] public SoundSpecifier? SoundRack = new SoundPathSpecifier("/Audio/Weapons/Guns/Cock/smg_cock.ogg"); - [ViewVariables(VVAccess.ReadWrite), DataField("soundInsert")] + [ViewVariables(VVAccess.ReadWrite), DataField] public SoundSpecifier? SoundInsert = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/bullet_insert.ogg"); - [ViewVariables(VVAccess.ReadWrite), DataField("proto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? FillProto; + [ViewVariables(VVAccess.ReadWrite), DataField] + public EntProtoId? Proto; - [ViewVariables(VVAccess.ReadWrite), DataField("capacity")] + [ViewVariables(VVAccess.ReadWrite), DataField] public int Capacity = 30; public int Count => UnspawnedCount + Container.ContainedEntities.Count; - [ViewVariables(VVAccess.ReadWrite), DataField("unspawnedCount")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public int UnspawnedCount; - [ViewVariables(VVAccess.ReadWrite), DataField("whitelist")] + [ViewVariables(VVAccess.ReadWrite), DataField] public EntityWhitelist? Whitelist; public Container Container = default!; // TODO: Make this use stacks when the typeserializer is done. - [DataField("entities")] + [DataField, AutoNetworkedField] public List Entities = new(); /// @@ -42,18 +41,18 @@ public sealed partial class BallisticAmmoProviderComponent : Component /// /// Set to false for entities like turrets to avoid users being able to cycle them. /// - [ViewVariables(VVAccess.ReadWrite), DataField("cycleable")] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public bool Cycleable = true; /// /// Is it okay for this entity to directly transfer its valid ammunition into another provider? /// - [ViewVariables(VVAccess.ReadWrite), DataField("mayTransfer")] - public bool MayTransfer = false; + [ViewVariables(VVAccess.ReadWrite), DataField] + public bool MayTransfer; /// /// DoAfter delay for filling a bullet into another ballistic ammo provider. /// - [DataField("fillDelay")] + [DataField] public TimeSpan FillDelay = TimeSpan.FromSeconds(0.5); } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index f8b2394315c..8ad96fda531 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -6,7 +6,6 @@ using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Serialization; @@ -29,29 +28,6 @@ protected virtual void InitializeBallistic() SubscribeLocalEvent(OnBallisticAfterInteract); SubscribeLocalEvent(OnBallisticAmmoFillDoAfter); SubscribeLocalEvent(OnBallisticUse); - - SubscribeLocalEvent(OnBallisticGetState); - SubscribeLocalEvent(OnBallisticHandleState); - } - - private void OnBallisticGetState(EntityUid uid, BallisticAmmoProviderComponent component, ref ComponentGetState args) - { - args.State = new BallisticAmmoProviderComponentState() - { - UnspawnedCount = component.UnspawnedCount, - Cycleable = component.Cycleable, - Entities = GetNetEntityList(component.Entities), - }; - } - - private void OnBallisticHandleState(EntityUid uid, BallisticAmmoProviderComponent component, ref ComponentHandleState args) - { - if (args.Current is not BallisticAmmoProviderComponentState state) - return; - - component.UnspawnedCount = state.UnspawnedCount; - component.Cycleable = state.Cycleable; - component.Entities = EnsureEntityList(state.Entities, uid); } private void OnBallisticUse(EntityUid uid, BallisticAmmoProviderComponent component, UseInHandEvent args) @@ -239,7 +215,7 @@ private void OnBallisticMapInit(EntityUid uid, BallisticAmmoProviderComponent co { // TODO this should be part of the prototype, not set on map init. // Alternatively, just track spawned count, instead of unspawned count. - if (component.FillProto != null) + if (component.Proto != null) { component.UnspawnedCount = Math.Max(0, component.Capacity - component.Container.ContainedEntities.Count); UpdateBallisticAppearance(uid, component); @@ -269,7 +245,7 @@ private void OnBallisticTakeAmmo(EntityUid uid, BallisticAmmoProviderComponent c else if (component.UnspawnedCount > 0) { component.UnspawnedCount--; - entity = Spawn(component.FillProto, args.Coordinates); + entity = Spawn(component.Proto, args.Coordinates); args.Ammo.Add((entity, EnsureShootable(entity))); } } @@ -292,14 +268,6 @@ private void UpdateBallisticAppearance(EntityUid uid, BallisticAmmoProviderCompo Appearance.SetData(uid, AmmoVisuals.AmmoCount, GetBallisticShots(component), appearance); Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity, appearance); } - - [Serializable, NetSerializable] - private sealed class BallisticAmmoProviderComponentState : ComponentState - { - public int UnspawnedCount; - public List Entities = new(); - public bool Cycleable = true; - } } /// diff --git a/Content.Shared/Zombies/ZombieComponent.cs b/Content.Shared/Zombies/ZombieComponent.cs index f03a0baf79f..bb1f6bec5f1 100644 --- a/Content.Shared/Zombies/ZombieComponent.cs +++ b/Content.Shared/Zombies/ZombieComponent.cs @@ -1,15 +1,14 @@ using Content.Shared.Chat.Prototypes; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; -using Content.Shared.Roles; using Content.Shared.Humanoid; +using Content.Shared.Roles; using Content.Shared.StatusIcon; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using static Content.Shared.Humanoid.HumanoidAppearanceState; namespace Content.Shared.Zombies; diff --git a/Content.Tests/Shared/Alert/ServerAlertsComponentTests.cs b/Content.Tests/Shared/Alert/ServerAlertsComponentTests.cs index 83fbb009ead..5d8d49d168c 100644 --- a/Content.Tests/Shared/Alert/ServerAlertsComponentTests.cs +++ b/Content.Tests/Shared/Alert/ServerAlertsComponentTests.cs @@ -57,7 +57,7 @@ public void ShowAlerts() var getty = new ComponentGetState(); entManager.EventBus.RaiseComponentEvent(alertsComponent, getty); - var alertState = (AlertsComponentState) getty.State!; + var alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!; Assert.NotNull(alertState); Assert.That(alertState.Alerts.Count, Is.EqualTo(1)); Assert.That(alertState.Alerts.ContainsKey(lowpressure.AlertKey)); @@ -66,14 +66,14 @@ public void ShowAlerts() // Lazy entManager.EventBus.RaiseComponentEvent(alertsComponent, getty); - alertState = (AlertsComponentState) getty.State!; + alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!; Assert.That(alertState.Alerts.Count, Is.EqualTo(1)); Assert.That(alertState.Alerts.ContainsKey(highpressure.AlertKey)); EntitySystem.Get().ClearAlertCategory(alertsComponent.Owner, AlertCategory.Pressure); entManager.EventBus.RaiseComponentEvent(alertsComponent, getty); - alertState = (AlertsComponentState) getty.State!; + alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!; Assert.That(alertState.Alerts.Count, Is.EqualTo(0)); } } From e0c596e33822d8bccc1826920c4c285f92a00e3b Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 16:46:39 -0700 Subject: [PATCH 35/98] Fix role unbans not applying in real time (#20547) --- .../Commands/RoleUnbanCommand.cs | 36 ++--------- .../Administration/Managers/BanManager.cs | 64 +++++++++++++------ .../Administration/Managers/IBanManager.cs | 15 ++++- Content.Server/Database/ServerDbBase.cs | 2 +- Content.Server/Database/ServerDbManager.cs | 5 +- Content.Server/Database/ServerDbPostgres.cs | 10 ++- Content.Server/Database/ServerDbSqlite.cs | 10 ++- 7 files changed, 78 insertions(+), 64 deletions(-) diff --git a/Content.Server/Administration/Commands/RoleUnbanCommand.cs b/Content.Server/Administration/Commands/RoleUnbanCommand.cs index ba8ab61c5c1..a49f1231bf4 100644 --- a/Content.Server/Administration/Commands/RoleUnbanCommand.cs +++ b/Content.Server/Administration/Commands/RoleUnbanCommand.cs @@ -1,7 +1,5 @@ -using System.Text; -using Content.Server.Database; +using Content.Server.Administration.Managers; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands; @@ -15,9 +13,6 @@ public sealed class RoleUnbanCommand : IConsoleCommand public async void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; - var dbMan = IoCManager.Resolve(); - if (args.Length != 1) { shell.WriteLine(Help); @@ -30,32 +25,9 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) return; } - var ban = await dbMan.GetServerRoleBanAsync(banId); - - if (ban == null) - { - shell.WriteLine($"No ban found with id {banId}"); - return; - } - - if (ban.Unban != null) - { - var response = new StringBuilder("This ban has already been pardoned"); - - if (ban.Unban.UnbanningAdmin != null) - { - response.Append($" by {ban.Unban.UnbanningAdmin.Value}"); - } - - response.Append($" in {ban.Unban.UnbanTime}."); - - shell.WriteLine(response.ToString()); - return; - } - - await dbMan.AddServerRoleUnbanAsync(new ServerRoleUnbanDef(banId, player?.UserId, DateTimeOffset.Now)); - - shell.WriteLine($"Pardoned ban with id {banId}"); + var banManager = IoCManager.Resolve(); + var response = await banManager.PardonRoleBan(banId, shell.Player?.UserId, DateTimeOffset.Now); + shell.WriteLine(response); } public CompletionResult GetCompletion(IConsoleShell shell, string[] args) diff --git a/Content.Server/Administration/Managers/BanManager.cs b/Content.Server/Administration/Managers/BanManager.cs index 4640c63dbd2..765df17b179 100644 --- a/Content.Server/Administration/Managers/BanManager.cs +++ b/Content.Server/Administration/Managers/BanManager.cs @@ -1,21 +1,22 @@ using System.Collections.Immutable; using System.Linq; using System.Net; +using System.Text; using System.Threading.Tasks; using Content.Server.Chat.Managers; using Content.Server.Database; using Content.Server.GameTicking; +using Content.Shared.CCVar; using Content.Shared.Database; using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Roles; -using Microsoft.CodeAnalysis; -using Content.Shared.CCVar; using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Network; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Server.Administration.Managers; @@ -47,28 +48,25 @@ public void Initialize() private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) { - if (e.NewStatus != SessionStatus.Connected - || _cachedRoleBans.ContainsKey(e.Session.UserId)) + if (e.NewStatus != SessionStatus.Connected || _cachedRoleBans.ContainsKey(e.Session.UserId)) return; var netChannel = e.Session.ConnectedClient; - await CacheDbRoleBans(e.Session.UserId, netChannel.RemoteEndPoint.Address, netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId); + ImmutableArray? hwId = netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId; + await CacheDbRoleBans(e.Session.UserId, netChannel.RemoteEndPoint.Address, hwId); + + SendRoleBans(e.Session); } private async Task AddRoleBan(ServerRoleBanDef banDef) { + banDef = await _db.AddServerRoleBanAsync(banDef); + if (banDef.UserId != null) { - if (!_cachedRoleBans.TryGetValue(banDef.UserId.Value, out var roleBans)) - { - roleBans = new HashSet(); - _cachedRoleBans.Add(banDef.UserId.Value, roleBans); - } - if (!roleBans.Contains(banDef)) - roleBans.Add(banDef); + _cachedRoleBans.GetOrNew(banDef.UserId.Value).Add(banDef); } - await _db.AddServerRoleBanAsync(banDef); return true; } @@ -231,6 +229,39 @@ public async void CreateRoleBan(NetUserId? target, string? targetUsername, NetUs } } + public async Task PardonRoleBan(int banId, NetUserId? unbanningAdmin, DateTimeOffset unbanTime) + { + var ban = await _db.GetServerRoleBanAsync(banId); + + if (ban == null) + { + return $"No ban found with id {banId}"; + } + + if (ban.Unban != null) + { + var response = new StringBuilder("This ban has already been pardoned"); + + if (ban.Unban.UnbanningAdmin != null) + { + response.Append($" by {ban.Unban.UnbanningAdmin.Value}"); + } + + response.Append($" in {ban.Unban.UnbanTime}."); + return response.ToString(); + } + + await _db.AddServerRoleUnbanAsync(new ServerRoleUnbanDef(banId, unbanningAdmin, DateTimeOffset.Now)); + + if (ban.UserId is { } player && _cachedRoleBans.TryGetValue(player, out var roleBans)) + { + roleBans.RemoveWhere(roleBan => roleBan.Id == ban.Id); + SendRoleBans(player); + } + + return $"Pardoned ban with id {banId}"; + } + public HashSet? GetJobBans(NetUserId playerUserId) { if (!_cachedRoleBans.TryGetValue(playerUserId, out var roleBans)) @@ -254,12 +285,7 @@ public void SendRoleBans(NetUserId userId) public void SendRoleBans(IPlayerSession pSession) { - if (!_cachedRoleBans.TryGetValue(pSession.UserId, out var roleBans)) - { - _sawmill.Error($"Tried to send rolebans for {pSession.Name} but none cached?"); - return; - } - + var roleBans = _cachedRoleBans.GetValueOrDefault(pSession.UserId) ?? new HashSet(); var bans = new MsgRoleBans() { Bans = roleBans.Select(o => o.Role).ToList() diff --git a/Content.Server/Administration/Managers/IBanManager.cs b/Content.Server/Administration/Managers/IBanManager.cs index 6d991c7576f..8458feac8d0 100644 --- a/Content.Server/Administration/Managers/IBanManager.cs +++ b/Content.Server/Administration/Managers/IBanManager.cs @@ -1,8 +1,9 @@ using System.Collections.Immutable; +using System.Net; +using System.Threading.Tasks; using Content.Shared.Database; using Robust.Server.Player; using Robust.Shared.Network; -using System.Net; namespace Content.Server.Administration.Managers; @@ -24,18 +25,26 @@ public interface IBanManager public void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableArray? hwid, uint? minutes, NoteSeverity severity, string reason); public HashSet? GetRoleBans(NetUserId playerUserId); public HashSet? GetJobBans(NetUserId playerUserId); + /// /// Creates a job ban for the specified target, username or GUID /// - /// Shell reference so we can write messages /// Target user, username or GUID, null for none - /// Job to be banned from + /// Role to be banned from /// Severity of the resulting ban note /// Reason for the ban /// Number of minutes to ban for. 0 and null mean permanent /// Time when the ban was applied, used for grouping role bans public void CreateRoleBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableArray? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan); + /// + /// Pardons a role ban for the specified target, username or GUID + /// + /// The id of the role ban to pardon. + /// The admin, if any, that pardoned the role ban. + /// The time at which this role ban was pardoned. + public Task PardonRoleBan(int banId, NetUserId? unbanningAdmin, DateTimeOffset unbanTime); + /// /// Sends role bans to the target /// diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index f90b938b791..aeebc64f07b 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -432,7 +432,7 @@ public abstract Task> GetServerRoleBansAsync(IPAddress? a ImmutableArray? hwId, bool includeUnbanned); - public abstract Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan); + public abstract Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan); public abstract Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverRoleUnban); public async Task EditServerRoleBan(int id, string reason, NoteSeverity severity, DateTime? expiration, Guid editedBy, DateTime editedAt) diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index f345763f53d..8d07a5ac5ea 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -14,7 +14,6 @@ using Microsoft.Extensions.Logging; using Npgsql; using Prometheus; -using Robust.Shared.Asynchronous; using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.Network; @@ -140,7 +139,7 @@ Task> GetServerRoleBansAsync( ImmutableArray? hwId, bool includeUnbanned = true); - Task AddServerRoleBanAsync(ServerRoleBanDef serverBan); + Task AddServerRoleBanAsync(ServerRoleBanDef serverBan); Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverBan); public Task EditServerRoleBan( @@ -453,7 +452,7 @@ public Task> GetServerRoleBansAsync( return RunDbCommand(() => _db.GetServerRoleBansAsync(address, userId, hwId, includeUnbanned)); } - public Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan) + public Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan) { DbWriteOpsMetric.Inc(); return RunDbCommand(() => _db.AddServerRoleBanAsync(serverRoleBan)); diff --git a/Content.Server/Database/ServerDbPostgres.cs b/Content.Server/Database/ServerDbPostgres.cs index 40e9010cf78..3548b1d1b37 100644 --- a/Content.Server/Database/ServerDbPostgres.cs +++ b/Content.Server/Database/ServerDbPostgres.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using System.Data; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; using System.Threading; @@ -350,6 +351,7 @@ private static IQueryable MakeRoleBanLookupQuery( return query; } + [return: NotNullIfNotNull(nameof(ban))] private static ServerRoleBanDef? ConvertRoleBan(ServerRoleBan? ban) { if (ban == null) @@ -406,11 +408,11 @@ private static IQueryable MakeRoleBanLookupQuery( unban.UnbanTime); } - public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan) + public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan) { await using var db = await GetDbImpl(); - db.PgDbContext.RoleBan.Add(new ServerRoleBan + var ban = new ServerRoleBan { Address = serverRoleBan.Address, HWId = serverRoleBan.HWId?.ToArray(), @@ -423,9 +425,11 @@ public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan) PlaytimeAtNote = serverRoleBan.PlaytimeAtNote, PlayerUserId = serverRoleBan.UserId?.UserId, RoleId = serverRoleBan.Role, - }); + }; + db.PgDbContext.RoleBan.Add(ban); await db.PgDbContext.SaveChangesAsync(); + return ConvertRoleBan(ban); } public override async Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverRoleUnban) diff --git a/Content.Server/Database/ServerDbSqlite.cs b/Content.Server/Database/ServerDbSqlite.cs index 35ee95f8d21..676081c54ed 100644 --- a/Content.Server/Database/ServerDbSqlite.cs +++ b/Content.Server/Database/ServerDbSqlite.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; using System.Threading; @@ -246,11 +247,11 @@ private static bool RoleBanMatches( return hwId is { Length: > 0 } hwIdVar && hwIdVar.AsSpan().SequenceEqual(ban.HWId); } - public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverBan) + public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverBan) { await using var db = await GetDbImpl(); - db.SqliteDbContext.RoleBan.Add(new ServerRoleBan + var ban = new ServerRoleBan { Address = serverBan.Address, Reason = serverBan.Reason, @@ -263,9 +264,11 @@ public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverBan) PlaytimeAtNote = serverBan.PlaytimeAtNote, PlayerUserId = serverBan.UserId?.UserId, RoleId = serverBan.Role, - }); + }; + db.SqliteDbContext.RoleBan.Add(ban); await db.SqliteDbContext.SaveChangesAsync(); + return ConvertRoleBan(ban); } public override async Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverUnban) @@ -282,6 +285,7 @@ public override async Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverUnba await db.SqliteDbContext.SaveChangesAsync(); } + [return: NotNullIfNotNull(nameof(ban))] private static ServerRoleBanDef? ConvertRoleBan(ServerRoleBan? ban) { if (ban == null) From 542683c9c1f440d27f6b37b9c35b34909f6275d3 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 28 Sep 2023 16:46:49 -0700 Subject: [PATCH 36/98] Disable AHelp buttons when no player is selected, update button styling (#20568) --- .../UI/Bwoink/BwoinkControl.xaml | 17 ++++--- .../UI/Bwoink/BwoinkControl.xaml.cs | 49 +++++++++++-------- .../UI/Bwoink/BwoinkWindow.xaml.cs | 16 +----- 3 files changed, 38 insertions(+), 44 deletions(-) diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml index 05c68615ebb..28b55f987f3 100644 --- a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml +++ b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml @@ -6,14 +6,15 @@ - - [DataField("hungerThresholdDecayModifiers", customTypeSerializer: typeof(DictionarySerializer))] - [AutoNetworkedField(cloneData: true)] + [AutoNetworkedField] public Dictionary HungerThresholdDecayModifiers = new() { { HungerThreshold.Overfed, 1.2f }, diff --git a/Content.Shared/Nutrition/Components/ThirstComponent.cs b/Content.Shared/Nutrition/Components/ThirstComponent.cs index 994361470ac..1e3f1398079 100644 --- a/Content.Shared/Nutrition/Components/ThirstComponent.cs +++ b/Content.Shared/Nutrition/Components/ThirstComponent.cs @@ -45,7 +45,7 @@ public sealed partial class ThirstComponent : Component public TimeSpan UpdateRate = TimeSpan.FromSeconds(1); [DataField("thresholds")] - [AutoNetworkedField(cloneData: true)] + [AutoNetworkedField] public Dictionary ThirstThresholds = new() { {ThirstThreshold.OverHydrated, 600.0f}, diff --git a/Content.Shared/Points/PointManagerComponent.cs b/Content.Shared/Points/PointManagerComponent.cs index 91dfef6a4e3..6c5bf6b0fa3 100644 --- a/Content.Shared/Points/PointManagerComponent.cs +++ b/Content.Shared/Points/PointManagerComponent.cs @@ -15,7 +15,7 @@ public sealed partial class PointManagerComponent : Component /// /// A dictionary of a player's netuserID to the amount of points they have. /// - [DataField, AutoNetworkedField(true)] + [DataField, AutoNetworkedField] public Dictionary Points = new(); /// diff --git a/Content.Shared/Research/Components/TechnologyDatabaseComponent.cs b/Content.Shared/Research/Components/TechnologyDatabaseComponent.cs index b9936956adc..fc317454c9a 100644 --- a/Content.Shared/Research/Components/TechnologyDatabaseComponent.cs +++ b/Content.Shared/Research/Components/TechnologyDatabaseComponent.cs @@ -17,21 +17,21 @@ public sealed partial class TechnologyDatabaseComponent : Component [DataField("mainDiscipline", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? MainDiscipline; - [AutoNetworkedField(true)] + [AutoNetworkedField] [DataField("currentTechnologyCards")] public List CurrentTechnologyCards = new(); /// /// Which research disciplines are able to be unlocked /// - [AutoNetworkedField(true)] + [AutoNetworkedField] [DataField("supportedDisciplines", customTypeSerializer: typeof(PrototypeIdListSerializer))] public List SupportedDisciplines = new(); /// /// The ids of all the technologies which have been unlocked. /// - [AutoNetworkedField(true)] + [AutoNetworkedField] [DataField("unlockedTechnologies", customTypeSerializer: typeof(PrototypeIdListSerializer))] public List UnlockedTechnologies = new(); @@ -40,7 +40,7 @@ public sealed partial class TechnologyDatabaseComponent : Component /// This is maintained alongside the TechnologyIds /// /// todo: if you unlock all the recipes in a tech, it doesn't count as unlocking the tech. sadge - [AutoNetworkedField(true)] + [AutoNetworkedField] [DataField("unlockedRecipes", customTypeSerializer: typeof(PrototypeIdListSerializer))] public List UnlockedRecipes = new(); } diff --git a/Content.Shared/Standing/StandingStateComponent.cs b/Content.Shared/Standing/StandingStateComponent.cs index b1ec6d8668b..5d7bb0a59fd 100644 --- a/Content.Shared/Standing/StandingStateComponent.cs +++ b/Content.Shared/Standing/StandingStateComponent.cs @@ -18,7 +18,7 @@ public sealed partial class StandingStateComponent : Component /// List of fixtures that had their collision mask changed when the entity was downed. /// Required for re-adding the collision mask. /// - [DataField, AutoNetworkedField(true)] + [DataField, AutoNetworkedField] public List ChangedFixtures = new(); } } diff --git a/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs b/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs index c4457179a97..f4731bf46ab 100644 --- a/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs +++ b/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs @@ -11,14 +11,14 @@ public sealed partial class StepTriggerComponent : Component /// /// List of entities that are currently colliding with the entity. /// - [ViewVariables, AutoNetworkedField(true)] + [ViewVariables, AutoNetworkedField] public HashSet Colliding = new(); /// /// The list of entities that are standing on this entity, /// which shouldn't be able to trigger it again until stepping off. /// - [ViewVariables, AutoNetworkedField(true)] + [ViewVariables, AutoNetworkedField] public HashSet CurrentlySteppedOn = new(); /// From 2a5244dbc06823c5e59a4e8c287519cea20315ad Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:20:44 +1000 Subject: [PATCH 63/98] Update submodule to 164.0.0 (#20618) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 889b8351be4..58aa6e5c756 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 889b8351be4be0926ce051c5bdf79b37d729a600 +Subproject commit 58aa6e5c7563c40baa51460a9def164a7ebc1791 From 399f95945e38a828b06ba7b15ea445474d6d0598 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:53:21 +0100 Subject: [PATCH 64/98] fix cognizine ghost role (#20632) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Server/Chemistry/ReagentEffects/MakeSentient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs b/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs index 00266c39a85..be8dbbaf52a 100644 --- a/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs +++ b/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs @@ -23,7 +23,7 @@ public override void Effect(ReagentEffectArgs args) entityManager.RemoveComponent(uid); // Stops from adding a ghost role to things like people who already have a mind - if (entityManager.HasComponent(uid)) + if (entityManager.TryGetComponent(uid, out var mindContainer) && mindContainer.HasMind) { return; } From bfd73fe8a26f7065d3d7e2d19feccec2e67c3c1b Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 30 Sep 2023 13:54:25 -0400 Subject: [PATCH 65/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e268d5d6cc4..7d60046e980 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Flareguy - changes: - - {message: Updated dirty steel & plastic floor tiles to match the new style., type: Tweak} - id: 4427 - time: '2023-08-04T08:55:08.0000000+00:00' - author: metalgearsloth changes: - {message: Spears can now embed into things and require removing., type: Add} @@ -2961,3 +2956,8 @@ Entries: - {message: Volumetric pumps now indicate if they can't pump., type: Add} id: 4926 time: '2023-09-30T03:35:23.0000000+00:00' +- author: deltanedas + changes: + - {message: Fixed cognizine not creating ghost roles., type: Fix} + id: 4927 + time: '2023-09-30T17:53:22.0000000+00:00' From cfc3bac7ea5a9003a2f57d00e4bf13383f3d223b Mon Sep 17 00:00:00 2001 From: Fluffiest Floofers Date: Sat, 30 Sep 2023 20:23:18 +0200 Subject: [PATCH 66/98] Move ID layer one pixel to correct alignment (#20630) --- .../Objects/Misc/id_cards.rsi/idbrigmedic.png | Bin 267 -> 242 bytes .../Misc/id_cards.rsi/idsecurityofficer.png | Bin 184 -> 252 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idbrigmedic.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idbrigmedic.png index a12f705a03622b64d5d48038dfd4ca2594777a69..1f64eb4845ab2dceceb265299fe2fae7a6ec8662 100644 GIT binary patch delta 214 zcmV;{04e{A0`dWnB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0001# zNklySsVNx>-7L6@cdvmWK2JM8UR4<=;+_yq7I<1w z-G<&)Si1mnYeUH(=mp>+_T5RC2GLR(Sd3X~t^qI0z+W)|2ta_}0~`Vj082+BKWG@r Q+yDRo07*qoM6N<$f?&r|;{X5v delta 239 zcmV4y*xa0z`;ArWvbtHt_0Slf6|DOF% zAl2Nv1|X@v1s~~xw94gI87`zq#SL#6x&UYn9LZ-6{0-oYya3Hkm;pXIgFpAlMSeO5 pYFZuVx&f}%^xrT50w4ea;00Gvi>2x`Q!W4i002ovPDHLkV1l!FVO;K(|5<=WO?u>vT70{k9e a6<`2wNqYREbpP%E0000B!7QNL_t(|obA)W4S*mF1<+sPNDkpro>+< Date: Sat, 30 Sep 2023 13:38:43 -0500 Subject: [PATCH 67/98] Update nukie hardsuit descriptions (#20529) --- .../Clothing/Head/hardsuit-helmets.yml | 53 ++++++++------- .../Clothing/OuterClothing/hardsuits.yml | 68 +++++++++---------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 30addb2f544..13bcde369e8 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -1,4 +1,5 @@ #When adding new hardsuits, please try to keep the organization consistent with hardsuit.yml (if possible.) + #For now, since locational damage is not a thing, all "combat" hardsuits (with the exception of the deathsquad hardsuit) have the equvilent of a helmet in terms of armor. This is so people don't need to wear both regular, on-station helmets and hardsuits to get full protection. #Generally, unless you're adding something like caustic damage, you should probably avoid messing with armor outside of the above scenario. @@ -326,7 +327,7 @@ id: ClothingHeadHelmetHardsuitSyndie noSpawn: true name: blood-red hardsuit helmet - description: An advanced red hardsuit helmet designed for work in special operations. + description: A heavily armored helmet designed for work in special operations. Property of Gorlex Marauders. components: - type: Sprite sprite: Clothing/Head/Hardsuits/syndicate.rsi @@ -345,36 +346,13 @@ Piercing: 0.9 Heat: 0.9 -#Cybersun Juggernaut Hardsuit -- type: entity - parent: ClothingHeadHardsuitBase - id: ClothingHeadHelmetHardsuitCybersun - noSpawn: true - name: cybersun juggernaut helmet - description: Made of compressed red matter, this helmet was designed in the Tau chromosphere facility. - components: - - type: Sprite - sprite: Clothing/Head/Hardsuits/cybersun.rsi - - type: Clothing - sprite: Clothing/Head/Hardsuits/cybersun.rsi - - type: PressureProtection - highPressureMultiplier: 0.3 - lowPressureMultiplier: 1000 - - type: Armor - modifiers: - coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 - #Syndicate Elite Hardsuit - type: entity parent: ClothingHeadHardsuitWithLightBase id: ClothingHeadHelmetHardsuitSyndieElite noSpawn: true name: syndicate elite helmet - description: A variant of the blood red helmet designed by the Gorlex Marauders to be exceptionally fireproof and pressure proof. + description: An elite version of the blood-red hardsuit's helmet, with improved armor and fireproofing. Property of Gorlex Marauders. components: - type: Sprite sprite: Clothing/Head/Hardsuits/syndieelite.rsi @@ -401,7 +379,7 @@ id: ClothingHeadHelmetHardsuitSyndieCommander noSpawn: true name: syndicate commander helmet - description: A syndicate hardsuit helmet custom designed for commanders of syndicate operative squads. + description: A bulked up version of the blood-red hardsuit's helmet, purpose-built for the commander of a syndicate operative squad. Has significantly improved armor for those deadly front-lines firefights. components: - type: Sprite sprite: Clothing/Head/Hardsuits/syndiecommander.rsi @@ -420,6 +398,29 @@ Piercing: 0.9 Heat: 0.9 +#Cybersun Juggernaut Hardsuit +- type: entity + parent: ClothingHeadHardsuitBase + id: ClothingHeadHelmetHardsuitCybersun + noSpawn: true + name: cybersun juggernaut helmet + description: Made of compressed red matter, this helmet was designed in the Tau chromosphere facility. + components: + - type: Sprite + sprite: Clothing/Head/Hardsuits/cybersun.rsi + - type: Clothing + sprite: Clothing/Head/Hardsuits/cybersun.rsi + - type: PressureProtection + highPressureMultiplier: 0.3 + lowPressureMultiplier: 1000 + - type: Armor + modifiers: + coefficients: + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 + Heat: 0.9 + #Wizard Hardsuit - type: entity parent: ClothingHeadHardsuitWithLightBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index c295bf88762..66db8332c95 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -426,7 +426,7 @@ parent: ClothingOuterHardsuitBase id: ClothingOuterHardsuitSyndie name: blood-red hardsuit - description: A heavily armored and agile advanced hardsuit designed for work in special operations. + description: A heavily armored hardsuit designed for work in special operations. Property of Gorlex Marauders. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/syndicate.rsi @@ -452,43 +452,12 @@ - type: ToggleableClothing clothingPrototype: ClothingHeadHelmetHardsuitSyndie -#Cybersun Juggernaut Hardsuit -- type: entity - parent: ClothingOuterHardsuitBase - id: ClothingOuterHardsuitJuggernaut - name: cybersun juggernaut suit - description: A suit made by the cutting edge R&D department at cybersun to be hyper resilient. - components: - - type: Sprite - sprite: Clothing/OuterClothing/Hardsuits/cybersun.rsi - - type: Clothing - sprite: Clothing/OuterClothing/Hardsuits/cybersun.rsi - - type: PressureProtection - highPressureMultiplier: 0.2 - lowPressureMultiplier: 1000 - - type: ExplosionResistance - damageCoefficient: 0.3 - - type: Armor - modifiers: - coefficients: - Blunt: 0.2 - Slash: 0.2 - Piercing: 0.2 - Heat: 0.2 - Radiation: 0.2 - Caustic: 0.2 - - type: ClothingSpeedModifier - walkModifier: 0.9 - sprintModifier: 0.65 - - type: ToggleableClothing - clothingPrototype: ClothingHeadHelmetHardsuitCybersun - #Syndicate Elite Hardsuit - type: entity parent: ClothingOuterHardsuitBase id: ClothingOuterHardsuitSyndieElite name: syndicate elite hardsuit - description: An upgraded version of the blood red hardsuit that features enhanced fireproofing, pressure resist, and superior armor. + description: An elite version of the blood-red hardsuit, with improved armor and fireproofing. Property of Gorlex Marauders. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/syndieelite.rsi @@ -521,7 +490,7 @@ parent: ClothingOuterHardsuitBase id: ClothingOuterHardsuitSyndieCommander name: syndicate commander hardsuit - description: A blood red hardsuit heavily modified for use by the commander of operative squads. + description: A bulked up version of the blood-red hardsuit, purpose-built for the commander of a syndicate operative squad. Has significantly improved armor for those deadly front-lines firefights. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/syndiecommander.rsi @@ -547,6 +516,37 @@ - type: ToggleableClothing clothingPrototype: ClothingHeadHelmetHardsuitSyndieCommander +#Cybersun Juggernaut Hardsuit +- type: entity + parent: ClothingOuterHardsuitBase + id: ClothingOuterHardsuitJuggernaut + name: cybersun juggernaut suit + description: A suit made by the cutting edge R&D department at cybersun to be hyper resilient. + components: + - type: Sprite + sprite: Clothing/OuterClothing/Hardsuits/cybersun.rsi + - type: Clothing + sprite: Clothing/OuterClothing/Hardsuits/cybersun.rsi + - type: PressureProtection + highPressureMultiplier: 0.2 + lowPressureMultiplier: 1000 + - type: ExplosionResistance + damageCoefficient: 0.3 + - type: Armor + modifiers: + coefficients: + Blunt: 0.2 + Slash: 0.2 + Piercing: 0.2 + Heat: 0.2 + Radiation: 0.2 + Caustic: 0.2 + - type: ClothingSpeedModifier + walkModifier: 0.9 + sprintModifier: 0.65 + - type: ToggleableClothing + clothingPrototype: ClothingHeadHelmetHardsuitCybersun + #Wizard Hardsuit - type: entity parent: ClothingOuterHardsuitBase From f60c646b772f05cea3d8b44abd9a8b435df59ca5 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:08:08 -0400 Subject: [PATCH 68/98] Make holofans destructable (#20445) --- .../Structures/Holographic/projections.yml | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml index 23f02156d77..1a81ac47024 100644 --- a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml +++ b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml @@ -15,6 +15,16 @@ state: icon - type: TimedDespawn lifetime: 90 + - type: Damageable + damageContainer: Inorganic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 30 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] - type: entity id: HoloFan @@ -58,17 +68,6 @@ - TableMask layer: - TableLayer - - type: Damageable - damageContainer: Inorganic - damageModifierSet: Metallic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 30 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] - type: TimedDespawn lifetime: 180 - type: PointLight From 60a3d48912a2d197b6e11a586a530dc592fdb064 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 30 Sep 2023 15:09:12 -0400 Subject: [PATCH 69/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 7d60046e980..54a8a3dbc68 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - {message: Spears can now embed into things and require removing., type: Add} - id: 4428 - time: '2023-08-04T08:56:39.0000000+00:00' - author: Flareguy changes: - {message: The smartfridge now uses its old sprites., type: Tweak} @@ -2961,3 +2956,8 @@ Entries: - {message: Fixed cognizine not creating ghost roles., type: Fix} id: 4927 time: '2023-09-30T17:53:22.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Holofans can now be destroyed by explosions., type: Fix} + id: 4928 + time: '2023-09-30T19:08:09.0000000+00:00' From 11661ab8523de87cd7b3fd8c77f9ca32bbf10091 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 30 Sep 2023 20:52:24 +0100 Subject: [PATCH 70/98] bowl is open (#20453) Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Consumable/Food/Containers/bowl.yml | 10 +- .../Entities/Objects/Consumable/Food/egg.yml | 12 +- .../Objects/Consumable/Food/ingredients.yml | 127 ++++++++---------- .../Objects/Consumable/Food/produce.yml | 23 +--- 4 files changed, 65 insertions(+), 107 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml index 4384542bb0d..eb05133a38e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml @@ -21,18 +21,12 @@ damage: types: Blunt: 5 - - type: Drink - solution: food - - type: DrawableSolution - solution: food - - type: Damageable - damageContainer: Inorganic - type: SolutionTransfer canChangeTransferAmount: true - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + - key: enum.TransferAmountUiKey.Key + type: TransferAmountBoundUserInterface - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml index 05cae79b166..e2ce3dfaa86 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml @@ -1,7 +1,7 @@ # Base - type: entity - parent: FoodInjectableBase + parent: [FoodInjectableBase, ItemHeftyBase] id: FoodEggBase description: An egg! abstract: true @@ -28,15 +28,7 @@ ignoreEmpty: true popup: spike-solution-egg - type: DeleteOnTrigger - - type: DamageOnLand - damage: - types: - Blunt: 1 - - type: DamageOtherOnHit - damage: - types: - Blunt: 1 - #Dignity: 25 + # egg fragile - type: DamageOnHighSpeedImpact minimumSpeed: 0.1 damage: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml index 9c9890084cf..c3b3bba35ba 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml @@ -5,9 +5,9 @@ # Reagent Containers - type: entity + abstract: true parent: BaseItem id: ReagentContainerBase - abstract: true components: - type: Sprite sprite: Objects/Consumable/Food/ingredients.rsi @@ -18,6 +18,8 @@ - type: SolutionTransfer # This is potentially badly-handled due to 'drink opening', # but it lets the flour be tampered with, refilled, etc. + - type: DrawableSolution + solution: food - type: RefillableSolution solution: food - type: DrainableSolution @@ -26,22 +28,58 @@ solution: food useSound: path: /Audio/Items/eating_1.ogg + - type: Damageable + damageContainer: Inorganic + - type: Spillable + solution: food + - type: TrashOnEmpty + solution: food + +- type: entity + abstract: true + parent: ReagentContainerBase + id: ReagentPacketBase + components: - type: Openable sound: collection: packetOpenSounds - - type: Spillable - solution: food + # packet can be broken open + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 2 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: desecration + - !type:SpillBehavior + solution: food + - !type:DoActsBehavior + acts: [ "Destruction" ] + # packet contents can be splashed when open - type: MeleeWeapon soundNoDamage: path: "/Audio/Effects/Fluids/splat.ogg" damage: types: Blunt: 0 - - type: TrashOnEmpty - solution: food - type: entity - parent: ReagentContainerBase + abstract: true + id: ItemHeftyBase + components: + - type: DamageOnLand + damage: + types: + Blunt: 1 + - type: DamageOtherOnHit + damage: + types: + Blunt: 1 + +- type: entity + parent: [ReagentPacketBase, ItemHeftyBase] id: ReagentContainerFlour name: flour bag description: A big bag of flour. Good for baking! @@ -55,34 +93,9 @@ reagents: - ReagentId: Flour Quantity: 50 - - type: DamageOnLand - damage: - types: - Blunt: 1 - - type: DamageOtherOnHit - damage: - types: - Blunt: 1 - - type: Damageable - damageContainer: Inorganic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 2 - behaviors: - - !type:PlaySoundBehavior - sound: - collection: desecration - - !type:SpillBehavior - solution: food - - !type:DoActsBehavior - acts: [ "Destruction" ] - - type: TrashOnEmpty - solution: food - type: entity - parent: ReagentContainerBase + parent: [ReagentPacketBase, ItemHeftyBase] id: ReagentContainerFlourSmall name: flour pack description: A pack of flour. Good for baking! @@ -96,32 +109,9 @@ reagents: - ReagentId: Flour Quantity: 20 - - type: DamageOnLand - damage: - types: - Blunt: 1 - - type: DamageOtherOnHit - damage: - types: - Blunt: 1 - - type: Damageable - damageContainer: Inorganic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 2 - behaviors: - - !type:PlaySoundBehavior - sound: - collection: desecration - - !type:SpillBehavior - solution: food - - !type:DoActsBehavior - acts: [ "Destruction" ] - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerCornmeal name: cornmeal bag description: A big bag of cornmeal. Good for cooking! @@ -136,7 +126,7 @@ Quantity: 50 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerCornmealSmall name: cornmeal pack description: A pack of cornmeal. Good for cooking! @@ -152,7 +142,7 @@ Quantity: 20 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerRice name: rice bag description: A big bag of rice. Good for cooking! @@ -167,7 +157,7 @@ Quantity: 50 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerRiceSmall name: rice pack description: A pack of rice. Good for cooking! @@ -183,7 +173,7 @@ Quantity: 20 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerSugar name: sugar bag description: A big bag of tasty spacey sugar. @@ -198,7 +188,7 @@ Quantity: 50 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerSugarSmall name: sugar pack description: A pack of tasty spacey sugar. @@ -216,7 +206,7 @@ # Milk - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerMilk name: milk description: It's milk. White and nutritious goodness! @@ -232,7 +222,7 @@ Quantity: 50 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerMilkSoy name: soy milk description: It's soy milk. White and nutritious goodness! @@ -248,7 +238,7 @@ Quantity: 50 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerMilkOat name: oat milk description: It's oat milk. Tan and nutritious goodness! @@ -266,7 +256,7 @@ # Misc - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerOliveoil name: olive oil description: Olive oil. From space olives presumably. @@ -282,7 +272,7 @@ Quantity: 20 - type: entity - parent: ReagentContainerBase + parent: ReagentPacketBase id: ReagentContainerMayo name: mayonnaise description: Bottle of mayonnaise. @@ -298,7 +288,7 @@ Quantity: 20 # - type: entity -# parent: ReagentContainerBase +# parent: ReagentPacketBase # id: ReagentContainerAllspice # name: all-spice # description: @@ -316,13 +306,12 @@ - type: entity abstract: true - parent: BaseItem + parent: FoodBase id: FoodBakingBase description: Used in various recipes. components: - type: Sprite sprite: Objects/Consumable/Food/ingredients.rsi - - type: Food - type: SolutionContainerManager solutions: food: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 4a5aa42130d..1e3d42b26b7 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -548,7 +548,7 @@ - type: entity name: tomato - parent: FoodProduceBase + parent: [FoodProduceBase, ItemHeftyBase] id: FoodTomato description: I say to-mah-to, you say tom-mae-to. components: @@ -576,15 +576,6 @@ reagents: - ReagentId: JuiceTomato Quantity: 10 - - type: DamageOnLand - damage: - types: - Blunt: 1 - - type: DamageOtherOnHit - damage: - types: - Blunt: 1 - #Dignity: 25 - type: Damageable damageContainer: Biological - type: DamageOnHighSpeedImpact @@ -1329,7 +1320,7 @@ - type: entity name: watermelon - parent: FoodProduceBase + parent: [FoodProduceBase, ItemHeftyBase] id: FoodWatermelon description: Round green object that you can slice and eat. components: @@ -1358,14 +1349,6 @@ reagents: - ReagentId: JuiceWatermelon Quantity: 20 - - type: DamageOnLand - damage: - types: - Blunt: 1 - - type: DamageOtherOnHit - damage: - types: - Blunt: 1 - type: Damageable damageContainer: Biological - type: DamageOnHighSpeedImpact @@ -1531,4 +1514,4 @@ - type: Seed seedId: bungo - type: SpaceGarbage - - type: BadFood \ No newline at end of file + - type: BadFood From 950d4588240aa38d1557f0beaf90ece323c5d94e Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 1 Oct 2023 07:00:20 +1100 Subject: [PATCH 71/98] Add TestPair.WaitCommand() (#20615) --- .../Pair/TestPair.Helpers.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Content.IntegrationTests/Pair/TestPair.Helpers.cs b/Content.IntegrationTests/Pair/TestPair.Helpers.cs index 1478a4c7d27..510dc0b854a 100644 --- a/Content.IntegrationTests/Pair/TestPair.Helpers.cs +++ b/Content.IntegrationTests/Pair/TestPair.Helpers.cs @@ -76,4 +76,22 @@ private static EntityUid ConvertUid( return otherUid.Value; } + + /// + /// Execute a command on the server and wait some number of ticks. + /// + public async Task WaitCommand(string cmd, int numTicks = 10) + { + await Server.ExecuteCommand(cmd); + await RunTicksSync(numTicks); + } + + /// + /// Execute a command on the client and wait some number of ticks. + /// + public async Task WaitClientCommand(string cmd, int numTicks = 10) + { + await Client.ExecuteCommand(cmd); + await RunTicksSync(numTicks); + } } From 054fbeec205856443d1ed19f596341e796b0cc12 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 1 Oct 2023 07:01:13 +1100 Subject: [PATCH 72/98] Rename ThreatPrototype and mark fields as required (#20611) --- Content.Server/Communications/CommsHackerSystem.cs | 8 ++++---- .../Communications/CommsHackerComponent.cs | 12 ++++++------ Resources/Prototypes/threats.yml | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Content.Server/Communications/CommsHackerSystem.cs b/Content.Server/Communications/CommsHackerSystem.cs index 851be07454f..1248d214003 100644 --- a/Content.Server/Communications/CommsHackerSystem.cs +++ b/Content.Server/Communications/CommsHackerSystem.cs @@ -64,7 +64,7 @@ private void OnDoAfter(EntityUid uid, CommsHackerComponent comp, TerrorDoAfterEv var threats = _proto.Index(comp.Threats); var threat = threats.Pick(_random); - CallInThreat(_proto.Index(threat)); + CallInThreat(_proto.Index(threat)); // prevent calling in multiple threats RemComp(uid); @@ -76,10 +76,10 @@ private void OnDoAfter(EntityUid uid, CommsHackerComponent comp, TerrorDoAfterEv /// /// Makes announcement and adds game rule of the threat. /// - public void CallInThreat(ThreatPrototype threat) + public void CallInThreat(NinjaHackingThreatPrototype ninjaHackingThreat) { - _gameTicker.StartGameRule(threat.Rule, out _); - _chat.DispatchGlobalAnnouncement(Loc.GetString(threat.Announcement), playSound: true, colorOverride: Color.Red); + _gameTicker.StartGameRule(ninjaHackingThreat.Rule, out _); + _chat.DispatchGlobalAnnouncement(Loc.GetString(ninjaHackingThreat.Announcement), playSound: true, colorOverride: Color.Red); } } diff --git a/Content.Shared/Communications/CommsHackerComponent.cs b/Content.Shared/Communications/CommsHackerComponent.cs index fdd1876c1d7..810058f1ce5 100644 --- a/Content.Shared/Communications/CommsHackerComponent.cs +++ b/Content.Shared/Communications/CommsHackerComponent.cs @@ -29,8 +29,8 @@ public sealed partial class CommsHackerComponent : Component /// Generally some kind of mid-round minor antag, though you could make it call in scrubber backflow if you wanted to. /// You wouldn't do that, right? /// -[Prototype("threat")] -public sealed class ThreatPrototype : IPrototype +[Prototype("ninjaHackingThreat")] +public sealed class NinjaHackingThreatPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; @@ -38,12 +38,12 @@ public sealed class ThreatPrototype : IPrototype /// /// Locale id for the announcement to be made from CentCom. /// - [DataField] - public string Announcement = default!; + [DataField(required: true)] + public LocId Announcement; /// /// The game rule for the threat to be added, it should be able to work when added mid-round otherwise this will do nothing. /// - [DataField] - public EntProtoId Rule = default!; + [DataField(required: true)] + public EntProtoId Rule; } diff --git a/Resources/Prototypes/threats.yml b/Resources/Prototypes/threats.yml index 6e21cc1037d..cb20ce19d97 100644 --- a/Resources/Prototypes/threats.yml +++ b/Resources/Prototypes/threats.yml @@ -5,12 +5,12 @@ Dragon: 1 Revenant: 1 -- type: threat +- type: ninjaHackingThreat id: Dragon announcement: terror-dragon rule: Dragon -- type: threat +- type: ninjaHackingThreat id: Revenant announcement: terror-revenant rule: RevenantSpawn From ad7c4deb9c957c86b8ab1bf505f642b6fadbea91 Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Sat, 30 Sep 2023 12:02:21 -0800 Subject: [PATCH 73/98] Adjust hard bomb shape (#20608) --- Resources/Prototypes/Entities/Structures/Machines/bombs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml index 40a3e36df89..a88da73550e 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml @@ -41,7 +41,7 @@ fix1: shape: !type:PhysShapeAabb - bounds: "-0.45,-0.45,0.45,0.45" + bounds: "-0.3,-0.3,0.3,0.3" density: 190 mask: - MachineMask From 8a0560b669c6fec89551271e016631d75bfdc003 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 30 Sep 2023 21:18:01 +0100 Subject: [PATCH 74/98] dragon refactor, objectives and use GenericAntag (#20201) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Server/Dragon/DragonRiftSystem.cs | 115 ++++++++ Content.Server/Dragon/DragonSystem.Rule.cs | 52 ---- Content.Server/Dragon/DragonSystem.cs | 277 ++++++++---------- .../Components/CarpRiftsConditionComponent.cs | 17 ++ .../Systems/CarpRiftsConditionSystem.cs | 56 ++++ Content.Server/Roles/DragonRoleComponent.cs | 12 + Content.Server/Roles/RoleSystem.cs | 1 + .../Locale/en-US/actions/actions/dragon.ftl | 16 - Resources/Locale/en-US/dragon/dragon.ftl | 5 + Resources/Locale/en-US/dragon/rifts.ftl | 9 + .../objectives/conditions/carp-rifts.ftl | 2 + .../Entities/Mobs/Player/dragon.yml | 2 + .../Entities/Structures/Specific/dragon.yml | 72 +++-- Resources/Prototypes/GameRules/events.yml | 3 +- Resources/Prototypes/GameRules/midround.yml | 12 + Resources/Prototypes/Objectives/dragon.yml | 42 +++ .../Specific/carp_rift.rsi/icon_blue.png | Bin 0 -> 8326 bytes .../Specific/carp_rift.rsi/meta.json | 14 +- 18 files changed, 455 insertions(+), 252 deletions(-) create mode 100644 Content.Server/Dragon/DragonRiftSystem.cs delete mode 100644 Content.Server/Dragon/DragonSystem.Rule.cs create mode 100644 Content.Server/Objectives/Components/CarpRiftsConditionComponent.cs create mode 100644 Content.Server/Objectives/Systems/CarpRiftsConditionSystem.cs create mode 100644 Content.Server/Roles/DragonRoleComponent.cs create mode 100644 Resources/Locale/en-US/dragon/dragon.ftl create mode 100644 Resources/Locale/en-US/dragon/rifts.ftl create mode 100644 Resources/Locale/en-US/objectives/conditions/carp-rifts.ftl create mode 100644 Resources/Prototypes/Objectives/dragon.yml create mode 100644 Resources/Textures/Structures/Specific/carp_rift.rsi/icon_blue.png diff --git a/Content.Server/Dragon/DragonRiftSystem.cs b/Content.Server/Dragon/DragonRiftSystem.cs new file mode 100644 index 00000000000..52137f2ee6e --- /dev/null +++ b/Content.Server/Dragon/DragonRiftSystem.cs @@ -0,0 +1,115 @@ +using Content.Server.Chat.Systems; +using Content.Server.NPC; +using Content.Server.NPC.Systems; +using Content.Server.Pinpointer; +using Content.Shared.Damage; +using Content.Shared.Dragon; +using Content.Shared.Examine; +using Content.Shared.Sprite; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Player; +using Robust.Shared.Serialization.Manager; +using System.Numerics; + +namespace Content.Server.Dragon; + +/// +/// Handles events for rift entities and rift updating. +/// +public sealed class DragonRiftSystem : EntitySystem +{ + [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly DragonSystem _dragon = default!; + [Dependency] private readonly ISerializationManager _serManager = default!; + [Dependency] private readonly NavMapSystem _navMap = default!; + [Dependency] private readonly NPCSystem _npc = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnAnchorChange); + SubscribeLocalEvent(OnShutdown); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var xform)) + { + if (comp.State != DragonRiftState.Finished && comp.Accumulator >= comp.MaxAccumulator) + { + // TODO: When we get autocall you can buff if the rift finishes / 3 rifts are up + // for now they just keep 3 rifts up. + + if (comp.Dragon != null) + _dragon.RiftCharged(comp.Dragon.Value); + + comp.Accumulator = comp.MaxAccumulator; + RemComp(uid); + comp.State = DragonRiftState.Finished; + Dirty(uid, comp); + } + else if (comp.State != DragonRiftState.Finished) + { + comp.Accumulator += frameTime; + } + + comp.SpawnAccumulator += frameTime; + + if (comp.State < DragonRiftState.AlmostFinished && comp.Accumulator > comp.MaxAccumulator / 2f) + { + comp.State = DragonRiftState.AlmostFinished; + Dirty(comp); + + var location = xform.LocalPosition; + _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red); + _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); + _navMap.SetBeaconEnabled(uid, true); + } + + if (comp.SpawnAccumulator > comp.SpawnCooldown) + { + comp.SpawnAccumulator -= comp.SpawnCooldown; + var ent = Spawn(comp.SpawnPrototype, xform.Coordinates); + + // Update their look to match the leader. + if (TryComp(comp.Dragon, out var randomSprite)) + { + var spawnedSprite = EnsureComp(ent); + _serManager.CopyTo(randomSprite, ref spawnedSprite, notNullableOverride: true); + Dirty(ent, spawnedSprite); + } + + if (comp.Dragon != null) + _npc.SetBlackboard(ent, NPCBlackboard.FollowTarget, new EntityCoordinates(comp.Dragon.Value, Vector2.Zero)); + } + } + } + + private void OnExamined(EntityUid uid, DragonRiftComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("carp-rift-examine", ("percentage", MathF.Round(component.Accumulator / component.MaxAccumulator * 100)))); + } + + private void OnAnchorChange(EntityUid uid, DragonRiftComponent component, ref AnchorStateChangedEvent args) + { + if (!args.Anchored && component.State == DragonRiftState.Charging) + { + QueueDel(uid); + } + } + + private void OnShutdown(EntityUid uid, DragonRiftComponent comp, ComponentShutdown args) + { + if (!TryComp(comp.Dragon, out var dragon) || dragon.Weakened) + return; + + _dragon.RiftDestroyed(comp.Dragon.Value, dragon); + } +} diff --git a/Content.Server/Dragon/DragonSystem.Rule.cs b/Content.Server/Dragon/DragonSystem.Rule.cs deleted file mode 100644 index 4a4f44e143b..00000000000 --- a/Content.Server/Dragon/DragonSystem.Rule.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Linq; -using Content.Server.GameTicking; -using Content.Server.GameTicking.Rules.Components; -using Content.Server.Station.Components; -using Content.Shared.Dragon; -using Robust.Server.GameObjects; -using Robust.Shared.Map.Components; -using Robust.Shared.Random; - -namespace Content.Server.Dragon; - -public sealed partial class DragonSystem -{ - private int RiftsMet(DragonComponent component) - { - var finished = 0; - - foreach (var rift in component.Rifts) - { - if (!TryComp(rift, out var drift) || - drift.State != DragonRiftState.Finished) - continue; - - finished++; - } - - return finished; - } - - private void OnRiftRoundEnd(RoundEndTextAppendEvent args) - { - if (EntityQuery().Count() == 0) - return; - - args.AddLine(Loc.GetString("dragon-round-end-summary")); - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var dragon)) - { - var met = RiftsMet(dragon); - - if (TryComp(uid, out var actor)) - { - args.AddLine(Loc.GetString("dragon-round-end-dragon-player", ("name", uid), ("count", met), ("player", actor.PlayerSession))); - } - else - { - args.AddLine(Loc.GetString("dragon-round-end-dragon", ("name", uid), ("count", met))); - } - } - } -} diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 40039be50e2..ed17ba8bdc2 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -1,35 +1,33 @@ -using System.Numerics; -using Content.Server.Chat.Systems; -using Content.Server.GameTicking; -using Content.Server.NPC; -using Content.Server.NPC.Systems; +using Content.Server.GenericAntag; +using Content.Server.Objectives.Components; +using Content.Server.Objectives.Systems; using Content.Server.Popups; +using Content.Server.Roles; using Content.Shared.Actions; -using Content.Shared.Damage; using Content.Shared.Dragon; -using Content.Shared.Examine; using Content.Shared.Maps; +using Content.Shared.Mind; +using Content.Shared.Mind.Components; using Content.Shared.Mobs; using Content.Shared.Movement.Systems; -using Content.Shared.Sprite; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Serialization.Manager; namespace Content.Server.Dragon; public sealed partial class DragonSystem : EntitySystem { + [Dependency] private readonly CarpRiftsConditionSystem _carpRifts = default!; [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly ISerializationManager _serManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDef = default!; - [Dependency] private readonly ChatSystem _chat = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly NPCSystem _npc = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly RoleSystem _role = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + private EntityQuery _objQuery; /// /// Minimum distance between 2 rifts allowed. @@ -47,26 +45,22 @@ public override void Initialize() { base.Initialize(); + _objQuery = GetEntityQuery(); + SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnDragonRift); + SubscribeLocalEvent(OnSpawnRift); SubscribeLocalEvent(OnDragonMove); - SubscribeLocalEvent(OnMobStateChanged); - - SubscribeLocalEvent(OnRiftShutdown); - SubscribeLocalEvent(OnRiftGetState); - SubscribeLocalEvent(OnAnchorChange); - SubscribeLocalEvent(OnRiftExamined); - - SubscribeLocalEvent(OnRiftRoundEnd); + SubscribeLocalEvent(OnCreated); } public override void Update(float frameTime) { base.Update(frameTime); - foreach (var comp in EntityQuery()) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) { if (comp.WeakenedAccumulator > 0f) { @@ -76,15 +70,13 @@ public override void Update(float frameTime) if (comp.WeakenedAccumulator < 0f) { comp.WeakenedAccumulator = 0f; - _movement.RefreshMovementSpeedModifiers(comp.Owner); + _movement.RefreshMovementSpeedModifiers(uid); } } // At max rifts if (comp.Rifts.Count >= RiftsAllowed) - { continue; - } // If there's an active rift don't accumulate. if (comp.Rifts.Count > 0) @@ -103,125 +95,40 @@ public override void Update(float frameTime) // Delete it, naughty dragon! if (comp.RiftAccumulator >= comp.RiftMaxAccumulator) { - Roar(comp); - QueueDel(comp.Owner); - } - } - - foreach (var comp in EntityQuery()) - { - if (comp.State != DragonRiftState.Finished && comp.Accumulator >= comp.MaxAccumulator) - { - // TODO: When we get autocall you can buff if the rift finishes / 3 rifts are up - // for now they just keep 3 rifts up. - - comp.Accumulator = comp.MaxAccumulator; - RemComp(comp.Owner); - comp.State = DragonRiftState.Finished; - Dirty(comp); - } - else if (comp.State != DragonRiftState.Finished) - { - comp.Accumulator += frameTime; - } - - comp.SpawnAccumulator += frameTime; - - if (comp.State < DragonRiftState.AlmostFinished && comp.Accumulator > comp.MaxAccumulator / 2f) - { - comp.State = DragonRiftState.AlmostFinished; - Dirty(comp); - var location = Transform(comp.Owner).LocalPosition; - - _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red); - _audioSystem.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); - } - - if (comp.SpawnAccumulator > comp.SpawnCooldown) - { - comp.SpawnAccumulator -= comp.SpawnCooldown; - var ent = Spawn(comp.SpawnPrototype, Transform(comp.Owner).Coordinates); - - // Update their look to match the leader. - if (TryComp(comp.Dragon, out var randomSprite)) - { - var spawnedSprite = EnsureComp(ent); - _serManager.CopyTo(randomSprite, ref spawnedSprite, notNullableOverride: true); - Dirty(ent, spawnedSprite); - } - - if (comp.Dragon != null) - _npc.SetBlackboard(ent, NPCBlackboard.FollowTarget, new EntityCoordinates(comp.Dragon.Value, Vector2.Zero)); + Roar(uid, comp); + QueueDel(uid); } } } - #region Rift - - private void OnRiftExamined(EntityUid uid, DragonRiftComponent component, ExaminedEvent args) + private void OnInit(EntityUid uid, DragonComponent component, MapInitEvent args) { - args.PushMarkup(Loc.GetString("carp-rift-examine", ("percentage", MathF.Round(component.Accumulator / component.MaxAccumulator * 100)))); + Roar(uid, component); + _actions.AddAction(uid, ref component.SpawnRiftActionEntity, component.SpawnRiftAction); } - private void OnAnchorChange(EntityUid uid, DragonRiftComponent component, ref AnchorStateChangedEvent args) - { - if (!args.Anchored && component.State == DragonRiftState.Charging) - { - QueueDel(uid); - } - } - - private void OnRiftShutdown(EntityUid uid, DragonRiftComponent component, ComponentShutdown args) - { - if (TryComp(component.Dragon, out var dragon) && !dragon.Weakened) - { - foreach (var rift in dragon.Rifts) - { - QueueDel(rift); - } - - dragon.Rifts.Clear(); - - // We can't predict the rift being destroyed anyway so no point adding weakened to shared. - dragon.WeakenedAccumulator = dragon.WeakenedDuration; - _movement.RefreshMovementSpeedModifiers(component.Dragon.Value); - _popupSystem.PopupEntity(Loc.GetString("carp-rift-destroyed"), component.Dragon.Value, component.Dragon.Value); - } - } - - private void OnRiftGetState(EntityUid uid, DragonRiftComponent component, ref ComponentGetState args) + private void OnShutdown(EntityUid uid, DragonComponent component, ComponentShutdown args) { - args.State = new DragonRiftComponentState() - { - State = component.State - }; + DeleteRifts(uid, false, component); } - private void OnDragonMove(EntityUid uid, DragonComponent component, RefreshMovementSpeedModifiersEvent args) + private void OnSpawnRift(EntityUid uid, DragonComponent component, DragonSpawnRiftActionEvent args) { if (component.Weakened) { - args.ModifySpeed(0.5f, 0.5f); - } - } - - private void OnDragonRift(EntityUid uid, DragonComponent component, DragonSpawnRiftActionEvent args) - { - if (component.Weakened) - { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-weakened"), uid, uid); + _popup.PopupEntity(Loc.GetString("carp-rift-weakened"), uid, uid); return; } if (component.Rifts.Count >= RiftsAllowed) { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-max"), uid, uid); + _popup.PopupEntity(Loc.GetString("carp-rift-max"), uid, uid); return; } if (component.Rifts.Count > 0 && TryComp(component.Rifts[^1], out var rift) && rift.State != DragonRiftState.Finished) { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-duplicate"), uid, uid); + _popup.PopupEntity(Loc.GetString("carp-rift-duplicate"), uid, uid); return; } @@ -230,72 +137,144 @@ private void OnDragonRift(EntityUid uid, DragonComponent component, DragonSpawnR // Have to be on a grid fam if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, uid); + _popup.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, uid); return; } + // cant stack rifts near eachother foreach (var (_, riftXform) in EntityQuery(true)) { if (riftXform.Coordinates.InRange(EntityManager, xform.Coordinates, RiftRange)) { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-proximity", ("proximity", RiftRange)), uid, uid); + _popup.PopupEntity(Loc.GetString("carp-rift-proximity", ("proximity", RiftRange)), uid, uid); return; } } + // cant put a rift on solars foreach (var tile in grid.GetTilesIntersecting(new Circle(xform.WorldPosition, RiftTileRadius), false)) { if (!tile.IsSpace(_tileDef)) continue; - _popupSystem.PopupEntity(Loc.GetString("carp-rift-space-proximity", ("proximity", RiftTileRadius)), uid, uid); + _popup.PopupEntity(Loc.GetString("carp-rift-space-proximity", ("proximity", RiftTileRadius)), uid, uid); return; } var carpUid = Spawn(component.RiftPrototype, xform.MapPosition); component.Rifts.Add(carpUid); Comp(carpUid).Dragon = uid; - _audioSystem.PlayPvs("/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg", carpUid); } - #endregion - - private void OnShutdown(EntityUid uid, DragonComponent component, ComponentShutdown args) + // TODO: just make this a move speed modifier component??? + private void OnDragonMove(EntityUid uid, DragonComponent component, RefreshMovementSpeedModifiersEvent args) { - foreach (var rift in component.Rifts) + if (component.Weakened) { - QueueDel(rift); + args.ModifySpeed(0.5f, 0.5f); } } private void OnMobStateChanged(EntityUid uid, DragonComponent component, MobStateChangedEvent args) { - //Empties the stomach upon death - //TODO: Do this when the dragon gets butchered instead - if (args.NewMobState == MobState.Dead) + // Deletes all rifts after dying + if (args.NewMobState != MobState.Dead) + return; + + if (component.SoundDeath != null) + _audio.PlayPvs(component.SoundDeath, uid); + + // objective is explicitly not reset so that it will show how many you got before dying in round end text + DeleteRifts(uid, false, component); + } + + private void OnCreated(EntityUid uid, DragonComponent comp, ref GenericAntagCreatedEvent args) + { + var mindId = args.MindId; + var mind = args.Mind; + + _role.MindAddRole(mindId, new DragonRoleComponent(), mind); + _role.MindAddRole(mindId, new RoleBriefingComponent() + { + Briefing = Loc.GetString("dragon-role-briefing") + }, mind); + } + + private void Roar(EntityUid uid, DragonComponent comp) + { + if (comp.SoundRoar != null) + _audio.Play(comp.SoundRoar, Filter.Pvs(uid, 4f, EntityManager), uid, true); + } + + /// + /// Delete all rifts this dragon made. + /// + /// Entity id of the dragon + /// If true, the role's rift count will be reset too + /// The dragon component + public void DeleteRifts(EntityUid uid, bool resetRole, DragonComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return; + + foreach (var rift in comp.Rifts) { - if (component.SoundDeath != null) - _audioSystem.PlayPvs(component.SoundDeath, uid, component.SoundDeath.Params); + QueueDel(rift); + } + + comp.Rifts.Clear(); - foreach (var rift in component.Rifts) + // stop here if not trying to reset the objective's rift count + if (!resetRole || !TryComp(uid, out var mindContainer) || !mindContainer.HasMind) + return; + + var mind = Comp(mindContainer.Mind.Value); + foreach (var objId in mind.AllObjectives) + { + if (_objQuery.TryGetComponent(objId, out var obj)) { - QueueDel(rift); + _carpRifts.ResetRifts(objId, obj); + break; } - - component.Rifts.Clear(); } } - private void Roar(DragonComponent component) + /// + /// Increment the dragon role's charged rift count. + /// + public void RiftCharged(EntityUid uid, DragonComponent? comp = null) { - if (component.SoundRoar != null) - _audioSystem.Play(component.SoundRoar, Filter.Pvs(component.Owner, 4f, EntityManager), component.Owner, true, component.SoundRoar.Params); + if (!Resolve(uid, ref comp)) + return; + + if (!TryComp(uid, out var mindContainer) || !mindContainer.HasMind) + return; + + var mind = Comp(mindContainer.Mind.Value); + foreach (var objId in mind.AllObjectives) + { + if (_objQuery.TryGetComponent(objId, out var obj)) + { + _carpRifts.RiftCharged(objId, obj); + break; + } + } } - private void OnInit(EntityUid uid, DragonComponent component, MapInitEvent args) + /// + /// Do everything that needs to happen when a rift gets destroyed by the crew. + /// + public void RiftDestroyed(EntityUid uid, DragonComponent? comp = null) { - Roar(component); - _actionsSystem.AddAction(uid, ref component.SpawnRiftActionEntity, component.SpawnRiftAction); + if (!Resolve(uid, ref comp)) + return; + + // do reset the rift count since crew destroyed the rift, not deleted by the dragon dying. + DeleteRifts(uid, true, comp); + + // We can't predict the rift being destroyed anyway so no point adding weakened to shared. + comp.WeakenedAccumulator = comp.WeakenedDuration; + _movement.RefreshMovementSpeedModifiers(uid); + _popup.PopupEntity(Loc.GetString("carp-rift-destroyed"), uid, uid); } } - diff --git a/Content.Server/Objectives/Components/CarpRiftsConditionComponent.cs b/Content.Server/Objectives/Components/CarpRiftsConditionComponent.cs new file mode 100644 index 00000000000..8e43154e37a --- /dev/null +++ b/Content.Server/Objectives/Components/CarpRiftsConditionComponent.cs @@ -0,0 +1,17 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Requires that the dragon open and fully charge a certain number of rifts. +/// Depends on to function. +/// +[RegisterComponent, Access(typeof(CarpRiftsConditionSystem))] +public sealed partial class CarpRiftsConditionComponent : Component +{ + /// + /// The number of rifts currently charged. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int RiftsCharged; +} diff --git a/Content.Server/Objectives/Systems/CarpRiftsConditionSystem.cs b/Content.Server/Objectives/Systems/CarpRiftsConditionSystem.cs new file mode 100644 index 00000000000..efb2d228d6f --- /dev/null +++ b/Content.Server/Objectives/Systems/CarpRiftsConditionSystem.cs @@ -0,0 +1,56 @@ +using Content.Server.Objectives.Components; +using Content.Server.Roles; +using Content.Shared.Objectives.Components; + +namespace Content.Server.Objectives.Systems; + +public sealed class CarpRiftsConditionSystem : EntitySystem +{ + [Dependency] private readonly NumberObjectiveSystem _number = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetProgress); + } + + private void OnGetProgress(EntityUid uid, CarpRiftsConditionComponent comp, ref ObjectiveGetProgressEvent args) + { + args.Progress = GetProgress(comp, _number.GetTarget(uid)); + } + + private float GetProgress(CarpRiftsConditionComponent comp, int target) + { + // prevent divide-by-zero + if (target == 0) + return 1f; + + if (comp.RiftsCharged >= target) + return 1f; + + return (float) comp.RiftsCharged / (float) target; + } + + /// + /// Increments RiftsCharged, called after a rift fully charges. + /// + public void RiftCharged(EntityUid uid, CarpRiftsConditionComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return; + + comp.RiftsCharged++; + } + + /// + /// Resets RiftsCharged to 0, called after rifts get destroyed. + /// + public void ResetRifts(EntityUid uid, CarpRiftsConditionComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return; + + comp.RiftsCharged = 0; + } +} diff --git a/Content.Server/Roles/DragonRoleComponent.cs b/Content.Server/Roles/DragonRoleComponent.cs new file mode 100644 index 00000000000..77fd97acb29 --- /dev/null +++ b/Content.Server/Roles/DragonRoleComponent.cs @@ -0,0 +1,12 @@ +using Content.Server.Dragon; +using Content.Shared.Roles; + +namespace Content.Server.Roles; + +/// +/// Role used to keep track of space dragons for antag purposes. +/// +[RegisterComponent, Access(typeof(DragonSystem))] +public sealed partial class DragonRoleComponent : AntagonistRoleComponent +{ +} diff --git a/Content.Server/Roles/RoleSystem.cs b/Content.Server/Roles/RoleSystem.cs index 4ca6c0ac801..b04f051c6e8 100644 --- a/Content.Server/Roles/RoleSystem.cs +++ b/Content.Server/Roles/RoleSystem.cs @@ -9,6 +9,7 @@ public override void Initialize() // TODO make roles entities base.Initialize(); + SubscribeAntagEvents(); SubscribeAntagEvents(); SubscribeAntagEvents(); SubscribeAntagEvents(); diff --git a/Resources/Locale/en-US/actions/actions/dragon.ftl b/Resources/Locale/en-US/actions/actions/dragon.ftl index a9b887142d6..b2b9b6d3af9 100644 --- a/Resources/Locale/en-US/actions/actions/dragon.ftl +++ b/Resources/Locale/en-US/actions/actions/dragon.ftl @@ -3,19 +3,3 @@ devour-action-popup-message-fail-target-not-valid = That doesn't look particular devour-action-popup-message-fail-target-alive = You can't consume creatures that are alive! dragon-spawn-action-popup-message-fail-no-eggs = You don't have the stamina to do that! - -# Rifts -carp-rift-warning = A rift is causing an unnaturally large energy flux at {$location}. Stop it at all costs! -carp-rift-duplicate = Cannot have 2 charging rifts at the same time! -carp-rift-examine = It is [color=yellow]{$percentage}%[/color] charged! -carp-rift-max = You have reached your maximum amount of rifts -carp-rift-anchor = Rifts require a stable surface to spawn. -carp-rift-proximity = Too close to a nearby rift! Need to be at least {$proximity}m away. -carp-rift-space-proximity = Too close to space! Need to be at least {$proximity}m away. -carp-rift-weakened = You are unable to summon more rifts in your weakened state. -carp-rift-destroyed = A rift has been destroyed! You are now weakened temporarily. - -# Round end -dragon-round-end-summary = The dragons were: -dragon-round-end-dragon = {$name} with {$count} rifts -dragon-round-end-dragon-player = {$name} ({$player}) with {$count} rifts diff --git a/Resources/Locale/en-US/dragon/dragon.ftl b/Resources/Locale/en-US/dragon/dragon.ftl new file mode 100644 index 00000000000..11e8a586203 --- /dev/null +++ b/Resources/Locale/en-US/dragon/dragon.ftl @@ -0,0 +1,5 @@ +dragon-round-end-agent-name = dragon + +objective-issuer-dragon = [color=#7567b6]Space Dragon[/color] + +dragon-role-briefing = Summon 3 carp rifts and take over this quadrant! diff --git a/Resources/Locale/en-US/dragon/rifts.ftl b/Resources/Locale/en-US/dragon/rifts.ftl new file mode 100644 index 00000000000..5ad061abf96 --- /dev/null +++ b/Resources/Locale/en-US/dragon/rifts.ftl @@ -0,0 +1,9 @@ +carp-rift-warning = A rift is causing an unnaturally large energy flux at {$location}. Stop it at all costs! +carp-rift-duplicate = Cannot have 2 charging rifts at the same time! +carp-rift-examine = It is [color=yellow]{$percentage}%[/color] charged! +carp-rift-max = You have reached your maximum amount of rifts +carp-rift-anchor = Rifts require a stable surface to spawn. +carp-rift-proximity = Too close to a nearby rift! Need to be at least {$proximity}m away. +carp-rift-space-proximity = Too close to space! Need to be at least {$proximity}m away. +carp-rift-weakened = You are unable to summon more rifts in your weakened state. +carp-rift-destroyed = A rift has been destroyed! You are now weakened temporarily. diff --git a/Resources/Locale/en-US/objectives/conditions/carp-rifts.ftl b/Resources/Locale/en-US/objectives/conditions/carp-rifts.ftl new file mode 100644 index 00000000000..6010473c552 --- /dev/null +++ b/Resources/Locale/en-US/objectives/conditions/carp-rifts.ftl @@ -0,0 +1,2 @@ +objective-carp-rifts-title = Open {$count} carp rifts +objective-carp-rifts-description = Use the rift action to open {$count} rifts and ensure they do not get destroyed. If you don't open a rift after 5 minutes, you get killed. diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml index 398d1010217..368d1846925 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml @@ -133,6 +133,8 @@ spawnsLeft: 2 spawnsProto: MobCarpDragon spawnRiftAction: ActionSpawnRift + - type: GenericAntag + rule: Dragon - type: GuideHelp guides: - MinorAntagonists diff --git a/Resources/Prototypes/Entities/Structures/Specific/dragon.yml b/Resources/Prototypes/Entities/Structures/Specific/dragon.yml index 9c9b09c7c71..8a7f13d1a45 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/dragon.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/dragon.yml @@ -5,35 +5,43 @@ placement: mode: SnapgridCenter components: - - type: DragonRift - - type: Transform - anchored: true - - type: Physics - bodyType: Static - canCollide: false - - type: Fixtures - - type: Sprite - layers: - - sprite: Structures/Specific/carp_rift.rsi - state: icon - color: "#569fff" - shader: unshaded - - type: InteractionOutline - - type: Clickable - - type: PointLight - enabled: true - color: "#366db5" - radius: 10.0 - energy: 5.0 - netsync: false - - type: Damageable - damageContainer: Inorganic - damageModifierSet: Metallic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 300 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] + - type: DragonRift + - type: Transform + anchored: true + - type: Physics + bodyType: Static + canCollide: false + - type: Fixtures + - type: Sprite + layers: + - sprite: Structures/Specific/carp_rift.rsi + state: icon + color: "#569fff" + shader: unshaded + - type: InteractionOutline + - type: Clickable + - type: PointLight + enabled: true + color: "#366db5" + radius: 10.0 + energy: 5.0 + netsync: false + - type: NavMapBeacon + color: "#ff0000" + text: carp rift + # only show after making the announcement at 50% + enabled: false + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: EmitSoundOnSpawn + sound: + path: /Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 0bfba08c734..2aa046035ca 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -68,13 +68,14 @@ - type: entity parent: BaseGameRule - id: Dragon + id: DragonSpawn noSpawn: true components: - type: StationEvent weight: 5 duration: 1 earliestStart: 45 + reoccurrenceDelay: 60 minimumPlayers: 20 - type: RandomSpawnRule prototype: SpawnPointGhostDragon diff --git a/Resources/Prototypes/GameRules/midround.yml b/Resources/Prototypes/GameRules/midround.yml index 1927cde53c3..d7dff95b51e 100644 --- a/Resources/Prototypes/GameRules/midround.yml +++ b/Resources/Prototypes/GameRules/midround.yml @@ -15,3 +15,15 @@ - NinjaSurviveObjective - type: NinjaRule threats: NinjaThreats + +# stores configuration for dragon +- type: entity + noSpawn: true + parent: BaseGameRule + id: Dragon + components: + - type: GenericAntagRule + agentName: dragon-round-end-agent-name + objectives: + - CarpRiftsObjective + - DragonSurviveObjective diff --git a/Resources/Prototypes/Objectives/dragon.yml b/Resources/Prototypes/Objectives/dragon.yml new file mode 100644 index 00000000000..2cf7eb292f7 --- /dev/null +++ b/Resources/Prototypes/Objectives/dragon.yml @@ -0,0 +1,42 @@ +- type: entity + abstract: true + parent: BaseObjective + id: BaseDragonObjective + components: + - type: Objective + # difficulty isn't used at all since objective are fixed + difficulty: 1.5 + issuer: dragon + - type: RoleRequirement + roles: + components: + - DragonRole + +- type: entity + noSpawn: true + parent: BaseDragonObjective + id: CarpRiftsObjective + components: + - type: Objective + icon: + sprite: Structures/Specific/carp_rift.rsi + state: icon_blue + - type: NumberObjective + # dragon can only spawn 3 rifts so keep objective the same + min: 3 + max: 3 + title: objective-carp-rifts-title + description: objective-carp-rifts-description + - type: CarpRiftsCondition + +- type: entity + noSpawn: true + parent: [BaseDragonObjective, BaseSurviveObjective] + id: DragonSurviveObjective + name: Survive + description: You have to stay alive to maintain control. + components: + - type: Objective + icon: + sprite: Mobs/Aliens/Carps/dragon.rsi + state: alive diff --git a/Resources/Textures/Structures/Specific/carp_rift.rsi/icon_blue.png b/Resources/Textures/Structures/Specific/carp_rift.rsi/icon_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..5d55d70b4817f81ca09c6ac98640e5e9c3a2792b GIT binary patch literal 8326 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 UKkhC7|LR2SCOBFju$n9VKQyPEy8r+H literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json b/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json index 2567d69886b..76699055fb2 100644 --- a/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json +++ b/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/blob/19da0cee1869bad0186d54d6bcd8a55ed30b9db6/icons/obj/carp_rift.dmi", + "copyright": "Taken from tgstations at https://github.com/tgstation/tgstation/blob/19da0cee1869bad0186d54d6bcd8a55ed30b9db6/icons/obj/carp_rift.dmi. icon_blue recolored by deltanedas (github)", "size": { "x": 32, "y": 32 @@ -16,6 +16,16 @@ 0.2 ] ] + }, + { + "name": "icon_blue", + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ] + ] } ] -} \ No newline at end of file +} From 0fa2773a64fe304a2a01c555c85e74ffcddde9ae Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 30 Sep 2023 16:19:06 -0400 Subject: [PATCH 75/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 54a8a3dbc68..67da2b81244 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Flareguy - changes: - - {message: The smartfridge now uses its old sprites., type: Tweak} - id: 4429 - time: '2023-08-04T18:29:43.0000000+00:00' - author: MilenVolf changes: - {message: Moths now have proper creampied texture! Honk!, type: Tweak} @@ -2961,3 +2956,9 @@ Entries: - {message: Holofans can now be destroyed by explosions., type: Fix} id: 4928 time: '2023-09-30T19:08:09.0000000+00:00' +- author: deltanedas + changes: + - {message: 'Space dragons get a proper greentext in the round end summary, along + with objectives in the character menu.', type: Tweak} + id: 4929 + time: '2023-09-30T20:18:02.0000000+00:00' From ea865c2715ae95d11b441fef6bf18734f4400077 Mon Sep 17 00:00:00 2001 From: drteaspoon420 <87363733+drteaspoon420@users.noreply.github.com> Date: Sat, 30 Sep 2023 23:21:07 +0300 Subject: [PATCH 76/98] Added generic empty liquids tank (#20563) --- .../Structures/Storage/Tanks/tanks.yml | 23 +++++++++++++++++- .../Storage/tanks.rsi/generictank-1.png | Bin 0 -> 1077 bytes .../Structures/Storage/tanks.rsi/meta.json | 3 +++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Structures/Storage/tanks.rsi/generictank-1.png diff --git a/Resources/Prototypes/Entities/Structures/Storage/Tanks/tanks.yml b/Resources/Prototypes/Entities/Structures/Storage/Tanks/tanks.yml index f4269b1fab3..5f3b841565d 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Tanks/tanks.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Tanks/tanks.yml @@ -156,4 +156,25 @@ - type: ExaminableSolution solution: tank - type: ReagentTank - transferAmount: 100 \ No newline at end of file + transferAmount: 100 + +- type: entity + id: GenericTank + parent: StorageTank + suffix: Empty + components: + - type: StaticPrice + price: 500 + - type: Sprite + sprite: Structures/Storage/tanks.rsi + layers: + - state: generictank-1 + - state: watertank-2-1 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false + - type: Appearance + - type: SolutionContainerVisuals + maxFillLevels: 5 + fillBaseName: watertank-2- + - type: ExaminableSolution + solution: tank diff --git a/Resources/Textures/Structures/Storage/tanks.rsi/generictank-1.png b/Resources/Textures/Structures/Storage/tanks.rsi/generictank-1.png new file mode 100644 index 0000000000000000000000000000000000000000..238e0733abd5f98161e060976df81e87465cce22 GIT binary patch literal 1077 zcmV-51j_q~P)Px&?@2^KR9J=WmR(O9R}h9DQz$l29Ip)+Hc5kQK$e$aDq1L2dl5^KS|Mab+`tb^ zZYZ*%R86TMQldm{V>J%gasgXJDo)nm4?aR-(yH4Fx~IGLu7gSL+E+T#?#!7p@6Mc= zS@<9SbvW!4v#|xuPIo(g(_}Y2H7WM``~hyqZ#rgU3tCali9L^g`q|P~tDWJI;o9?uR!>UQLI^!XnC7+b+3%NSLWAr zmQSx=BcDt%G&3J>6d^?!wNurhjsSqVSGL^ze7D?Ce;!y8&@s>}H8eKn{=Bff14euj z4vH_Yh2-^7E*0ND0e_E#3Ort3<<(9mrpr4nhT}0rp?K75Fe?fP?b>~(rmr0P`*mQ(PhPAb|l*nxNxiD86;)R!k>!_m2a%vs(lpcJxmq0uW1YY~uEK>JGj8!;cK~_nTx^ z`=F)~g-3?9Kxl$LyM1WY*EpQ6Is;wadRQcvN#OQ)&Qx}()H(;13h9kalTT3v;gMnO z#@rkLT_^kW$d?Ez3O$!U7AvSI^vIX!I@t$cFgWy9$41D6!P?CRq96*B%czEMtPEaDhSv?^mCnM zOPd>acPCCch~)QEIXn`ZJ>4HsR#mF`EC+|jsK5V4Yg-$&v%m@~D=SD|AKTe2+#Zh@ zPA%~7q#Ee&Cznak?v<(Lvy`4~^H;ejR_WO`)qIwAuS_nJpx1wT(+h=N)3TH4m0=u8 zb*(rMn!w?7(e9OTI9+v1mj^-%UfSgyk%#=Ce4QE+oGnM@OevlHZTR z>7ts?n)cV$d@UO3>n>qY&Cxsf^=S&KuT8pAxyVT=PrFy9xcR-fc<%yJ1oTjyB?VS? zcF^@!`%DDJBV$NjAL)Bb4O5W5w`BVI+7Q<|()CuUu$+cE2|E~_OI}}HBLYlgS}$?q zbhIR}w77`gj?Xg5jL!7#XC!Bok4MH>T3oENt!qU3jBgfpwnn-BY-~iP2$V}j27^OQ z|K%84tuYlwx!t)U0*W%q!w2`9a(o_q@#R;fQtKiDq9uk$hBckN)!cp;G&)<9q1)qO vVPPIc8MXa;IWNw9_Vm=G_C9{Kn>qV$7)H~Zq82Ya00000NkvXXu0mjfe69O! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/tanks.rsi/meta.json b/Resources/Textures/Structures/Storage/tanks.rsi/meta.json index 5dfa9273d1a..93b557cf5a2 100644 --- a/Resources/Textures/Structures/Storage/tanks.rsi/meta.json +++ b/Resources/Textures/Structures/Storage/tanks.rsi/meta.json @@ -114,6 +114,9 @@ }, { "name": "watercooler-2-4" + }, + { + "name": "generictank-1" } ] } From 05f8198bfa6c275821649b814b423807f020ce15 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Sat, 30 Sep 2023 13:22:07 -0700 Subject: [PATCH 77/98] Move view variables verb to the top of the list with no category and localize it (#20546) --- .../Administration/Systems/AdminVerbSystem.cs | 5 ++--- Content.Shared/Verbs/Verb.cs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Content.Client/Administration/Systems/AdminVerbSystem.cs b/Content.Client/Administration/Systems/AdminVerbSystem.cs index d08ebc0fcef..e0f84bc4f03 100644 --- a/Content.Client/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Client/Administration/Systems/AdminVerbSystem.cs @@ -24,10 +24,9 @@ private void AddAdminVerbs(GetVerbsEvent args) // View variables verbs if (_clientConGroupController.CanViewVar()) { - Verb verb = new() + var verb = new VvVerb() { - Category = VerbCategory.Debug, - Text = "View Variables", + Text = Loc.GetString("view-variables"), Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/vv.svg.192dpi.png")), Act = () => _clientConsoleHost.ExecuteCommand($"vv {GetNetEntity(args.Target)}"), ClientExclusive = true // opening VV window is client-side. Don't ask server to run this verb. diff --git a/Content.Shared/Verbs/Verb.cs b/Content.Shared/Verbs/Verb.cs index 33576b6b9c7..76ed2073075 100644 --- a/Content.Shared/Verbs/Verb.cs +++ b/Content.Shared/Verbs/Verb.cs @@ -1,7 +1,7 @@ -using Robust.Shared.Serialization; -using Robust.Shared.Utility; using Content.Shared.Database; using Content.Shared.Interaction.Events; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared.Verbs { @@ -215,6 +215,7 @@ public int CompareTo(object? obj) public static List VerbTypes = new() { typeof(Verb), + typeof(VvVerb), typeof(InteractionVerb), typeof(UtilityVerb), typeof(InnateVerb), @@ -225,6 +226,16 @@ public int CompareTo(object? obj) }; } + /// + /// View variables verbs. + /// + /// Currently only used for the verb that opens the view variables panel. + [Serializable, NetSerializable] + public sealed class VvVerb : Verb + { + public override int TypePriority => int.MaxValue; + } + /// /// Primary interaction verbs. This includes both use-in-hand and interacting with external entities. /// From e033de414cba1f23a5e6f8f94981060bc9c7f2e9 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 30 Sep 2023 22:47:41 +0100 Subject: [PATCH 78/98] saltern update (#20325) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Maps/saltern.yml | 550 ++++++++++++++++++++++++++++++++----- 1 file changed, 476 insertions(+), 74 deletions(-) diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml index 8a8818d91eb..36f6a9a987d 100644 --- a/Resources/Maps/saltern.yml +++ b/Resources/Maps/saltern.yml @@ -206,7 +206,7 @@ entities: version: 6 -3,-2: ind: -3,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAGgAAAAAAGgAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAGgAAAAADGgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAbQAAAAACbQAAAAABbQAAAAACbQAAAAABbQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAbQAAAAAAbQAAAAABbQAAAAACbQAAAAACbQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAbQAAAAAAbQAAAAACbQAAAAABbQAAAAABbQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAbQAAAAABbQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAcAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAcAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAcAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAA + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAGgAAAAAAGgAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAGgAAAAADGgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAbQAAAAACbQAAAAABbQAAAAACbQAAAAABbQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAbQAAAAAAbQAAAAABbQAAAAACbQAAAAACbQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAbQAAAAAAbQAAAAACbQAAAAABbQAAAAABbQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAbQAAAAABbQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAcAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAcAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAOwAAAAAAOwAAAAAAOwAAAAAAcAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAA version: 6 -3,-3: ind: -3,-3 @@ -884,42 +884,43 @@ entities: 7,4: 0: 65535 7,5: - 0: 65535 + 0: 65471 + 2: 64 7,6: 0: 61422 8,4: 0: 65535 8,5: 0: 48063 - 2: 17472 + 3: 17472 8,6: 0: 65535 9,4: 0: 65535 9,5: 0: 43695 - 3: 4368 - 4: 17472 + 4: 4368 + 5: 17472 9,6: 0: 8191 10,4: 0: 65535 10,5: 0: 43695 - 4: 4368 - 5: 17472 + 5: 4368 + 6: 17472 11,4: 0: 65535 11,5: 0: 43695 - 4: 21840 + 5: 21840 12,4: 0: 65535 12,5: 0: 13183 13,4: 0: 65399 - 4: 136 + 5: 136 13,5: 0: 7 -8,7: @@ -1024,7 +1025,7 @@ entities: 0: 62463 13,3: 0: 32755 - 4: 32768 + 5: 32768 14,0: 0: 65535 14,2: @@ -1378,6 +1379,21 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.14996 + moles: + - 20.078888 + - 75.53487 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - volume: 2500 temperature: 293.15 moles: @@ -4320,11 +4336,25 @@ entities: pos: 32.5,19.5 parent: 31 type: Transform + - links: + - 11307 + type: DeviceLinkSink + - linkedPorts: + 11306: + - DoorStatus: InputB + type: DeviceLinkSource - uid: 9068 components: - pos: 31.5,18.5 parent: 31 type: Transform + - links: + - 11306 + type: DeviceLinkSink + - linkedPorts: + 11307: + - DoorStatus: InputB + type: DeviceLinkSource - proto: AirlockExternalGlassCargoLocked entities: - uid: 6522 @@ -4332,11 +4362,25 @@ entities: - pos: 29.5,20.5 parent: 31 type: Transform + - links: + - 11306 + type: DeviceLinkSink + - linkedPorts: + 11307: + - DoorStatus: InputA + type: DeviceLinkSource - uid: 9067 components: - pos: 31.5,23.5 parent: 31 type: Transform + - links: + - 11307 + type: DeviceLinkSink + - linkedPorts: + 11306: + - DoorStatus: InputA + type: DeviceLinkSource - uid: 10094 components: - rot: 1.5707963267948966 rad @@ -4351,47 +4395,103 @@ entities: pos: 58.5,7.5 parent: 31 type: Transform + - links: + - 175 + type: DeviceLinkSink + - linkedPorts: + 175: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 145 components: - rot: 3.141592653589793 rad pos: -24.5,24.5 parent: 31 type: Transform + - links: + - 151 + type: DeviceLinkSink + - linkedPorts: + 151: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 151 components: - rot: 3.141592653589793 rad pos: -26.5,24.5 parent: 31 type: Transform + - links: + - 145 + type: DeviceLinkSink + - linkedPorts: + 145: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 172 components: - rot: 3.141592653589793 rad pos: 17.5,-31.5 parent: 31 type: Transform + - links: + - 173 + type: DeviceLinkSink + - linkedPorts: + 173: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 173 components: - rot: 3.141592653589793 rad pos: 15.5,-30.5 parent: 31 type: Transform + - links: + - 172 + type: DeviceLinkSink + - linkedPorts: + 172: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 174 components: - rot: 3.141592653589793 rad pos: 53.5,8.5 parent: 31 type: Transform + - links: + - 9974 + type: DeviceLinkSink + - linkedPorts: + 9974: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 175 components: - rot: 3.141592653589793 rad pos: 61.5,7.5 parent: 31 type: Transform + - links: + - 72 + type: DeviceLinkSink + - linkedPorts: + 72: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 9974 components: - pos: 53.5,4.5 parent: 31 type: Transform + - links: + - 174 + type: DeviceLinkSink + - linkedPorts: + 174: + - DoorStatus: DoorBolt + type: DeviceLinkSource - proto: AirlockExternalGlassLocked entities: - uid: 182 @@ -4400,22 +4500,50 @@ entities: pos: -24.5,-32.5 parent: 31 type: Transform + - links: + - 183 + type: DeviceLinkSink + - linkedPorts: + 183: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 183 components: - rot: 3.141592653589793 rad pos: -21.5,-32.5 parent: 31 type: Transform + - links: + - 182 + type: DeviceLinkSink + - linkedPorts: + 182: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 1594 components: - pos: 16.5,19.5 parent: 31 type: Transform + - links: + - 2465 + type: DeviceLinkSink + - linkedPorts: + 2465: + - DoorStatus: DoorBolt + type: DeviceLinkSource - uid: 2465 components: - pos: 16.5,22.5 parent: 31 type: Transform + - links: + - 1594 + type: DeviceLinkSink + - linkedPorts: + 1594: + - DoorStatus: DoorBolt + type: DeviceLinkSource - proto: AirlockExternalGlassShuttleArrivals entities: - uid: 1755 @@ -6385,6 +6513,8 @@ entities: - pos: -22.5,-21.5 parent: 31 type: Transform + - storageUsed: 5 + type: Storage - containers: storagebase: !type:Container showEnts: False @@ -6601,6 +6731,8 @@ entities: - pos: -35.410393,-24.380575 parent: 31 type: Transform + - storageUsed: 1 + type: Storage - containers: storagebase: !type:Container showEnts: False @@ -16104,6 +16236,13 @@ entities: - pos: 3.5,-24.5 parent: 31 type: Transform + - uid: 11270 + components: + - pos: 36.5,14.5 + parent: 31 + type: Transform + - enabled: True + type: AmbientSound - uid: 11274 components: - pos: -24.5,-15.5 @@ -30493,6 +30632,46 @@ entities: - pos: 16.5,-29.5 parent: 31 type: Transform +- proto: CrateEngineeringSecure + entities: + - uid: 11305 + components: + - desc: Stores logic gates that control the salvage-atmos airlocks. + name: logic gate crate + type: MetaData + - pos: 30.5,21.5 + parent: 31 + type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage + - containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 11306 + - 11307 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + type: ContainerContainer - proto: CrateFilledSpawner entities: - uid: 1637 @@ -51578,6 +51757,46 @@ entities: - pos: 54.5,-1.5 parent: 31 type: Transform +- proto: LogicGate + entities: + - uid: 11306 + components: + - flags: InContainer + type: MetaData + - parent: 11305 + type: Transform + - links: + - 9067 + - 3052 + type: DeviceLinkSink + - linkedPorts: + 6522: + - Output: DoorBolt + 9068: + - Output: DoorBolt + type: DeviceLinkSource + - canCollide: False + type: Physics + - type: InsideEntityStorage + - uid: 11307 + components: + - flags: InContainer + type: MetaData + - parent: 11305 + type: Transform + - links: + - 6522 + - 9068 + type: DeviceLinkSink + - linkedPorts: + 3052: + - Output: DoorBolt + 9067: + - Output: DoorBolt + type: DeviceLinkSource + - canCollide: False + type: Physics + - type: InsideEntityStorage - proto: MachineAnomalyGenerator entities: - uid: 6098 @@ -72226,147 +72445,330 @@ entities: type: Transform - location: library type: WarpPoint - - uid: 1208 + - uid: 7640 components: - - pos: -36.5,5.5 + - pos: 49.5,-24.5 parent: 31 type: Transform - - location: evac + - location: observatory type: WarpPoint - - uid: 7275 +- proto: WarpPointBeaconBar + entities: + - uid: 6995 components: - - pos: -18.5,-0.5 + - pos: -7.5,12.5 parent: 31 type: Transform - - location: botany + - text: security + type: NavMapBeacon + - location: security type: WarpPoint - - uid: 7276 + - type: BombingTarget + - uid: 11267 components: - - pos: 33.5,4.5 + - pos: -12.5,19.5 parent: 31 type: Transform - - location: engineering + - text: armory + type: NavMapBeacon + - location: armory type: WarpPoint - - uid: 7640 + - type: BombingTarget + - uid: 11319 components: - - pos: 49.5,-24.5 + - pos: -17.5,9.5 parent: 31 type: Transform - - location: observatory - type: WarpPoint - - uid: 8316 + - text: permabrig + type: NavMapBeacon + - uid: 11320 components: - - pos: -36.5,15.5 + - pos: -10.5,8.5 parent: 31 type: Transform - - location: chapel - type: WarpPoint - - uid: 11268 + - text: cells + type: NavMapBeacon + - uid: 11321 components: - - pos: -47.5,-10.5 + - pos: -13.5,15.5 parent: 31 type: Transform - - location: arrivals - type: WarpPoint - - uid: 11270 + - text: locker room + type: NavMapBeacon +- proto: WarpPointBeaconCargo + entities: + - uid: 2142 components: - - pos: -25.5,-5.5 + - pos: 27.5,19.5 parent: 31 type: Transform - - location: dorms + - text: salvage + type: NavMapBeacon + - type: BombingTarget + - uid: 5767 + components: + - pos: 14.5,10.5 + parent: 31 + type: Transform + - location: cargo type: WarpPoint -- proto: WarpPointBombing + - type: BombingTarget + - uid: 11324 + components: + - pos: 21.5,17.5 + parent: 31 + type: Transform + - text: cargo bay + type: NavMapBeacon +- proto: WarpPointBeaconCommand entities: - - uid: 538 + - uid: 7262 components: - - pos: 3.5,30.5 + - pos: 9.5,19.5 parent: 31 type: Transform - - location: bridge + - text: hop's office + type: NavMapBeacon + - location: hop's office type: WarpPoint - - uid: 1136 + - type: BombingTarget + - uid: 7281 components: - - pos: 27.5,19.5 + - pos: 12.5,24.5 parent: 31 type: Transform - - location: salvage + - text: captain's room + type: NavMapBeacon + - location: captain's room type: WarpPoint - - uid: 2142 + - type: BombingTarget + - uid: 7954 components: - - pos: 14.5,10.5 + - pos: 3.5,30.5 parent: 31 type: Transform - - location: cargo + - text: bridge + type: NavMapBeacon + - location: bridge type: WarpPoint - - uid: 5767 + - type: BombingTarget + - uid: 11269 components: - - pos: -7.5,12.5 + - pos: -1.5,17.5 parent: 31 type: Transform - - location: security + - text: vault + type: NavMapBeacon + - location: vault type: WarpPoint - - uid: 6995 + - type: BombingTarget +- proto: WarpPointBeaconEngineering + entities: + - uid: 7256 + components: + - pos: 33.5,4.5 + parent: 31 + type: Transform + - text: engineering lobby + type: NavMapBeacon + - uid: 7261 components: - pos: 48.5,8.5 parent: 31 type: Transform - - location: ame - type: WarpPoint - - uid: 7256 + - text: ame + type: NavMapBeacon + - type: BombingTarget + - uid: 8316 components: - - pos: -4.5,-1.5 + - pos: 38.5,15.5 parent: 31 type: Transform - - location: bar + - text: atmospherics + type: NavMapBeacon + - location: atmospherics type: WarpPoint - - uid: 7261 + - type: BombingTarget + - uid: 11313 components: - - pos: 9.5,19.5 + - pos: 32.5,-2.5 parent: 31 type: Transform - - location: hop's office + - text: locker room + type: NavMapBeacon + - uid: 11314 + components: + - pos: 47.5,4.5 + parent: 31 + type: Transform + - text: materials + type: NavMapBeacon + - uid: 11315 + components: + - pos: 58.5,2.5 + parent: 31 + type: Transform + - text: particle accelerator + type: NavMapBeacon + - uid: 11325 + components: + - pos: 27.5,1.5 + parent: 31 + type: Transform + - text: drone closet + type: NavMapBeacon +- proto: WarpPointBeaconMedical + entities: + - uid: 9712 + components: + - pos: 16.5,-8.5 + parent: 31 + type: Transform + - type: BombingTarget + - uid: 11309 + components: + - pos: 9.5,-1.5 + parent: 31 + type: Transform + - text: medical lobby + type: NavMapBeacon + - uid: 11310 + components: + - pos: 8.5,-15.5 + parent: 31 + type: Transform + - text: cryo + type: NavMapBeacon + - uid: 11311 + components: + - pos: 13.5,-16.5 + parent: 31 + type: Transform + - text: morgue + type: NavMapBeacon + - uid: 11312 + components: + - pos: 16.5,-0.5 + parent: 31 + type: Transform + - text: chemistry + type: NavMapBeacon + - uid: 11323 + components: + - pos: 21.5,-6.5 + parent: 31 + type: Transform + - text: locker room + type: NavMapBeacon +- proto: WarpPointBeaconNeutral + entities: + - uid: 538 + components: + - pos: -36.5,5.5 + parent: 31 + type: Transform + - text: evac + type: NavMapBeacon + - location: evac type: WarpPoint - - uid: 7262 + - uid: 7276 components: - - pos: 12.5,24.5 + - pos: -47.5,-10.5 parent: 31 type: Transform - - location: captain's room + - text: arrivals + type: NavMapBeacon + - location: arrivals type: WarpPoint - uid: 7280 components: - - pos: 16.5,-8.5 + - pos: -25.5,-5.5 parent: 31 type: Transform - - location: medical + - text: dorms + type: NavMapBeacon + - location: dorms type: WarpPoint - - uid: 7281 + - uid: 11322 components: - - pos: 38.5,15.5 + - pos: 8.5,9.5 parent: 31 type: Transform - - location: atmospherics + - text: eva + type: NavMapBeacon + - location: eva type: WarpPoint - - uid: 10539 + - type: BombingTarget +- proto: WarpPointBeaconScience + entities: + - uid: 11316 components: - - pos: -9.5,-20.5 + - pos: -9.5,-29.5 parent: 31 type: Transform - - location: science - type: WarpPoint - - uid: 11267 + - text: xenoarch/anomalies + type: NavMapBeacon + - uid: 11317 components: - - pos: -12.5,19.5 + - pos: -1.5,-28.5 parent: 31 type: Transform - - location: armory + - text: robotics + type: NavMapBeacon + - uid: 11318 + components: + - pos: -15.5,-22.5 + parent: 31 + type: Transform + - text: research & development + type: NavMapBeacon +- proto: WarpPointBeaconService + entities: + - uid: 1136 + components: + - pos: -4.5,-1.5 + parent: 31 + type: Transform + - text: bar + type: NavMapBeacon + - uid: 1208 + components: + - pos: -18.5,-0.5 + parent: 31 + type: Transform + - text: botany + type: NavMapBeacon + - uid: 7275 + components: + - pos: -36.5,15.5 + parent: 31 + type: Transform + - text: chapel + type: NavMapBeacon + - location: chapel type: WarpPoint - - uid: 11269 + - uid: 11268 components: - - pos: -1.5,17.5 + - pos: -11.5,-0.5 parent: 31 type: Transform - - location: vault + - text: kitchen + type: NavMapBeacon + - uid: 11308 + components: + - pos: -18.5,-7.5 + parent: 31 + type: Transform + - text: theatre + type: NavMapBeacon +- proto: WarpPointBombing + entities: + - uid: 10539 + components: + - pos: -9.5,-20.5 + parent: 31 + type: Transform + - location: science type: WarpPoint - proto: WaterCooler entities: From a17b0423cd825136944088c27aa28c1e5a5b419c Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 2 Oct 2023 01:25:06 +1100 Subject: [PATCH 79/98] Fix followers leaking (#20643) --- Content.Shared/Follower/FollowerSystem.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index 339136ffe81..38c0e5ada3f 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -33,6 +33,8 @@ public override void Initialize() SubscribeLocalEvent>(OnGetAlternativeVerbs); SubscribeLocalEvent(OnFollowerMove); SubscribeLocalEvent(OnPullStarted); + SubscribeLocalEvent(OnFollowerTerminating); + SubscribeLocalEvent(OnGotEquippedHand); SubscribeLocalEvent(OnFollowedTerminating); SubscribeLocalEvent(OnBeforeSave); @@ -107,6 +109,11 @@ private void OnGotEquippedHand(EntityUid uid, FollowerComponent component, GotEq StopFollowingEntity(uid, component.Following, deparent:false); } + private void OnFollowerTerminating(EntityUid uid, FollowerComponent component, ref EntityTerminatingEvent args) + { + StopFollowingEntity(uid, component.Following, deparent: false); + } + // Since we parent our observer to the followed entity, we need to detach // before they get deleted so that we don't get recursively deleted too. private void OnFollowedTerminating(EntityUid uid, FollowedComponent component, ref EntityTerminatingEvent args) @@ -186,7 +193,7 @@ public void StopFollowingEntity(EntityUid uid, EntityUid target, FollowedCompone RaiseLocalEvent(uid, uidEv, true); RaiseLocalEvent(target, targetEv, false); - Dirty(followed); + Dirty(target, followed); RaiseLocalEvent(uid, uidEv); RaiseLocalEvent(target, targetEv); From 91dded60f363f37d39f87dbc9c4893becc6e8e60 Mon Sep 17 00:00:00 2001 From: Ubaser <134914314+UbaserB@users.noreply.github.com> Date: Mon, 2 Oct 2023 01:28:14 +1100 Subject: [PATCH 80/98] Add Winter Boots (#20622) * add * fix prototype --- .../Inventories/winterdrobe.yml | 1 + .../Entities/Clothing/Shoes/boots.yml | 13 +++++++++ .../Boots/winterboots.rsi/equipped-FEET.png | Bin 0 -> 1548 bytes .../Shoes/Boots/winterboots.rsi/icon.png | Bin 0 -> 1543 bytes .../Boots/winterboots.rsi/inhand-left.png | Bin 0 -> 1372 bytes .../Boots/winterboots.rsi/inhand-right.png | Bin 0 -> 1368 bytes .../Shoes/Boots/winterboots.rsi/meta.json | 26 ++++++++++++++++++ 7 files changed, 40 insertions(+) create mode 100644 Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/equipped-FEET.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/meta.json diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml index 55144b606e0..11e992adfb5 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml @@ -10,6 +10,7 @@ ClothingNeckScarfStripedOrange: 3 ClothingNeckScarfStripedPurple: 3 ClothingOuterWinterCoat: 6 + ClothingShoesBootsWinter: 6 ClothingOuterCoatBomber: 3 ClothingHeadHatSantahat: 2 ClothingHeadHatXmasCrown: 2 diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml index fcd21def8af..b75a2a712ec 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml @@ -91,3 +91,16 @@ sprite: Clothing/Shoes/Boots/laceups.rsi - type: Clothing sprite: Clothing/Shoes/Boots/laceups.rsi + +- type: entity + parent: ClothingShoesBaseButcherable + id: ClothingShoesBootsWinter + name: winter boots + description: Fluffy boots to help survive even the coldest of winters. + components: + - type: Sprite + sprite: Clothing/Shoes/Boots/winterboots.rsi + - type: Clothing + sprite: Clothing/Shoes/Boots/winterboots.rsi + - type: TemperatureProtection + coefficient: 0.05 diff --git a/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/equipped-FEET.png b/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/equipped-FEET.png new file mode 100644 index 0000000000000000000000000000000000000000..6e8c884f33ace4edf3999cf0a11f478ce8ff5c7d GIT binary patch literal 1548 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/inhand-left.png b/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4754255ad5e29a991e4a3e4fc410bc2518cb7e GIT binary patch literal 1372 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F;KxA5N2eb5`33|fjKQRB%&n3*T*V3KUXg?B|j-uuOhbq ztjngt3dqb&ElE_U$j!+swyLmI0;{kBvO&W7N(x{lCE2!05xxNm&iO^D3TAo+dIm~% zTnY*bHbp6ERzWUqQ0+jTtx`rwNr9EVetCJhUb(Seeo?xG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9RfSI+_)5S5Qg7NJw!@NTVA`OYbr7a6BokUj(YqPJo62}nwmba>#&zAKL zL(2|F{{Y1<7H?InDZQ$;4(t<@B^9;J%KjL+{Mvk^?9aTn=ac6J*>ET{FfgGJMohE& zFFvf_Z*$}Qg*Rn$UbY`=KewA}u7t6F{C zkF&o|@L&J_UTN^-c8rKazTNr!(_6PiFZGG$Z;`uq?LzOt_9*z zwYsOietA24TR!tQbKzj~d*|Hc8Ce7z7;q5_-ZCwVJ5YCg-s*|J8gBR=IX8WcJjbt4 z+1&@1J@>xGzeUJ_+50Mg$A8(pU*DF#W{+Z>5LF*gYPpu_0{eox1+SzeogqdyS~0mV Xe{!Hmv!l@jRI+)x`njxgN@xNA61B+T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/inhand-right.png b/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..467a79e9fa9e9b707e2ba656389d51555e35a289 GIT binary patch literal 1368 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F;KxA5N2eb5`33|fjKQRB%&n3*T*V3KUXg?B|j-uuOhbq ztjngt3dqb&ElE_U$j!+swyLmI0;{kBvO&W7N(x{lCE2!05xxNm&iO^D3TAo+dIm~% zTnY*bHbp6ERzWUqQ0+jTtx`rwNr9EVetCJhUb(Seeo?xG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9RfSI+>)5S5Qg7NJw!@NTV5^agwU)|t4D;TiEFSeRtNfBeq1Gc@a&i;XU z3{H0zsIOSn#KIk9bz!Y{6$9HU`zsz2yZa(#y!DyO-rV^4=fF32O*;;S1_mZHqPp?w z>(hC^|86wC9a3}V&aYc%>NELHY`s%c{(r%>)8?t$nv$X~FWETZkNCC+moI*}@BD4v zytS`$s*g%=pL}m~V!{2bN8Ay2*dR2Ay-C!%DX;3h?@#sxbBN>ocXFY4y#F_wW99ze-@0t;!&X`^`6u_gVc+xltO~QQ zt=<2d>Bv0$m3+UMTCd%&{e5&EKabP0l+XkK0RPl0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/meta.json new file mode 100644 index 00000000000..e484bbb13af --- /dev/null +++ b/Resources/Textures/Clothing/Shoes/Boots/winterboots.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "drawn by Ubaser", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-FEET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} From a2e69cc4f638de1e00d7572159900aa52330f6c7 Mon Sep 17 00:00:00 2001 From: Ubaser <134914314+UbaserB@users.noreply.github.com> Date: Mon, 2 Oct 2023 01:28:47 +1100 Subject: [PATCH 81/98] Add QM mantle (#20621) * add * fix prototype --- .../Entities/Clothing/Neck/mantles.yml | 11 +++++++++++ .../Prototypes/Recipes/Lathes/clothing.yml | 9 +++++++++ .../mantles/qmmantle.rsi/equipped-NECK.png | Bin 0 -> 2021 bytes .../Neck/mantles/qmmantle.rsi/icon.png | Bin 0 -> 1678 bytes .../Neck/mantles/qmmantle.rsi/meta.json | 18 ++++++++++++++++++ 5 files changed, 38 insertions(+) create mode 100644 Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/equipped-NECK.png create mode 100644 Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml b/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml index 83ba6603f8b..c3f854e9780 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/mantles.yml @@ -63,3 +63,14 @@ sprite: Clothing/Neck/mantles/rdmantle.rsi - type: Clothing sprite: Clothing/Neck/mantles/rdmantle.rsi + +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMantleQM + name: quartermaster's mantle + description: For the master of goods and materials to rule over the department, a befitting mantle to show off superiority! + components: + - type: Sprite + sprite: Clothing/Neck/mantles/qmmantle.rsi + - type: Clothing + sprite: Clothing/Neck/mantles/qmmantle.rsi diff --git a/Resources/Prototypes/Recipes/Lathes/clothing.yml b/Resources/Prototypes/Recipes/Lathes/clothing.yml index fea18760b76..328b557460b 100644 --- a/Resources/Prototypes/Recipes/Lathes/clothing.yml +++ b/Resources/Prototypes/Recipes/Lathes/clothing.yml @@ -552,6 +552,15 @@ Cloth: 150 Durathread: 150 +- type: latheRecipe + id: ClothingNeckMantleQM + result: ClothingNeckMantleQM + completetime: 2.8 + materials: + Cloth: 150 + Durathread: 150 + + - type: latheRecipe id: ClothingOuterWinterMusician result: ClothingOuterWinterMusician diff --git a/Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/equipped-NECK.png b/Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/equipped-NECK.png new file mode 100644 index 0000000000000000000000000000000000000000..96e251430015ea0ddc4bcd0268126208014ca60b GIT binary patch literal 2021 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 W{1b!S$$Wc2b%Cd=pUXO@geCy$4{W;t literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/meta.json b/Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/meta.json new file mode 100644 index 00000000000..1b05cf9b674 --- /dev/null +++ b/Resources/Textures/Clothing/Neck/mantles/qmmantle.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "drawn by Ubaser", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-NECK", + "directions": 4 + } + ] +} \ No newline at end of file From 58f3af100891e154287c83e37d49463771cfa4b0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 10:29:53 -0400 Subject: [PATCH 82/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 67da2b81244..227efe88fba 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: MilenVolf - changes: - - {message: Moths now have proper creampied texture! Honk!, type: Tweak} - id: 4430 - time: '2023-08-04T18:31:39.0000000+00:00' -- author: metalgearsloth - changes: - - {message: Fix spear wielding., type: Fix} - id: 4431 - time: '2023-08-04T18:37:17.0000000+00:00' - author: Aleksh changes: - {message: Added laser raptors., type: Add} @@ -2962,3 +2952,13 @@ Entries: with objectives in the character menu.', type: Tweak} id: 4929 time: '2023-09-30T20:18:02.0000000+00:00' +- author: Ubaser + changes: + - {message: Winter Boots are now available in the Winterdrobe., type: Add} + id: 4930 + time: '2023-10-01T14:28:14.0000000+00:00' +- author: Ubaser + changes: + - {message: 'QM now has a mantle, available at HoP''s uniform printer.', type: Add} + id: 4931 + time: '2023-10-01T14:28:47.0000000+00:00' From c4a7b71256fe184a5e34b78662f2c760f62ea821 Mon Sep 17 00:00:00 2001 From: Nim <128169402+Nimfar11@users.noreply.github.com> Date: Sun, 1 Oct 2023 17:34:29 +0300 Subject: [PATCH 83/98] Slime mobs breathe nitrogen and resprite their organs (#20577) * Slimes breathe nitrogen and resprite their organs * ups * mmm --- .../Prototypes/Body/Organs/Animal/slimes.yml | 56 ++++++++++++++++++ Resources/Prototypes/Body/Organs/slime.yml | 8 ++- .../Body/Prototypes/Animal/slimes.yml | 18 ++++++ .../Prototypes/Entities/Mobs/NPCs/slimes.yml | 3 + .../Slime/organs.rsi/brain-inhand-left.png | Bin 0 -> 228 bytes .../Slime/organs.rsi/brain-inhand-right.png | Bin 0 -> 220 bytes .../Species/Slime/organs.rsi/brain-slime.png | Bin 0 -> 442 bytes .../Species/Slime/organs.rsi/lung-l-slime.png | Bin 0 -> 271 bytes .../Species/Slime/organs.rsi/lung-r-slime.png | Bin 0 -> 273 bytes .../Mobs/Species/Slime/organs.rsi/meta.json | 28 +++++++++ 10 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 Resources/Prototypes/Body/Organs/Animal/slimes.yml create mode 100644 Resources/Prototypes/Body/Prototypes/Animal/slimes.yml create mode 100644 Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-inhand-left.png create mode 100644 Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-inhand-right.png create mode 100644 Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-slime.png create mode 100644 Resources/Textures/Mobs/Species/Slime/organs.rsi/lung-l-slime.png create mode 100644 Resources/Textures/Mobs/Species/Slime/organs.rsi/lung-r-slime.png create mode 100644 Resources/Textures/Mobs/Species/Slime/organs.rsi/meta.json diff --git a/Resources/Prototypes/Body/Organs/Animal/slimes.yml b/Resources/Prototypes/Body/Organs/Animal/slimes.yml new file mode 100644 index 00000000000..f5d94554498 --- /dev/null +++ b/Resources/Prototypes/Body/Organs/Animal/slimes.yml @@ -0,0 +1,56 @@ +- type: entity + id: SentientSlimesCore + parent: [BaseItem, OrganHumanBrain] + name: sentient slimes core + description: "The source of incredible, unending gooeyness." + components: + - type: Sprite + sprite: Mobs/Species/Slime/organs.rsi + state: brain-slime + - type: Stomach + - type: Metabolizer + maxReagents: 3 + metabolizerTypes: [ Slime ] + removeEmpty: true + groups: + - id: Food + - id: Drink + - id: Medicine + - id: Poison + - id: Narcotic + - id: Alcohol + rateModifier: 0.2 + - type: SolutionContainerManager + solutions: + stomach: + maxVol: 30.0 + +- type: entity + id: OrganSlimesLungs + parent: BaseHumanOrgan + name: slimes gas sacs + description: "Collects nitrogen, which slime cells use for maintenance." + components: + - type: Sprite + sprite: Mobs/Species/Slime/organs.rsi + layers: + - state: lung-l-slime + - state: lung-r-slime + - type: Lung + - type: Metabolizer + removeEmpty: true + solutionOnBody: false + solution: "Lung" + metabolizerTypes: [ Slime ] + groups: + - id: Gas + rateModifier: 100.0 + - type: SolutionContainerManager + solutions: + organ: + reagents: + - ReagentId: Nutriment + Quantity: 10 + Lung: + maxVol: 100.0 + canReact: false diff --git a/Resources/Prototypes/Body/Organs/slime.yml b/Resources/Prototypes/Body/Organs/slime.yml index 4bb07da4dc2..e6ce18b335d 100644 --- a/Resources/Prototypes/Body/Organs/slime.yml +++ b/Resources/Prototypes/Body/Organs/slime.yml @@ -4,6 +4,9 @@ name: sentient slime core description: "The source of incredible, unending gooeyness." components: + - type: Sprite + sprite: Mobs/Species/Slime/organs.rsi + state: brain-slime - type: Stomach - type: Metabolizer maxReagents: 6 @@ -35,9 +38,10 @@ description: "Collects nitrogen, which slime cells use for maintenance." components: - type: Sprite + sprite: Mobs/Species/Slime/organs.rsi layers: - - state: lung-l - - state: lung-r + - state: lung-l-slime + - state: lung-r-slime - type: Lung - type: Metabolizer removeEmpty: true diff --git a/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml b/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml new file mode 100644 index 00000000000..8d9827e99a0 --- /dev/null +++ b/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml @@ -0,0 +1,18 @@ +- type: body + id: Slimes + name: "slimes" + root: torso + slots: + torso: + part: TorsoSlime + connections: + - legs + organs: + core: SentientSlimesCore + lungs: OrganSlimesLungs + legs: + part: LegsAnimal + connections: + - feet + feet: + part: FeetAnimal diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml index 85a0b2afa44..4d56face9d1 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml @@ -94,6 +94,9 @@ type: Local messages: [ "slime-hurt-by-water-popup" ] probability: 0.25 + - type: Body + prototype: Slimes + requiredLegs: 1 - type: CombatMode - type: MeleeWeapon hidden: true diff --git a/Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-inhand-left.png b/Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a536818eee96f7113aee27ab26ae8fe27c4670ce GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|=6Sj}hE&XX zdrOh8*+GEyLau4KV}ih5!S)*p+FI4irSzP&3PN(7vLrn;->(d{pFF?RSd$T`uRw45 zivxP!i!1Ga@3H#-ZO8eq7OhWfce}Nf?wr4RnQ!Rjw$y8nr+7WvbVp+$tH}F@UoTgB zKV+SfxOiXo$(x&4fF=OJga57XZ+{ml?A~y)s)j#sJ4d_jf{5K__9cuLw{tKs%sI*4 Wa6?bS*D2}*NVTV{pUXO@geCw|x>!a4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-inhand-right.png b/Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..c7e0adca9a15c579e2379a6dc8b92575977fd95c GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|rg^$JhE&XX zdutfV%1J3mb%;BjlRqUP_t$Wl51EqgkIw($l?Nhc@loS5PX>1k}Xv|7n<& z!SOB6-m4yc^mFyxv(@W&mPjl&=(+stQ@jaKe9hKXTotzRXBVz3P|M%g@JIS2hrt*<7;L0|c^@>$j|+suLT(fR*HwD^y?_W6KR Nd%F6$taD0e0sy#ZSd;(& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-slime.png b/Resources/Textures/Mobs/Species/Slime/organs.rsi/brain-slime.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a611f5118ca17bc49a42a81ccb89165e645acd GIT binary patch literal 442 zcmV;r0Y(0aP)Px$bV)=(R9J=W(=A9tQ5eSY|J;Z8u`uy#6J&^r*ffe+7_JC%hsB^^FlZ5@;EJFk zXb=n&d-6mO}AayJ*F!r*}27Xe(A#HJnzHHIiM(tqWm+L(}S^v zd0~Ga@9a9xkv_Pzwj#2Db|@BzbOyjQNu(}*{>zr}NDbeJi>$u|N+lwl0g`o%THmvw zkBeecdwhKiLfd)XUgA!^|(mkJs@xQ7 zi%goYPm7a-!yy6NyW(MO=IJHoF=5!4-Pl*+tK#E%L_ll|4npe kT1022Ykq!;q9}^(8*rVDq%>>&82|tP07*qoM6N<$f?Gq+H~;_u literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Slime/organs.rsi/lung-l-slime.png b/Resources/Textures/Mobs/Species/Slime/organs.rsi/lung-l-slime.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4591ed9bf5dc73e8ebe3d62c29c235af420396 GIT binary patch literal 271 zcmV+q0r38bP)Px#$w@>(R9J=Wlrav1KoCVA#6&HKfl7!4u{9R7R^Gkfxar&l3ElTWv9zO`F`Y$geI_b|IjX)=Hc7wk^>ij1N3W^%c%HwNb zbasqu`~2SCSc2=*q&3qg2Ay7eX*2(x2|*R=A9*Ip^_`vb%Au=H%uDtF5GZ_n(@Y*V2^5%p`CI=2QL~%`$7KJ$5Ac29QHPmfi#FDJ3 QKyNX4y85}Sb4q9e0HM-rH~;_u literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Slime/organs.rsi/meta.json b/Resources/Textures/Mobs/Species/Slime/organs.rsi/meta.json new file mode 100644 index 00000000000..cacfcdc40bb --- /dev/null +++ b/Resources/Textures/Mobs/Species/Slime/organs.rsi/meta.json @@ -0,0 +1,28 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by Nimfar11 (Github) for Space Station 14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "brain-slime" + }, + { + "name": "brain-inhand-left", + "directions": 4 + }, + { + "name": "brain-inhand-right", + "directions": 4 + }, + { + "name": "lung-l-slime" + }, + { + "name": "lung-r-slime" + } + ] +} From 05c2e1179a3fb745a23736d36c8a580a7da19bc0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 10:35:33 -0400 Subject: [PATCH 84/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 227efe88fba..9da3b6f40fc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Aleksh - changes: - - {message: Added laser raptors., type: Add} - id: 4432 - time: '2023-08-04T18:38:11.0000000+00:00' - author: Unbelievable-Salmon changes: - {message: The Syndicate gas mask now protects your eyes from welders., type: Tweak} @@ -2962,3 +2957,9 @@ Entries: - {message: 'QM now has a mantle, available at HoP''s uniform printer.', type: Add} id: 4931 time: '2023-10-01T14:28:47.0000000+00:00' +- author: Nimfar11 + changes: + - {message: Added new sprites for slime organs, type: Add} + - {message: Slimes now breathe nitrogen too., type: Tweak} + id: 4932 + time: '2023-10-01T14:34:29.0000000+00:00' From 7f46d47140a02171eb206eace41e4721d9f92d61 Mon Sep 17 00:00:00 2001 From: Ubaser <134914314+UbaserB@users.noreply.github.com> Date: Mon, 2 Oct 2023 01:50:10 +1100 Subject: [PATCH 85/98] Fix the new lizard horn's consistency + issue (#20620) * fix * add * Revert "add" This reverts commit a054a3204a8f185a94ceb80b1bd3bc9f30423711. --- .../Mobs/Customization/Markings/reptilian.yml | 2 +- .../reptilian_parts.rsi/horns_argali.png | Bin 1360 -> 1347 bytes .../reptilian_parts.rsi/horns_ayrshire.png | Bin 1273 -> 1271 bytes .../reptilian_parts.rsi/horns_bighorn.png | Bin 1430 -> 1463 bytes .../reptilian_parts.rsi/horns_myrsore.png | Bin 1294 -> 1307 bytes 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml index 60e7f346493..72da7b1d2a5 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml @@ -255,7 +255,7 @@ state: horns_myrsore - type: marking - id: LizardBighorn + id: LizardHornsBighorn bodyPart: HeadTop markingCategory: HeadTop speciesRestriction: [Reptilian] diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/horns_argali.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/horns_argali.png index f66087be661555867c760f00b77d941070e4a061..1efa87c6aa17831a5c4faf7927de04028cd5bc05 100644 GIT binary patch delta 377 zcmcb>b(m|z73TUVPZ!6K3dXm$qVt*!1X>f9zjE8Lrtz=+W{wDk9LB9yE7Uiw@sXOn zLjUhXCF$G7$@QmZdv>xn1}u2JOaJd7R)4j1N37mXm05qRZdb&Wb+4-~-!btm@2H%2 zexuE@IpK56Ca%wXX}@Z{%}=>cx8_xQ|4o!Q$GpPf{`d6w+)9JBpX+Bt<)6qseNgmq z#nyA{3%~xI_uY2-@ys`ug2gISBfWj5gzxN;U#ofie&qf$XRVny6dD-t5PyUjV{LwY z3v~~(um7*zwrSnH#Q+4Ju6{1-oD!Md31X?au2-clD@OQo?iwwg$2NP$R%O+u&f$@Jl zd~V-8ckbKd?Lnb70vD7`2`LeS_-FFJ!rW^D4Gb&_42&EO3`{tfKg5}Km4AM^ z_}rSx9sfkzZ-l>I_j*(Q;`6G!zq6v2eYOcdy~!r8$otjPtT)>EXP1Wizuxt1+N!!u zj5fQ=<&S?9F`InXwe3Lr_j2ZGug>-)pW7>SzfNJI(CGln+4qjW2{#C}7ZrbT<8naI zto27&56B1998E|M{QA&7d3j4N4ksbpT<`gSO?UQk3%16Nr>mdKI;Vst0G&Ii AZ~y=R diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/horns_ayrshire.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/horns_ayrshire.png index 0390a1fc690ff5a1d952878dbd7bfa51b9b8c4ed..6c0d0b5b93d9c64387177d5692769627625a6c3e 100644 GIT binary patch delta 275 zcmey#`JHpa73O+APZ!6K3dXlL9r>CS1RMf$tJtm;alWe;ju1Y-;H*k&<5fl;)2%=A zczDh{n0%Lq*?(_Cao*Li>5p#Rn-!s1uemS$@kaB?>pLsw&F;U)B9I)yJ>}7>XI%-W z^4FftOOnz*9W+rj{t}Bq^wU|sm%kJ;%#=TFc>Z7O#48`~rMITk2t4~W-zx6Xy*#^F z_tz!&FfdJyXOS!WF1}-t>l$cuoKS delta 252 zcmV_rD3Q4QH^;BxM1W#~3s< z{kwyiVepf#aGLn_3pnRqwd_{BR@)P6t>238^?2+}-gPd7px(L)U|rX0gI2s++!2iH z&-0v|#5mrztz(rmMFk+Ga?Gr?UmK8lV@$gG2_xy_y-ym+_{b0OKeWB5ofntp^E}1~ zAb^u$1RO-%Tp+(MJo9m`?4^2+D=sKU_fX#s*F@s=buH)DVnYDrNRECpB`86bUZeg7 z&r&1J{IV=^U!Qz4psCm93c{zSwv>F6zyu%{Rp1RtLqif8!S`7J0000kYP{i@$esGLni0hvL2gM(+^$Oqzk^Y+}Qp8XH@lD z8|lMeE_0eB`|i?XxU*KnSF36N-pMlSGtZxUU&o>-rL;(X%iZ-a`~F(hpFNh@$I;P% z1=S;q#`HO?`shAo;fIXuI#tox9)G0f`o)m6bHbTP+gjDOTW~q< zbXmd3)MhKF`Y8H`()W)dLBU%VNbh3Wc1v1!(zb{MU!EMXXN>1eeBb?YQg3itx3A)b z&Q%Gf1IexeIg5|?{7c_r$-75tVp@$N!%l~9QBU67mpc6HiGs`L_Ig%<3u;b}R@=;X zD6kibQL)#n(charr#!5>v^IThbfK#QiwiEapyL2{alq{gLuG@P3_#%N>gTe~DWM4f D7x>;k delta 461 zcmdnaJ&k+A73TW2o-U3d6^w6ZdFM47h`44>H8n^Rz4?Des6m>rN%$+*X-|)w=iB08 z>GP-Zf3q)}{^0|kZ?f!Ddg_09OYh?ytJl4@(mB29_O&Ow6Q3`6wqLDY^xHQtjhS;- zXV^D=WO(p&L8)Fn$99oR>+V?Wy#Ic-Ptbo=@s&2`*DsO37tGX@&|F{g&bIgEzGr?m zS6|LN9sX|j6ZPw!*H!<1h+DrnZnw?GxCw!~-`gbYyH=Q`>-KAt^`nay`@|ksT=HMv z@_qO5c`Un{MR}^@91ikE3p6mWC@?T`I503_XUh8~y#MH~@x<2t>;1lrM)xH9%a!K! z%U}IxmbuY*Y1!j^<}VZeGg|nau5j_Y`fh`e7VD+i;ysIZ9nfu!4&V4W_{E$>ymv2% zdfYzyzxGM&pUr{#-bM#!KHnJ?|ANKh#?|idd221(7=A=Zwj6(9xcQ%CvL<_cug4yN zhDnRRL``{8zjgWa;3k1y`G2Al4x3D1iho+k?)24F`JvL^!jHSYuDkhe&Bs?i=Z2cs fDdO~niQo^$_T`6uu9nk_VgLe9S3j3^P6@UW-h5340u2wdY?!k-${+m8_B$xGquFZKq?ax2Yu6rp z@}BJ&-`t1H;YTgq_BdQGEw7#0`!%MsIQslCL(}z!C(}>PU8b3F^w_~CjuUtSu77>4 z`{8)A)y-v3Gws_ymp;`fd=*{L{nm%;>}Q!6HGhY?_rL!M`G{~FlPWAZY@kzmrSije zoq%6^Q!bmVZv7*y88)L;aPmDCiFyGC21XVEhX*E1E3LN}norp6_UYS>T&wcrvRc{a zYo@XuF#mG4o$D9d_j9S$F>UL2PXB%K&ZhJKJU5-4s8-`_wEWwv+^lO6`A5S;pVobh zJ@kzCMVi@UF5fM=yML{9T3Dph&A`N=(145hAby>RU+b&izCC(X2@F8s>FVdQ&MBb@ E00Nwm1ONa4 delta 299 zcmbQu)yK8r3Uj@xr;B4q1>@UWhJ4KiJgpD6v?s6?vcI!0=1P0Omn-|yb72$L9EMe2 zHt%qdncZK)rC1;%{$kg=scE(Imw!L^YwfJAdshDWkM34pHaRLLviI)}##g)gRy$n0 z-JpK{-mm8!E5(Y#4kj{ao1Oo>D8HK9(pN|AcA-&UvP9d%L}%Sw^*>YHFPn7#-_Lb_ zqfp4~4hAL;g$6vtb*`9=j#0agJ-qu+_tK@_+^ZX3t7eNb1~~7O*ZxzLarbiAj;vR^ z%#YcY@w*p|ch_Gb0-+q0+V9Ssi^{k89WRo~vy@Z(F*uHm!zm~?yFYPS1Yb0Q|K hoSefVC-E=r0dGN$cN~L>{Uin;@O1TaS?83{1OWcwg@FJ7 From 5f4d67548cb0fb540c025746d602d20cc0ec059b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Urba=C5=84czyk?= Date: Sun, 1 Oct 2023 16:51:35 +0200 Subject: [PATCH 86/98] Add RandomHumanoidAppearance component to for space ninjas (#20605) --- Resources/Prototypes/Entities/Mobs/Player/human.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 985be544e5f..59990a3f7b4 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -61,6 +61,8 @@ parent: MobHuman id: MobHumanSpaceNinja components: + - type: RandomHumanoidAppearance + randomizeName: false - type: Loadout prototypes: [SpaceNinjaGear] - type: NpcFactionMember From 0080808315f6ac8f3accf25cb07773d8bea2fd7b Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 10:52:39 -0400 Subject: [PATCH 87/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9da3b6f40fc..062161e9e87 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Unbelievable-Salmon - changes: - - {message: The Syndicate gas mask now protects your eyes from welders., type: Tweak} - id: 4433 - time: '2023-08-04T18:43:25.0000000+00:00' - author: metalgearsloth changes: - {message: Allow pulling while buckled, type: Add} @@ -2963,3 +2958,8 @@ Entries: - {message: Slimes now breathe nitrogen too., type: Tweak} id: 4932 time: '2023-10-01T14:34:29.0000000+00:00' +- author: casperr04 + changes: + - {message: Space ninjas now have random appearance., type: Tweak} + id: 4933 + time: '2023-10-01T14:51:35.0000000+00:00' From f14b77dc0b8a95d1698c3e992a2f422ed1f5a060 Mon Sep 17 00:00:00 2001 From: Tox Cruize <141375638+TexCruize@users.noreply.github.com> Date: Sun, 1 Oct 2023 15:55:58 +0100 Subject: [PATCH 88/98] Space cat breathes space (#20550) * Space cat breathes space Made Space Cat lungs ROBUST * Made Space Cat's lungs ROBUST 2.0 --- Resources/Prototypes/Entities/Mobs/NPCs/animals.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 170d5e242ba..a76b68aced3 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -2108,6 +2108,8 @@ interactFailureString: petting-failure-generic interactSuccessSound: path: /Audio/Animals/cat_meow.ogg + - type: Respirator #It just works? + minSaturation: 5.0 - type: entity name: caracal cat From 137c0caedf4e8a61aba60e835f547dcec5171d5f Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 10:57:03 -0400 Subject: [PATCH 89/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 062161e9e87..2e81dd951ab 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - {message: Allow pulling while buckled, type: Add} - id: 4434 - time: '2023-08-04T18:47:52.0000000+00:00' - author: astriloqua changes: - {message: People wont hear buckling and unbuckling sounds twice anymore., type: Fix} @@ -2963,3 +2958,8 @@ Entries: - {message: Space ninjas now have random appearance., type: Tweak} id: 4933 time: '2023-10-01T14:51:35.0000000+00:00' +- author: TomCruize + changes: + - {message: Made Space Cats lungs ROBUST (They now don't suffocate in space), type: Fix} + id: 4934 + time: '2023-10-01T14:55:59.0000000+00:00' From 3cbd5b04567635759c8803fbbb765fdb7e9c6089 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sun, 1 Oct 2023 19:41:32 +0300 Subject: [PATCH 90/98] Wide anomaly locator (#20581) * Add files via upload * Add files via upload * Add files via upload * Add files via upload * add textures * fix encoding * fix 2 --- .../Objects/Specific/Research/anomaly.yml | 33 ++++++++++++++++++ .../Entities/Structures/Machines/lathe.yml | 1 + .../Prototypes/Recipes/Lathes/devices.yml | 8 +++++ .../Prototypes/Research/experimental.yml | 1 + .../Research/anomalylocatorwide.rsi/icon.png | Bin 0 -> 500 bytes .../anomalylocatorwide.rsi/inhand-left.png | Bin 0 -> 316 bytes .../anomalylocatorwide.rsi/inhand-right.png | Bin 0 -> 307 bytes .../Research/anomalylocatorwide.rsi/meta.json | 33 ++++++++++++++++++ .../anomalylocatorwide.rsi/screen.png | Bin 0 -> 258 bytes 9 files changed, 76 insertions(+) create mode 100644 Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/icon.png create mode 100644 Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/screen.png diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index b2c1f6cdcc7..e78d8dd1504 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -71,3 +71,36 @@ slots: cell_slot: name: power-cell-slot-component-slot-name-default + +- type: entity + id: AnomalyLocatorWideUnpowered + parent: AnomalyLocatorUnpowered + name: wide-spectrum anomaly locator + description: A device that looks for anomalies from an extended distance, but has no way to determine the distance to them. + suffix: Unpowered + components: + - type: Sprite + sprite: Objects/Specific/Research/anomalylocatorwide.rsi + - type: ProximityBeeper + maximumDistance: 40 + minBeepInterval: 0.5 + maxBeepInterval: 0.5 + +- type: entity + id: AnomalyLocatorWide + parent: [ AnomalyLocatorWideUnpowered, PowerCellSlotSmallItem ] + suffix: Powered + components: + - type: PowerCellDraw + drawRate: 1 + useRate: 0 + +- type: entity + id: AnomalyLocatorWideEmpty + parent: AnomalyLocatorWide + suffix: Empty + components: + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index f6fa327ac54..42c97f4f3ac 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -203,6 +203,7 @@ - MiningDrill - AnomalyScanner - AnomalyLocator + - AnomalyLocatorWide - RCD - RCDAmmo - HandheldCrewMonitor diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml index de79b975133..ed73dc1b644 100644 --- a/Resources/Prototypes/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/Recipes/Lathes/devices.yml @@ -68,6 +68,14 @@ Steel: 400 Glass: 100 +- type: latheRecipe + id: AnomalyLocatorWide + result: AnomalyLocatorWideEmpty + completetime: 3 + materials: + Steel: 400 + Glass: 100 + - type: latheRecipe id: AnomalyScanner result: AnomalyScanner diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml index c1730bb15ea..02d66c06bf7 100644 --- a/Resources/Prototypes/Research/experimental.yml +++ b/Resources/Prototypes/Research/experimental.yml @@ -26,6 +26,7 @@ recipeUnlocks: - AnomalyScanner - AnomalyLocator + - AnomalyLocatorWide - BorgModuleAnomaly - APECircuitboard - AnomalyVesselCircuitboard diff --git a/Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/icon.png b/Resources/Textures/Objects/Specific/Research/anomalylocatorwide.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fe7c1c92276c68305522f0c50de63690a294a001 GIT binary patch literal 500 zcmVPx$u1Q2eR9J=WmA^~FKorNn5eKIPp=5E0TR{qSbQ3IX2dC0@6ha;9e9hDwIrsM+*uJJ9|#=pUEcfNd&fH5`fl>>pbbg+MQVX&iVvglo0HqcPG3QA#*_7)ZIFl1% zf>LX>0-O|!Crf>$(gjm2-vab{Mc91)u$8TCNRk9fsb`NQNf=cJ7{9$hA6~BZ5(2>c zWU|tI0AmZLQ4!+40(wpnJIH$ct-Bh;V+GTVS778XCes`MfK)nfXR@iK{_C0!y2a)D?+!^0{~dfG5X~OtmYU1(Cze?PR}Kv-EPmzN8iOh&f8SzUw!cD+S;Z?oc=!FGd)KS5V-GV051KD6Ou zg~$?hE&XX zd&`i!$wA`S$L$%VU%69FyJiG;?_hab*LPrTtmB4)ua`@G*?H5#)bC#XZ~jWw=DXYu zn=YVk28M>}z&+tWbpPB(zT}&+vJSJJE-pI%Tke%}c}{1v#h1OREqT{%cbxS!Yir!8otdsK zXHxCNmVT8#VsiTGMvdhsGk!lb4KHE>TMQ(29DiER(IavD@ajR)XwmLU$#izZr#Js@X}q!RZqRWnRb5jlhx%yy9~Aer$jpK^?rWA^|VItKcllZ zjeX=3UWA`6-mDv6tE`lKF&3mB0v@cM`J3_8T%NyCOXM%y(|^fdnD_7Erj{!8(gjq@Bz^``TJHPv00R*A4HILz_+7>Mub>gTe~DWM4f!bWJ1 literal 0 HcmV?d00001 From c41b6052c2011a7819f4a9702f381a3c3d1a2293 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 12:42:36 -0400 Subject: [PATCH 91/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2e81dd951ab..3e9d23a3405 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: astriloqua - changes: - - {message: People wont hear buckling and unbuckling sounds twice anymore., type: Fix} - id: 4435 - time: '2023-08-04T22:24:21.0000000+00:00' - author: Errant changes: - {message: Gas tanks and jetpacks have reduced capacity and now need to be refilled @@ -2963,3 +2958,8 @@ Entries: - {message: Made Space Cats lungs ROBUST (They now don't suffocate in space), type: Fix} id: 4934 time: '2023-10-01T14:55:59.0000000+00:00' +- author: TheShuEd + changes: + - {message: Added wide-spectrum anomaly locator., type: Add} + id: 4935 + time: '2023-10-01T16:41:32.0000000+00:00' From 0bf2628e824b39224b0391b4d3dc5c1fc5972d20 Mon Sep 17 00:00:00 2001 From: Michael Cu <43478115+michaelcu@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:16:54 -0500 Subject: [PATCH 92/98] Fixed Telescopic Shield Lighting (#20650) * Fixed Telescopic Shield Lighting Bug fix #20199 * no need for these at all --------- Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> --- Resources/Prototypes/Entities/Objects/Shields/shields.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index ea5935957df..8afe40bfe72 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -424,7 +424,6 @@ - state: teleriot-icon - state: teleriot-on visible: false - shader: unshaded map: [ "shield" ] - type: Item size: 10 @@ -437,10 +436,8 @@ inhandVisuals: left: - state: inhand-left-shield - shader: unshaded right: - state: inhand-right-shield - shader: unshaded - type: Appearance - type: Destructible thresholds: From 88365868267ba376e3c375a7c57c6d7a2b9ebc7a Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 13:17:58 -0400 Subject: [PATCH 93/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3e9d23a3405..0742414253a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Errant - changes: - - {message: Gas tanks and jetpacks have reduced capacity and now need to be refilled - more regularly., type: Tweak} - - {message: Jetpacks now start fully filled., type: Tweak} - id: 4436 - time: '2023-08-04T22:40:42.0000000+00:00' - author: Potato1234_x changes: - {message: Added the Dr. Gibb Vendor, type: Add} @@ -2963,3 +2956,8 @@ Entries: - {message: Added wide-spectrum anomaly locator., type: Add} id: 4935 time: '2023-10-01T16:41:32.0000000+00:00' +- author: michaelcu + changes: + - {message: Telescopic Shield no longer glows in the dark when deployed., type: Fix} + id: 4936 + time: '2023-10-01T17:16:54.0000000+00:00' From a4889489ee7736d0d53c7a9d374c90bedaac4823 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 1 Oct 2023 13:36:20 -0400 Subject: [PATCH 94/98] Add a special hardsuit for nukie medic (#20471) --- .../Clothing/Head/hardsuit-helmets.yml | 25 +++++++++++ .../Clothing/OuterClothing/hardsuits.yml | 14 ++++++ .../Roles/Jobs/Fun/misc_startinggear.yml | 2 +- .../Hardsuits/syndiemedic.rsi/icon-flash.png | Bin 0 -> 851 bytes .../Head/Hardsuits/syndiemedic.rsi/icon.png | Bin 0 -> 559 bytes .../Head/Hardsuits/syndiemedic.rsi/meta.json | 41 ++++++++++++++++++ .../syndiemedic.rsi/off-equipped-HELMET.png | Bin 0 -> 1098 bytes .../syndiemedic.rsi/off-inhand-left.png | Bin 0 -> 912 bytes .../syndiemedic.rsi/off-inhand-right.png | Bin 0 -> 856 bytes .../syndiemedic.rsi/on-equipped-HELMET.png | Bin 0 -> 1688 bytes .../syndiemedic.rsi/on-inhand-left.png | Bin 0 -> 1325 bytes .../syndiemedic.rsi/on-inhand-right.png | Bin 0 -> 1311 bytes .../equipped-OUTERCLOTHING.png | Bin 0 -> 2486 bytes .../Hardsuits/syndiemedic.rsi/icon.png | Bin 0 -> 913 bytes .../Hardsuits/syndiemedic.rsi/inhand-left.png | Bin 0 -> 794 bytes .../syndiemedic.rsi/inhand-right.png | Bin 0 -> 837 bytes .../Hardsuits/syndiemedic.rsi/meta.json | 26 +++++++++++ 17 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/icon-flash.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-left.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-right.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-equipped-HELMET.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-left.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-right.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 13bcde369e8..27e9f45c2e1 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -346,6 +346,31 @@ Piercing: 0.9 Heat: 0.9 +#Blood-red Medic Hardsuit +- type: entity + parent: ClothingHeadHardsuitWithLightBase + id: ClothingHeadHelmetHardsuitSyndieMedic + noSpawn: true + name: blood-red medic hardsuit helmet + description: An advanced red hardsuit helmet specifically designed for field medic operations. + components: + - type: Sprite + sprite: Clothing/Head/Hardsuits/syndiemedic.rsi + - type: Clothing + sprite: Clothing/Head/Hardsuits/syndiemedic.rsi + - type: PointLight + color: green + - type: PressureProtection + highPressureMultiplier: 0.08 + lowPressureMultiplier: 1000 + - type: Armor + modifiers: + coefficients: + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 + Heat: 0.9 + #Syndicate Elite Hardsuit - type: entity parent: ClothingHeadHardsuitWithLightBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 66db8332c95..7da6b3393f6 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -452,6 +452,20 @@ - type: ToggleableClothing clothingPrototype: ClothingHeadHelmetHardsuitSyndie +# Syndicate Medic Hardsuit +- type: entity + parent: ClothingOuterHardsuitSyndie + id: ClothingOuterHardsuitMedic + name: blood-red medic hardsuit + description: A heavily armored and agile advanced hardsuit specifically designed for field medic operations. + components: + - type: Sprite + sprite: Clothing/OuterClothing/Hardsuits/syndiemedic.rsi + - type: Clothing + sprite: Clothing/OuterClothing/Hardsuits/syndiemedic.rsi + - type: ToggleableClothing + clothingPrototype: ClothingHeadHelmetHardsuitSyndieMedic + #Syndicate Elite Hardsuit - type: entity parent: ClothingOuterHardsuitBase diff --git a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml index a66881089c3..c8c17445752 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml @@ -151,7 +151,7 @@ eyes: ClothingEyesHudMedical ears: ClothingHeadsetAltSyndicate gloves: ClothingHandsGlovesCombat - outerClothing: ClothingOuterHardsuitSyndieElite + outerClothing: ClothingOuterHardsuitMedic shoes: ClothingShoesBootsMagSyndie id: SyndiPDA pocket1: DoubleEmergencyOxygenTankFilled diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/icon-flash.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/icon-flash.png new file mode 100644 index 0000000000000000000000000000000000000000..6d63fa871b4d50253a595a8e6ffff520827f05ab GIT binary patch literal 851 zcmV-Z1FZasP)Px&4M{{nR9J=WmEUVqXBfvn=SO>z=A0yrr%mfpyBb<+Y1gqS3a&KbWVoyCLi};D ziy?X^UI=<8&LIx=C#)j78-k1>=$)rTFUEA8C}N%SN7mI=W0U4bV{(#nyl9hENzzjh zdXo>laNv2~_xV2G^FF-Lph1HMYm87UU>HW_`-jsf?GvZYRdSDid&sV~=g0Fu3AOe_ zB9W?f#MP)R7uUTSJ;4sPhQn+Phv^A+pnJ8N!s@Xq0mi6N=_sAc63;BIbS_&p#|iRk zipQGHSakP*0Gi8#u6io*bYTHO5{N0^TSgwq>A5R9V2m09BE&prt*(y-kv&a_E{Tk} zKs=izzK|tj<&fMGvf4z~@F4$s&y@s8aO6f^0ZRu+>u=ts>(e2I-7itvT*&@reC%#@x%jjrG5u2vv29x z7nSFekLjE^(g);$($ZN~apFJ$m~XqdcU%0MUw@ZE8h;d1yvlbH9f<-kJu%JPYz#YN zQv5GP@bZC=f#lNOcXMEw3nq{NX7!)H`s`s`LTK$KIr)+&$8PcX=q-|yFA(%F_Y*Sh zm-c-E%mOK(Sg(6<_!t?Zh6uO;AD~>@{oA7tyn)3ZY};VNR3gqUPx$=}AOER9J=WmBCBfP#niUnZgKJ#6wwC$fPvL8-kuJo6y0i9qgiifY3wnPY}Ax z7-N?W{1aRcp1liV7_{PMy(JXF77&-yz*|j9|Cu``c#++l598sc`LHZW>p35QdY(c<+p!4uP z6{-N-t$yQ4p$Nd?XBXddr42|GqUOXzWSAli{NU$Hs=pUc=+fouZ zh#Hoq_@0Yl3Jg-FAq2`(S=gE;N| zuEUq!$04n3+)Rb2VOfejUqap7AP5KaSC8ng9ub5C)Xfd-`BJ9EGaG=o;hY}ZLw8?S xHBOK1p=Kn@t$M*udsq3h@!V$doSd8-fM3EfuTAd45@rAZ002ovPDHLkV1mN44rKrU literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json new file mode 100644 index 00000000000..b69addc4760 --- /dev/null +++ b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json @@ -0,0 +1,41 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Based on tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by EmoGarbage404 (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "icon-flash" + }, + { + "name": "off-equipped-HELMET", + "directions": 4 + }, + { + "name": "off-inhand-left", + "directions": 4 + }, + { + "name": "off-inhand-right", + "directions": 4 + }, + { + "name": "on-equipped-HELMET", + "directions": 4 + }, + { + "name": "on-inhand-left", + "directions": 4 + }, + { + "name": "on-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET.png new file mode 100644 index 0000000000000000000000000000000000000000..37d8a092d9cbbdd87fbedc04887f40292d413a13 GIT binary patch literal 1098 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..6fdf0f3318aec9813e5698efd913d4305e92c254 GIT binary patch literal 794 zcmV+#1LgdQP)Px%)Ja4^RCt{2+RsaqaU8($_gav62r8C2rL|`p5?i3Kw0bUfh$R^+^$%EN#PHOi zgPqV+j^}w&zhMpV#FX+w=K6 zpYMn7cRcX@f)GLoA%qY@2qAcgwvyHre{fY0Z%N#mV#pl8bxm=EHHv7+K`u%?G z^Z7V+w3@G9a!jS?h=;<|1$+!Ve8l+pIDLJ6j@Inx5=i&=v(VYP<8MkSlF8(M_Mc9Y}(0ar3h06cy25`g^DcL3Vk+lz{~?u&=Q+pbn#r#U*E zEFBlmYk;p`a?}NU06c&7w&-V-8*hi>GXUV&i}dn*6E2h7acEz5JCtcgb+dqA%qZOAJTCn ztcQn(_3Z4dF81ufPF&d-aa-K@y5nu)_3*Y4F$| zPesmvzgY(_N>z~!SgWqu`drMxi~UFsG(`30IRahk`mc2Q#mU24o2aF#$R%Jg{I&EJ z(q-kS*aj%2SbaRohuin|x|F>UH^TZ^%LV=B>b0_#fU5^3-BMp)uMgGM@Br|6f0mW& Y7l*_J_7-c!7ytkO07*qoM6N<$f~lH(#{d8T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6f5a83c86f306c5a3614ba0a95d13f25fbba98 GIT binary patch literal 837 zcmV-L1G@Z)P)Px%|4BqaRCt{2+W$)vaU93-=bB+e1Qlz!sI}XM#TF`<6&F!ZsAQPbKcJEj%b)sD zP#WA15&c%b^jq@>e<`RR!XNsfC?cp4X#@o~$wd=4(=fk7eEJ~ryac?zZ`em zeR$oQ_kB3-b0CBeLI@#*5JCtcg!u1;!(pXqngW!jX(}8JtBuZ7jAHU{T6v(u=~OqS zlU%;kNWB)I(H|rhi(wdsEs9_mhKj{v9QL}oa<-91e~=r~NjjX)y!k5%4d!$2VPa;M zR4QdnT8m`!PRz`%d9Gvmj$s(8xw)C^*CHG{Qp?*H@A)x5OXZF&e4d;mlgW@ur5t}6 zY@>NR9_4bmIIwdoUq>^<6DIZk0DHYI`flA}aBz^Go}QfiIgdc1x0kUCr}7SN7zU9@ z#Jcol5Q#)E3A=fOOEK`l>?;pszZl(m{_cUV^gHL62&xty2I^wRHva zuj&9@*HznYA47+N01O=p(ze@&uIsiag0AbTE7U-8X%T?r(jr}<2HWHpLI@#*5JCtc zgb+fAe^ZCksa~GHsQRiys$L7&_KR!Yg^{&nZ}|Jr6TX-qbB@_fNd<@}O#IO(cl{y0 zoopy~rgc?P0RU=hYG^oPk0tX$N?Y<)sE!IJ`vM1f=h^=IZ;TPsHp}PBmDT|c9K&88 z*FSv#;N0fQa%QrRrrJ97c>i`=PJUS>&jA44lL<6WRk^Zkh`)Mn16SQ@n|muW<8zp| z$89+W6#P$cE%!!GkbX0Ukx2vNWs0=E{;B{soj=J`IH;_0!-!d~OzY|w-NFJ`9y6Kj P00000NkvXXu0mjfRr!I6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json new file mode 100644 index 00000000000..373d282410c --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Based on tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by EmoGarbage404 (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} From c694fa449db0cc84407d16626d01a1ce46d3d13b Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 13:37:24 -0400 Subject: [PATCH 95/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0742414253a..e511547b906 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Potato1234_x - changes: - - {message: Added the Dr. Gibb Vendor, type: Add} - id: 4437 - time: '2023-08-05T02:07:41.0000000+00:00' - author: liltenhead changes: - {message: Changed the swat crate to only contain non-lethal shells; now it comes @@ -2961,3 +2956,8 @@ Entries: - {message: Telescopic Shield no longer glows in the dark when deployed., type: Fix} id: 4936 time: '2023-10-01T17:16:54.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Nuclear Operative medics now come with a custom hardsuit., type: Add} + id: 4937 + time: '2023-10-01T17:36:20.0000000+00:00' From 8a213195fb24cdd4832d517a797f93506767a215 Mon Sep 17 00:00:00 2001 From: drteaspoon420 <87363733+drteaspoon420@users.noreply.github.com> Date: Sun, 1 Oct 2023 20:52:45 +0300 Subject: [PATCH 96/98] Carry over other mutations when doing species mutation (#20551) --- Content.Server/Botany/SeedPrototype.cs | 95 +++++++++++++++++++ .../Botany/Systems/MutationSystem.cs | 13 +-- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/Content.Server/Botany/SeedPrototype.cs b/Content.Server/Botany/SeedPrototype.cs index 3d700f2775e..82d5b8de10b 100644 --- a/Content.Server/Botany/SeedPrototype.cs +++ b/Content.Server/Botany/SeedPrototype.cs @@ -56,9 +56,26 @@ public enum PlantJuicy : byte [DataDefinition] public partial struct SeedChemQuantity { + /// + /// Minimum amount of chemical that is added to produce, regardless of the potency + /// [DataField("Min")] public int Min; + + /// + /// Maximum amount of chemical that can be produced after taking plant potency into account. + /// [DataField("Max")] public int Max; + + /// + /// When chemicals are added to produce, the potency of the seed is divided with this value. Final chemical amount is the result plus the `Min` value. + /// Example: PotencyDivisor of 20 with seed potency of 55 results in 2.75, 55/20 = 2.75. If minimum is 1 then final result will be 3.75 of that chemical, 55/20+1 = 3.75. + /// [DataField("PotencyDivisor")] public int PotencyDivisor; + + /// + /// Inherent chemical is one that is NOT result of mutation or crossbreeding. These chemicals are removed if species mutation is executed. + /// + [DataField("Inherent")] public bool Inherent = true; } // TODO reduce the number of friends to a reasonable level. Requires ECS-ing things like plant holder component. @@ -293,4 +310,82 @@ public SeedData Clone() return newSeed; } + + + /// + /// Handles copying most species defining data from 'other' to this seed while keeping the accumulated mutations intact. + /// + public SeedData SpeciesChange(SeedData other) + { + var newSeed = new SeedData + { + Name = other.Name, + Noun = other.Noun, + DisplayName = other.DisplayName, + Mysterious = other.Mysterious, + + PacketPrototype = other.PacketPrototype, + ProductPrototypes = new List(other.ProductPrototypes), + MutationPrototypes = new List(other.MutationPrototypes), + + Chemicals = new Dictionary(Chemicals), + ConsumeGasses = new Dictionary(ConsumeGasses), + ExudeGasses = new Dictionary(ExudeGasses), + + NutrientConsumption = NutrientConsumption, + WaterConsumption = WaterConsumption, + IdealHeat = IdealHeat, + HeatTolerance = HeatTolerance, + IdealLight = IdealLight, + LightTolerance = LightTolerance, + ToxinsTolerance = ToxinsTolerance, + LowPressureTolerance = LowPressureTolerance, + HighPressureTolerance = HighPressureTolerance, + PestTolerance = PestTolerance, + WeedTolerance = WeedTolerance, + + Endurance = Endurance, + Yield = Yield, + Lifespan = Lifespan, + Maturation = Maturation, + Production = Production, + GrowthStages = other.GrowthStages, + HarvestRepeat = HarvestRepeat, + Potency = Potency, + + Seedless = Seedless, + Viable = Viable, + Slip = Slip, + Sentient = Sentient, + Ligneous = Ligneous, + + PlantRsi = other.PlantRsi, + PlantIconState = other.PlantIconState, + Bioluminescent = Bioluminescent, + CanScream = CanScream, + TurnIntoKudzu = TurnIntoKudzu, + BioluminescentColor = BioluminescentColor, + SplatPrototype = other.SplatPrototype, + + // Newly cloned seed is unique. No need to unnecessarily clone if repeatedly modified. + Unique = true, + }; + + // Adding the new chemicals from the new species. + foreach (var otherChem in other.Chemicals) + { + Chemicals.TryAdd(otherChem.Key, otherChem.Value); + } + + // Removing the inherent chemicals from the old species. Leaving mutated/crossbread ones intact. + foreach (var originalChem in Chemicals) + { + if (!other.Chemicals.ContainsKey(originalChem.Key) && originalChem.Value.Inherent) + { + Chemicals.Remove(originalChem.Key); + } + } + + return newSeed; + } } diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index 13ef8e37818..94a450ebeff 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Chemistry.Reagent; using System.Linq; using Content.Shared.Atmos; +using FastAccessors; namespace Content.Server.Botany; @@ -269,6 +270,7 @@ private void MutateChemicals(ref Dictionary chemicals, { seedChemQuantity.Min = 1; seedChemQuantity.Max = 1 + amount; + seedChemQuantity.Inherent = false; } int potencyDivisor = (int) Math.Ceiling(100.0f / seedChemQuantity.Max); seedChemQuantity.PotencyDivisor = potencyDivisor; @@ -295,10 +297,7 @@ private void MutateSpecies(ref SeedData seed, int bits, int totalbits, float mul return; } - var oldSeed = seed.Clone(); - seed = protoSeed.Clone(); - seed.Potency = oldSeed.Potency; - seed.Yield = oldSeed.Yield; + seed = seed.SpeciesChange(protoSeed); } private Color RandomColor(Color color, int bits, int totalbits, float mult) @@ -330,12 +329,14 @@ private void CrossChemicals(ref Dictionary val, Dictio { val[otherChem.Key] = Random(0.5f) ? otherChem.Value : val[otherChem.Key]; } - // if target plant doesn't have this chemical, has 50% chance to add it. + // if target plant doesn't have this chemical, has 50% chance to add it. else { if (Random(0.5f)) { - val.Add(otherChem.Key, otherChem.Value); + var fixedChem = otherChem.Value; + fixedChem.Inherent = false; + val.Add(otherChem.Key, fixedChem); } } } From dc53f23fa656133153b359a398a034f9dd8821ff Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 1 Oct 2023 13:53:49 -0400 Subject: [PATCH 97/98] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e511547b906..4f4d33685ed 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: liltenhead - changes: - - {message: Changed the swat crate to only contain non-lethal shells; now it comes - with shields., type: Tweak} - id: 4438 - time: '2023-08-05T03:47:32.0000000+00:00' - author: crazybrain changes: - {message: Uplinks can now purchase a Syndicate pAI., type: Add} @@ -2961,3 +2955,8 @@ Entries: - {message: Nuclear Operative medics now come with a custom hardsuit., type: Add} id: 4937 time: '2023-10-01T17:36:20.0000000+00:00' +- author: DrTeaSpoon + changes: + - {message: Plant species mutation no longer resets other mutations., type: Fix} + id: 4938 + time: '2023-10-01T17:52:45.0000000+00:00' From e71ae3ac8c33b7e833a6c594ec2903e4ff0a8074 Mon Sep 17 00:00:00 2001 From: ravage <142820619+ravage123321@users.noreply.github.com> Date: Sun, 1 Oct 2023 20:55:05 +0300 Subject: [PATCH 98/98] Add Spanish accent to poncho and sombrero (#20377) --- Resources/Prototypes/Entities/Clothing/Head/hats.yml | 2 ++ Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index 70e6902e667..b29bc5104f6 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -373,6 +373,8 @@ sprite: Clothing/Head/Hats/sombrero.rsi - type: Clothing sprite: Clothing/Head/Hats/sombrero.rsi + - type: AddAccentClothing + accent: SpanishAccent - type: entity parent: ClothingHeadBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml index c19560ab1e4..e0de6c7d83e 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml @@ -114,6 +114,8 @@ sprite: Clothing/OuterClothing/Misc/classicponcho.rsi - type: Clothing sprite: Clothing/OuterClothing/Misc/classicponcho.rsi + - type: AddAccentClothing + accent: SpanishAccent - type: entity parent: ClothingOuterBase @@ -147,6 +149,8 @@ sprite: Clothing/OuterClothing/Misc/poncho.rsi - type: Clothing sprite: Clothing/OuterClothing/Misc/poncho.rsi + - type: AddAccentClothing + accent: SpanishAccent - type: entity parent: ClothingOuterBase