From b8d7dd7a55da40a887d673b57a0d5724b42a8097 Mon Sep 17 00:00:00 2001 From: Salvantrix <149609610+Salvantrix@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:48:03 -0400 Subject: [PATCH 01/83] Pirate Bounties The start of a probably long PR for the pirate bounty system. Not at all complete. --- Resources/Locale/en-US/cargo/bounties.ftl | 35 ++ .../Prototypes/Catalog/Bounties/bounties.yml | 352 ++++++++++++++++++ 2 files changed, 387 insertions(+) diff --git a/Resources/Locale/en-US/cargo/bounties.ftl b/Resources/Locale/en-US/cargo/bounties.ftl index b332517c70d..5ede28606ae 100644 --- a/Resources/Locale/en-US/cargo/bounties.ftl +++ b/Resources/Locale/en-US/cargo/bounties.ftl @@ -65,6 +65,38 @@ bounty-item-cardboard-box = Cardboard box bounty-item-wine = Wine bottle bounty-item-cotton-boll = Cotton boll bounty-item-microwave-machine-board = Microwave machine board +bounty-item-mail = Mail +bounty-item-pda = PDA +bounty-item-extinguisher = Fire Extinguisher +bounty-item-captainGloves = Captain Gloves +bounty-item-gyro = Ship Gyroscope +bounty-item-defib = Defibrillator +bounty-item-researchDisk = Research Disk +bounty-item-alcohol = Booze Dispenser +bounty-item-thruster = Thruster +bounty-item-gravGen = Gravity Generator +bounty-item-chemVend = Chemical Vendo +bounty-item-mercSuit = Mercenary Hardsuit +bounty-item-cappy = Cappy +bounty-item-cultistNeck = Cultist Necklace +bounty-item-nfsdCampaign = Nfsd Small Campaign Hat +bounty-item-scafsuit = SCAF Suit +bounty-item-rtg = RTG +bounty-item-mercgas = Mercenary Gas Mask +bounty-item-rdhardsuit = Experimental RD Hardsuit +bounty-item-mk58 = MK58 +bounty-item-artifactanalyzer = Artifact Analyzer Machine +bounty-item-hotplate = Hotplate +bounty-item-deepfryer = Deep Fryer +bounty-item-keycommon = Common Key +bounty-item-medicalfabboard = Medical Tech Fab Board +bounty-item-orebox = Ore Box +bounty-item-autolathe = Autolathe +bounty-item-diamond = Diamond +bounty-item-plasmacanister = Plasma Canister +bounty-item-contracrate = Contraband Crate +bounty-item-hydrotray = Hydroponics Tray + bounty-description-artifact = NanoTrasen is in some hot water for stealing artifacts from non-spacefaring planets. Return one and we'll compensate you for it. bounty-description-baseball-bat = Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream. @@ -132,3 +164,6 @@ bounty-description-cardobard-box = "The Cardborgs Cometh" is a new play premieri bounty-description-wine = The new librarian and the Quartermaster are falling head over heels for each other after she caught him disassembling the bookshelves for wood. Send a couple bottles of wine (Or cans, if you must) to help make the date go well. bounty-description-cotton-boll = A massive swarm of mothroaches ate all the paper and cloth on the station. Send us some cotton to help keep our winged crewmembers fed. bounty-description-microwave-machine-board = Mr. Giggles thought it'd be funny to stick forks in all the kitchen microwaves. Help us replace them before the chefs start making clown burgers. +bounty-description-pirate = Go now you goon! Plunder me this! + + diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 3c1bd02fcfc..8f0e3bfbe9e 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -707,3 +707,355 @@ tags: - MicrowaveMachineBoard +- type: pirateBounty + id: BountyMail + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-mail + amount: 10 + whitelist: + tag: + - Mail + +- type: pirateBounty + id: BountyPDA + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-pda + amount: 8 + whitelist: + components: + - BasePDA + +- type: pirateBounty + id: BountyExtinguisher + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-extinguisher + amount: 5 + whitelist: + components: + - FireExtinguisher + +- type: pirateBounty + id: BountyCaptainGloves + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-captainGloves + amount: 5 + whitelist: + components: + - ClothingHandsGlovesCaptain + +- type: pirateBounty + id: BountyCaptainGyro + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-gyro + amount: 4 + whitelist: + components: + - ShuttleGyroscope + +- type: pirateBounty + id: BountyCaptainDefib + reward: 3 + description: bounty-description-pirate + entries: + - name: bounty-item-defib + amount: 5 + whitelist: + components: + - BaseDefibrillator + +- type: pirateBounty + id: BountyCaptainResearchDisk + reward: 5 + description: bounty-description-pirate + entries: + - name: bounty-item-researchDisk + amount: 5 + whitelist: + components: + - ResearchDisk + +- type: pirateBounty + id: BountyCaptainAlcohol + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-alcohol + amount: 4 + whitelist: + components: + - BoozeDispenser + +- type: pirateBounty + id: BountyCaptainThruster + reward: 4 + description: bounty-description-pirate + entries: + - name: bounty-item-thruster + amount: 4 + whitelist: + components: + - BaseThruster + +- type: pirateBounty + id: BountyCaptainGravGen + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-gravGen + amount: 4 + whitelist: + components: + - GravityGenerator + +- type: pirateBounty + id: BountyCaptainChemVend + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-chemVend + amount: 3 + whitelist: + components: + - VendingMachineChemicals + +- type: pirateBounty + id: BountyCaptainMercSuit + reward: 3 + description: bounty-description-pirate + entries: + - name: bounty-item-mercSuit + amount: 2 + whitelist: + components: + - ClothingOuterHardsuitMercenary + +- type: pirateBounty + id: BountyCappy + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-cappy + amount: 10 + whitelist: + components: + - MobCatCappy + +- type: pirateBounty + id: BountyCultistNecklace + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-cultistNeck + amount: 4 + whitelist: + components: + - ClothingNeckAmuletBloodCult + +- type: pirateBounty + id: BountyNfsdCampaign + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-nfsdCampaign + amount: 4 + whitelist: + components: + - ClothingHeadHatNfsdSmallCampaign + - ClothingHeadHatNfsdCampaign + +- type: pirateBounty + id: BountyScafSuit + reward: 5 + description: bounty-description-pirate + entries: + - name: bounty-item-scafsuit + amount: 3 + whitelist: + components: + - ClothingOuterHardsuitScaf + +- type: pirateBounty + id: BountyRTG + reward: 4 + description: bounty-description-pirate + entries: + - name: bounty-item-rtg + amount: 2 + whitelist: + components: + - GeneratorRTG + +- type: pirateBounty + id: BountyMercGas + reward: 3 + description: bounty-description-pirate + entries: + - name: bounty-item-mercgas + amount: 4 + whitelist: + components: + - ClothingMaskGasMercenary + +- type: pirateBounty + id: BountyRDHardsuit + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-rdhardsuit + amount: 3 + whitelist: + components: + - ClothingOuterHardsuitRd + +- type: pirateBounty + id: BountyMK58 + reward: 5 + description: bounty-description-pirate + entries: + - name: bounty-item-mk58 + amount: 2 + whitelist: + components: + - WeaponPistolMk58 + +- type: pirateBounty + id: BountyArtifactAnalyzer + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-artifactanalyzer + amount: 4 + whitelist: + components: + - MachineArtifactAnalyzer + +- type: pirateBounty + id: BountyHotplate + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-hotplate + amount: 5 + whitelist: + components: + - ChemistryHotplate + +- type: pirateBounty + id: BountyDeepFryer + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-deepfryer + amount: 4 + whitelist: + components: + - KitchenDeepFryer + +- type: pirateBounty + id: BountyKeyCommon + reward: 3 + description: bounty-description-pirate + entries: + - name: bounty-item-keycommon + amount: 5 + whitelist: + components: + - EncryptionKeyCommon + +- type: pirateBounty + id: BountyMedicalFabBoard + reward: 1 + description: bounty-description-pirate + entries: + - name: bounty-item-medicalfabboard + amount: 3 + whitelist: + components: + - MedicalTechFabCircuitboard + +- type: pirateBounty + id: BountyHypo + reward: 3 + description: bounty-description-pirate + entries: + - name: bounty-item-hypo + amount: 6 + whitelist: + components: + - Hypospray + +- type: pirateBounty + id: BountyOreBox + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-orebox + amount: 3 + whitelist: + components: + - OreBox + +- type: pirateBounty + id: BountyAutolathe + reward: 2 + description: bounty-description-pirate + entries: + - name: bounty-item-autolathe + amount: 3 + whitelist: + components: + - Autolathe + +- type: pirateBounty + id: BountyDiamond + reward: 4 + description: bounty-description-pirate + entries: + - name: bounty-item-diamond + amount: 5 + whitelist: + components: + - MaterialDiamond + +- type: pirateBounty + id: BountyPlasmaCanister + reward: 4 + description: bounty-description-pirate + entries: + - name: bounty-item-plasmacanister + amount: 5 + whitelist: + components: + - PlasmaCanister + +- type: pirateBounty + id: BountyContraCrate + reward: 3 + description: bounty-description-pirate + entries: + - name: bounty-item-contracrate + amount: 1 + whitelist: + components: + - CrateTradeContrabandSecureNormal + +- type: pirateBounty + id: BountyHydroTray + reward: 4 + description: bounty-description-pirate + entries: + - name: bounty-item-hydrotray + amount: 2 + whitelist: + components: + - hydroponicsTray \ No newline at end of file From e59b30a2c707471717940ee04f1d637344dace3c Mon Sep 17 00:00:00 2001 From: Salvantrix <149609610+Salvantrix@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:53:27 -0400 Subject: [PATCH 02/83] Changed Components to ID's Awaiting further checkiessssssssssss --- .../Prototypes/Catalog/Bounties/bounties.yml | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 8f0e3bfbe9e..96f1bfd5e55 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -715,8 +715,11 @@ - name: bounty-item-mail amount: 10 whitelist: - tag: + components: - Mail + blacklist: + tag: + - Trash - type: pirateBounty id: BountyPDA @@ -726,7 +729,7 @@ - name: bounty-item-pda amount: 8 whitelist: - components: + id: - BasePDA - type: pirateBounty @@ -737,7 +740,7 @@ - name: bounty-item-extinguisher amount: 5 whitelist: - components: + id: - FireExtinguisher - type: pirateBounty @@ -748,7 +751,7 @@ - name: bounty-item-captainGloves amount: 5 whitelist: - components: + id: - ClothingHandsGlovesCaptain - type: pirateBounty @@ -759,7 +762,7 @@ - name: bounty-item-gyro amount: 4 whitelist: - components: + id: - ShuttleGyroscope - type: pirateBounty @@ -770,7 +773,7 @@ - name: bounty-item-defib amount: 5 whitelist: - components: + id: - BaseDefibrillator - type: pirateBounty @@ -781,7 +784,7 @@ - name: bounty-item-researchDisk amount: 5 whitelist: - components: + id: - ResearchDisk - type: pirateBounty @@ -792,7 +795,7 @@ - name: bounty-item-alcohol amount: 4 whitelist: - components: + id: - BoozeDispenser - type: pirateBounty @@ -803,7 +806,7 @@ - name: bounty-item-thruster amount: 4 whitelist: - components: + id: - BaseThruster - type: pirateBounty @@ -814,7 +817,7 @@ - name: bounty-item-gravGen amount: 4 whitelist: - components: + id: - GravityGenerator - type: pirateBounty @@ -825,7 +828,7 @@ - name: bounty-item-chemVend amount: 3 whitelist: - components: + id: - VendingMachineChemicals - type: pirateBounty @@ -836,7 +839,7 @@ - name: bounty-item-mercSuit amount: 2 whitelist: - components: + id: - ClothingOuterHardsuitMercenary - type: pirateBounty @@ -847,7 +850,7 @@ - name: bounty-item-cappy amount: 10 whitelist: - components: + id: - MobCatCappy - type: pirateBounty @@ -858,7 +861,7 @@ - name: bounty-item-cultistNeck amount: 4 whitelist: - components: + id: - ClothingNeckAmuletBloodCult - type: pirateBounty @@ -869,7 +872,7 @@ - name: bounty-item-nfsdCampaign amount: 4 whitelist: - components: + id: - ClothingHeadHatNfsdSmallCampaign - ClothingHeadHatNfsdCampaign @@ -881,7 +884,7 @@ - name: bounty-item-scafsuit amount: 3 whitelist: - components: + id: - ClothingOuterHardsuitScaf - type: pirateBounty @@ -892,7 +895,7 @@ - name: bounty-item-rtg amount: 2 whitelist: - components: + id: - GeneratorRTG - type: pirateBounty @@ -903,7 +906,7 @@ - name: bounty-item-mercgas amount: 4 whitelist: - components: + id: - ClothingMaskGasMercenary - type: pirateBounty @@ -914,7 +917,7 @@ - name: bounty-item-rdhardsuit amount: 3 whitelist: - components: + id: - ClothingOuterHardsuitRd - type: pirateBounty @@ -925,7 +928,7 @@ - name: bounty-item-mk58 amount: 2 whitelist: - components: + id: - WeaponPistolMk58 - type: pirateBounty @@ -936,7 +939,7 @@ - name: bounty-item-artifactanalyzer amount: 4 whitelist: - components: + id: - MachineArtifactAnalyzer - type: pirateBounty @@ -947,7 +950,7 @@ - name: bounty-item-hotplate amount: 5 whitelist: - components: + id: - ChemistryHotplate - type: pirateBounty @@ -958,7 +961,7 @@ - name: bounty-item-deepfryer amount: 4 whitelist: - components: + id: - KitchenDeepFryer - type: pirateBounty @@ -969,7 +972,7 @@ - name: bounty-item-keycommon amount: 5 whitelist: - components: + id: - EncryptionKeyCommon - type: pirateBounty @@ -980,7 +983,7 @@ - name: bounty-item-medicalfabboard amount: 3 whitelist: - components: + id: - MedicalTechFabCircuitboard - type: pirateBounty @@ -991,7 +994,7 @@ - name: bounty-item-hypo amount: 6 whitelist: - components: + id: - Hypospray - type: pirateBounty @@ -1002,7 +1005,7 @@ - name: bounty-item-orebox amount: 3 whitelist: - components: + id: - OreBox - type: pirateBounty @@ -1013,7 +1016,7 @@ - name: bounty-item-autolathe amount: 3 whitelist: - components: + id: - Autolathe - type: pirateBounty @@ -1024,7 +1027,7 @@ - name: bounty-item-diamond amount: 5 whitelist: - components: + id: - MaterialDiamond - type: pirateBounty @@ -1035,7 +1038,7 @@ - name: bounty-item-plasmacanister amount: 5 whitelist: - components: + id: - PlasmaCanister - type: pirateBounty @@ -1046,7 +1049,7 @@ - name: bounty-item-contracrate amount: 1 whitelist: - components: + id: - CrateTradeContrabandSecureNormal - type: pirateBounty @@ -1057,5 +1060,5 @@ - name: bounty-item-hydrotray amount: 2 whitelist: - components: + id: - hydroponicsTray \ No newline at end of file From 948622b946068b33d03528f421bda72f273a34f0 Mon Sep 17 00:00:00 2001 From: Salvantrix <149609610+Salvantrix@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:58:37 -0400 Subject: [PATCH 03/83] added additional bounties Added gold ore/ingots and Vending Machines --- Resources/Locale/en-US/cargo/bounties.ftl | 5 ++-- .../Prototypes/Catalog/Bounties/bounties.yml | 29 +++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Resources/Locale/en-US/cargo/bounties.ftl b/Resources/Locale/en-US/cargo/bounties.ftl index 5ede28606ae..85e08c15634 100644 --- a/Resources/Locale/en-US/cargo/bounties.ftl +++ b/Resources/Locale/en-US/cargo/bounties.ftl @@ -75,7 +75,8 @@ bounty-item-researchDisk = Research Disk bounty-item-alcohol = Booze Dispenser bounty-item-thruster = Thruster bounty-item-gravGen = Gravity Generator -bounty-item-chemVend = Chemical Vendo +bounty-item-chemVend = Chemical Vending Machine +bounty-item-vendingmachine = Vending Machine bounty-item-mercSuit = Mercenary Hardsuit bounty-item-cappy = Cappy bounty-item-cultistNeck = Cultist Necklace @@ -92,7 +93,7 @@ bounty-item-keycommon = Common Key bounty-item-medicalfabboard = Medical Tech Fab Board bounty-item-orebox = Ore Box bounty-item-autolathe = Autolathe -bounty-item-diamond = Diamond +bounty-item-gold = Gold bounty-item-plasmacanister = Plasma Canister bounty-item-contracrate = Contraband Crate bounty-item-hydrotray = Hydroponics Tray diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 96f1bfd5e55..2545347f0ec 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -782,7 +782,7 @@ description: bounty-description-pirate entries: - name: bounty-item-researchDisk - amount: 5 + amount: 7 whitelist: id: - ResearchDisk @@ -822,15 +822,26 @@ - type: pirateBounty id: BountyCaptainChemVend - reward: 1 + reward: 3 description: bounty-description-pirate entries: - name: bounty-item-chemVend - amount: 3 + amount: 1 whitelist: id: - VendingMachineChemicals +- type: pirateBounty + id: BountyVendingMachine + reward: 6 + description: bounty-description-pirate + entries: + - name: bounty-item-vendingmachine + amount: 3 + whitelist: + id: + - VendingMachine + - type: pirateBounty id: BountyCaptainMercSuit reward: 3 @@ -1030,6 +1041,18 @@ id: - MaterialDiamond +- type: pirateBounty + id: BountyGold + reward: 4 + description: bounty-description-pirate + entries: + - name: bounty-item-gold + amount: 5 + whitelist: + id: + - OreGold + - IngotGold + - type: pirateBounty id: BountyPlasmaCanister reward: 4 From b6007a3288e7aba0f727366d243a4e672f278d4b Mon Sep 17 00:00:00 2001 From: Salvantrix <149609610+Salvantrix@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:59:17 -0400 Subject: [PATCH 04/83] Fixed ID names Everything was Captain, NO LONGER --- .../Prototypes/Catalog/Bounties/bounties.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 2545347f0ec..849f9058df1 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -755,7 +755,7 @@ - ClothingHandsGlovesCaptain - type: pirateBounty - id: BountyCaptainGyro + id: BountyGyro reward: 2 description: bounty-description-pirate entries: @@ -766,7 +766,7 @@ - ShuttleGyroscope - type: pirateBounty - id: BountyCaptainDefib + id: BountyDefib reward: 3 description: bounty-description-pirate entries: @@ -777,7 +777,7 @@ - BaseDefibrillator - type: pirateBounty - id: BountyCaptainResearchDisk + id: BountyResearchDisk reward: 5 description: bounty-description-pirate entries: @@ -788,7 +788,7 @@ - ResearchDisk - type: pirateBounty - id: BountyCaptainAlcohol + id: BountyAlcohol reward: 2 description: bounty-description-pirate entries: @@ -799,7 +799,7 @@ - BoozeDispenser - type: pirateBounty - id: BountyCaptainThruster + id: BountyThruster reward: 4 description: bounty-description-pirate entries: @@ -810,7 +810,7 @@ - BaseThruster - type: pirateBounty - id: BountyCaptainGravGen + id: BountyGravGen reward: 2 description: bounty-description-pirate entries: @@ -821,7 +821,7 @@ - GravityGenerator - type: pirateBounty - id: BountyCaptainChemVend + id: BountyChemVend reward: 3 description: bounty-description-pirate entries: @@ -843,7 +843,7 @@ - VendingMachine - type: pirateBounty - id: BountyCaptainMercSuit + id: BountyMercSuit reward: 3 description: bounty-description-pirate entries: From 3d2c3d0aef2302b9ea37ad00149133ca3d14d92e Mon Sep 17 00:00:00 2001 From: Whatstone Date: Sun, 16 Jun 2024 12:59:14 -0400 Subject: [PATCH 05/83] ID Whitelist, move pirate bounties to _NF folders --- .../Cargo/Prototypes/PirateBountyPrototype.cs | 70 ++++ .../_NF/Whitelist/EntProtoIdWhitelist.cs | 32 ++ .../Whitelist/EntProtoIdWhitelistSystem.cs | 83 ++++ .../en-US/_NF/cargo/pirate-bounties.ftl | 34 ++ Resources/Locale/en-US/cargo/bounties.ftl | 36 -- .../Prototypes/Catalog/Bounties/bounties.yml | 379 ------------------ .../_NF/Catalog/Bounties/pirate_bounties.yml | 379 ++++++++++++++++++ 7 files changed, 598 insertions(+), 415 deletions(-) create mode 100644 Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs create mode 100644 Content.Shared/_NF/Whitelist/EntProtoIdWhitelist.cs create mode 100644 Content.Shared/_NF/Whitelist/EntProtoIdWhitelistSystem.cs create mode 100644 Resources/Locale/en-US/_NF/cargo/pirate-bounties.ftl create mode 100644 Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml diff --git a/Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs b/Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs new file mode 100644 index 00000000000..bf9f11826da --- /dev/null +++ b/Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs @@ -0,0 +1,70 @@ +using Content.Shared.Whitelist; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Cargo.Prototypes; + +/// +/// This is a prototype for a pirate bounty, a set of items +/// that must be sold together in a labeled container in order +/// to receive a reward in doubloons. +/// +[Prototype, Serializable, NetSerializable] +public sealed partial class PirateBountyPrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// The monetary reward for completing the bounty + /// + [DataField(required: true)] + public int Reward; + + /// + /// A description for flava purposes. If empty, will fallback to a default option. + /// + [DataField] + public LocId Description = string.Empty; + + /// + /// The entries that must be satisfied for the cargo bounty to be complete. + /// + [DataField(required: true)] + public List Entries = new(); + + /// + /// A prefix appended to the beginning of a bounty's ID. + /// + [DataField] + public string IdPrefix = "NT"; +} + +[DataDefinition, Serializable, NetSerializable] +public readonly partial record struct PirateBountyItemEntry() +{ + /// + /// A whitelist for determining what items satisfy the entry by tag, component, etc. + /// + [DataField(required: true)] + public EntityWhitelist Whitelist { get; init; } = default!; + + /// + /// A whitelist for determining what items satisfy the entry by entity prototype ID + /// + [DataField(required: true)] + public EntProtoIdWhitelist IdWhitelist { get; init; } = default!; + + /// + /// How much of the item must be present to satisfy the entry + /// + [DataField] + public int Amount { get; init; } = 1; + + /// + /// A player-facing name for the item. + /// + [DataField] + public LocId Name { get; init; } = string.Empty; +} diff --git a/Content.Shared/_NF/Whitelist/EntProtoIdWhitelist.cs b/Content.Shared/_NF/Whitelist/EntProtoIdWhitelist.cs new file mode 100644 index 00000000000..f1844b47d2f --- /dev/null +++ b/Content.Shared/_NF/Whitelist/EntProtoIdWhitelist.cs @@ -0,0 +1,32 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Whitelist; + +/// +/// Used to determine whether an entity fits a certain whitelist by ID set. +/// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all +/// entity prototypes that need to be whitelisted, and checking for that. +/// +/// +/// whitelist: +/// ids: +/// - Cigarette +/// - FirelockElectronics +/// matchParents: false +/// +[DataDefinition] +[Serializable, NetSerializable] +public sealed partial class EntProtoIdWhitelist +{ + /// + /// Component names that are allowed in the whitelist. + /// + [DataField] public EntProtoId[]? Ids; + + /// + /// If false, an entity must be a direct match. If true, check against the entity's parents. + /// + [DataField] + public bool MatchParents = false; +} diff --git a/Content.Shared/_NF/Whitelist/EntProtoIdWhitelistSystem.cs b/Content.Shared/_NF/Whitelist/EntProtoIdWhitelistSystem.cs new file mode 100644 index 00000000000..3bc93c904dc --- /dev/null +++ b/Content.Shared/_NF/Whitelist/EntProtoIdWhitelistSystem.cs @@ -0,0 +1,83 @@ +using Robust.Shared.Prototypes; +using System.Diagnostics.CodeAnalysis; + +namespace Content.Shared.Whitelist; + +public sealed class EntProtoIdWhitelistSystem : EntitySystem +{ + [Dependency] private readonly IEntityManager _entMan = default!; + [Dependency] private readonly IPrototypeManager _protoMan = default!; + public override void Initialize() + { + base.Initialize(); + } + + public bool IsValid(EntProtoIdWhitelist list, [NotNullWhen(true)] EntityUid? uid) + { + return uid != null && IsValid(list, uid.Value); + } + + /// + /// Checks whether a given entity satisfies a whitelist. + /// Note: no cycle checks, possibility to run away. + /// + public bool IsValid(EntProtoIdWhitelist list, EntityUid uid) + { + // All of the information we need is in EntityPrototype (ID, parents). + NetEntity netEntity = _entMan.GetNetEntity(uid); + MetaDataComponent? metadata = _entMan.GetComponentOrNull(_entMan.GetEntity(netEntity)); + EntityPrototype? prototype = metadata?.EntityPrototype; + + if (list.Ids is null || prototype is null) + return false; + + // Check our prototype's ID against our desired list. Any match is good (no duplicate IDs). + foreach (var id in list.Ids) + { + if (prototype?.ID?.Equals(id) ?? false) + return true; + } + + // If we haven't matched, check the parents if needed: recurse through each ancestor of this entity. + if (list.MatchParents) + { + string[] parents = prototype?.Parents ?? new string[] {}; + foreach (var parent in parents) + { + if (IsValidRecursive(list, parent)) + return true; + } + } + + return false; + } + + private bool IsValidRecursive(EntProtoIdWhitelist list, string prototypeId) + { + // Check + if (!_protoMan.TryIndex(prototypeId, out var prototype)) + return false; + + if (list.Ids is null || prototype is null) + return false; + + foreach (var id in list.Ids) + { + if (prototype?.ID?.Equals(id) ?? false) + return true; + } + + // Nothing found here, recurse to the next set of parents. + if (list.MatchParents) + { + string [] parents = prototype?.Parents ?? new string[] {}; + foreach (var parent in parents) + { + if (IsValidRecursive(list, parent)) + return true; + } + } + + return false; + } +} diff --git a/Resources/Locale/en-US/_NF/cargo/pirate-bounties.ftl b/Resources/Locale/en-US/_NF/cargo/pirate-bounties.ftl new file mode 100644 index 00000000000..67eaf3ec319 --- /dev/null +++ b/Resources/Locale/en-US/_NF/cargo/pirate-bounties.ftl @@ -0,0 +1,34 @@ +pirate-bounty-item-mail = Mail +pirate-bounty-item-pda = PDA +pirate-bounty-item-extinguisher = Fire Extinguisher +pirate-bounty-item-captainGloves = Captain Gloves +pirate-bounty-item-gyro = Ship Gyroscope +pirate-bounty-item-defib = Defibrillator +pirate-bounty-item-researchDisk = Research Disk +pirate-bounty-item-alcohol = Booze Dispenser +pirate-bounty-item-thruster = Thruster +pirate-bounty-item-gravGen = Gravity Generator +pirate-bounty-item-chemVend = Chemical Vending Machine +pirate-bounty-item-vendingmachine = Vending Machine +pirate-bounty-item-mercSuit = Mercenary Hardsuit +pirate-bounty-item-cappy = Cappy +pirate-bounty-item-cultistNeck = Cultist Necklace +pirate-bounty-item-nfsdCampaign = Nfsd Small Campaign Hat +pirate-bounty-item-scafsuit = SCAF Suit +pirate-bounty-item-rtg = RTG +pirate-bounty-item-mercgas = Mercenary Gas Mask +pirate-bounty-item-rdhardsuit = Experimental RD Hardsuit +pirate-bounty-item-mk58 = MK58 +pirate-bounty-item-artifactanalyzer = Artifact Analyzer Machine +pirate-bounty-item-hotplate = Hotplate +pirate-bounty-item-deepfryer = Deep Fryer +pirate-bounty-item-keycommon = Common Key +pirate-bounty-item-medicalfabboard = Medical Tech Fab Board +pirate-bounty-item-orebox = Ore Box +pirate-bounty-item-autolathe = Autolathe +pirate-bounty-item-gold = Gold +pirate-bounty-item-plasmacanister = Plasma Canister +pirate-bounty-item-contracrate = Contraband Crate +pirate-bounty-item-hydrotray = Hydroponics Tray + +bounty-description-pirate = Go now, ye goon! Plunder me this! diff --git a/Resources/Locale/en-US/cargo/bounties.ftl b/Resources/Locale/en-US/cargo/bounties.ftl index 85e08c15634..b332517c70d 100644 --- a/Resources/Locale/en-US/cargo/bounties.ftl +++ b/Resources/Locale/en-US/cargo/bounties.ftl @@ -65,39 +65,6 @@ bounty-item-cardboard-box = Cardboard box bounty-item-wine = Wine bottle bounty-item-cotton-boll = Cotton boll bounty-item-microwave-machine-board = Microwave machine board -bounty-item-mail = Mail -bounty-item-pda = PDA -bounty-item-extinguisher = Fire Extinguisher -bounty-item-captainGloves = Captain Gloves -bounty-item-gyro = Ship Gyroscope -bounty-item-defib = Defibrillator -bounty-item-researchDisk = Research Disk -bounty-item-alcohol = Booze Dispenser -bounty-item-thruster = Thruster -bounty-item-gravGen = Gravity Generator -bounty-item-chemVend = Chemical Vending Machine -bounty-item-vendingmachine = Vending Machine -bounty-item-mercSuit = Mercenary Hardsuit -bounty-item-cappy = Cappy -bounty-item-cultistNeck = Cultist Necklace -bounty-item-nfsdCampaign = Nfsd Small Campaign Hat -bounty-item-scafsuit = SCAF Suit -bounty-item-rtg = RTG -bounty-item-mercgas = Mercenary Gas Mask -bounty-item-rdhardsuit = Experimental RD Hardsuit -bounty-item-mk58 = MK58 -bounty-item-artifactanalyzer = Artifact Analyzer Machine -bounty-item-hotplate = Hotplate -bounty-item-deepfryer = Deep Fryer -bounty-item-keycommon = Common Key -bounty-item-medicalfabboard = Medical Tech Fab Board -bounty-item-orebox = Ore Box -bounty-item-autolathe = Autolathe -bounty-item-gold = Gold -bounty-item-plasmacanister = Plasma Canister -bounty-item-contracrate = Contraband Crate -bounty-item-hydrotray = Hydroponics Tray - bounty-description-artifact = NanoTrasen is in some hot water for stealing artifacts from non-spacefaring planets. Return one and we'll compensate you for it. bounty-description-baseball-bat = Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream. @@ -165,6 +132,3 @@ bounty-description-cardobard-box = "The Cardborgs Cometh" is a new play premieri bounty-description-wine = The new librarian and the Quartermaster are falling head over heels for each other after she caught him disassembling the bookshelves for wood. Send a couple bottles of wine (Or cans, if you must) to help make the date go well. bounty-description-cotton-boll = A massive swarm of mothroaches ate all the paper and cloth on the station. Send us some cotton to help keep our winged crewmembers fed. bounty-description-microwave-machine-board = Mr. Giggles thought it'd be funny to stick forks in all the kitchen microwaves. Help us replace them before the chefs start making clown burgers. -bounty-description-pirate = Go now you goon! Plunder me this! - - diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 849f9058df1..0000b35d28b 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -706,382 +706,3 @@ whitelist: tags: - MicrowaveMachineBoard - -- type: pirateBounty - id: BountyMail - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-mail - amount: 10 - whitelist: - components: - - Mail - blacklist: - tag: - - Trash - -- type: pirateBounty - id: BountyPDA - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-pda - amount: 8 - whitelist: - id: - - BasePDA - -- type: pirateBounty - id: BountyExtinguisher - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-extinguisher - amount: 5 - whitelist: - id: - - FireExtinguisher - -- type: pirateBounty - id: BountyCaptainGloves - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-captainGloves - amount: 5 - whitelist: - id: - - ClothingHandsGlovesCaptain - -- type: pirateBounty - id: BountyGyro - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-gyro - amount: 4 - whitelist: - id: - - ShuttleGyroscope - -- type: pirateBounty - id: BountyDefib - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-defib - amount: 5 - whitelist: - id: - - BaseDefibrillator - -- type: pirateBounty - id: BountyResearchDisk - reward: 5 - description: bounty-description-pirate - entries: - - name: bounty-item-researchDisk - amount: 7 - whitelist: - id: - - ResearchDisk - -- type: pirateBounty - id: BountyAlcohol - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-alcohol - amount: 4 - whitelist: - id: - - BoozeDispenser - -- type: pirateBounty - id: BountyThruster - reward: 4 - description: bounty-description-pirate - entries: - - name: bounty-item-thruster - amount: 4 - whitelist: - id: - - BaseThruster - -- type: pirateBounty - id: BountyGravGen - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-gravGen - amount: 4 - whitelist: - id: - - GravityGenerator - -- type: pirateBounty - id: BountyChemVend - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-chemVend - amount: 1 - whitelist: - id: - - VendingMachineChemicals - -- type: pirateBounty - id: BountyVendingMachine - reward: 6 - description: bounty-description-pirate - entries: - - name: bounty-item-vendingmachine - amount: 3 - whitelist: - id: - - VendingMachine - -- type: pirateBounty - id: BountyMercSuit - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-mercSuit - amount: 2 - whitelist: - id: - - ClothingOuterHardsuitMercenary - -- type: pirateBounty - id: BountyCappy - reward: 1 - description: bounty-description-pirate - entries: - - name: bounty-item-cappy - amount: 10 - whitelist: - id: - - MobCatCappy - -- type: pirateBounty - id: BountyCultistNecklace - reward: 1 - description: bounty-description-pirate - entries: - - name: bounty-item-cultistNeck - amount: 4 - whitelist: - id: - - ClothingNeckAmuletBloodCult - -- type: pirateBounty - id: BountyNfsdCampaign - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-nfsdCampaign - amount: 4 - whitelist: - id: - - ClothingHeadHatNfsdSmallCampaign - - ClothingHeadHatNfsdCampaign - -- type: pirateBounty - id: BountyScafSuit - reward: 5 - description: bounty-description-pirate - entries: - - name: bounty-item-scafsuit - amount: 3 - whitelist: - id: - - ClothingOuterHardsuitScaf - -- type: pirateBounty - id: BountyRTG - reward: 4 - description: bounty-description-pirate - entries: - - name: bounty-item-rtg - amount: 2 - whitelist: - id: - - GeneratorRTG - -- type: pirateBounty - id: BountyMercGas - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-mercgas - amount: 4 - whitelist: - id: - - ClothingMaskGasMercenary - -- type: pirateBounty - id: BountyRDHardsuit - reward: 1 - description: bounty-description-pirate - entries: - - name: bounty-item-rdhardsuit - amount: 3 - whitelist: - id: - - ClothingOuterHardsuitRd - -- type: pirateBounty - id: BountyMK58 - reward: 5 - description: bounty-description-pirate - entries: - - name: bounty-item-mk58 - amount: 2 - whitelist: - id: - - WeaponPistolMk58 - -- type: pirateBounty - id: BountyArtifactAnalyzer - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-artifactanalyzer - amount: 4 - whitelist: - id: - - MachineArtifactAnalyzer - -- type: pirateBounty - id: BountyHotplate - reward: 1 - description: bounty-description-pirate - entries: - - name: bounty-item-hotplate - amount: 5 - whitelist: - id: - - ChemistryHotplate - -- type: pirateBounty - id: BountyDeepFryer - reward: 1 - description: bounty-description-pirate - entries: - - name: bounty-item-deepfryer - amount: 4 - whitelist: - id: - - KitchenDeepFryer - -- type: pirateBounty - id: BountyKeyCommon - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-keycommon - amount: 5 - whitelist: - id: - - EncryptionKeyCommon - -- type: pirateBounty - id: BountyMedicalFabBoard - reward: 1 - description: bounty-description-pirate - entries: - - name: bounty-item-medicalfabboard - amount: 3 - whitelist: - id: - - MedicalTechFabCircuitboard - -- type: pirateBounty - id: BountyHypo - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-hypo - amount: 6 - whitelist: - id: - - Hypospray - -- type: pirateBounty - id: BountyOreBox - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-orebox - amount: 3 - whitelist: - id: - - OreBox - -- type: pirateBounty - id: BountyAutolathe - reward: 2 - description: bounty-description-pirate - entries: - - name: bounty-item-autolathe - amount: 3 - whitelist: - id: - - Autolathe - -- type: pirateBounty - id: BountyDiamond - reward: 4 - description: bounty-description-pirate - entries: - - name: bounty-item-diamond - amount: 5 - whitelist: - id: - - MaterialDiamond - -- type: pirateBounty - id: BountyGold - reward: 4 - description: bounty-description-pirate - entries: - - name: bounty-item-gold - amount: 5 - whitelist: - id: - - OreGold - - IngotGold - -- type: pirateBounty - id: BountyPlasmaCanister - reward: 4 - description: bounty-description-pirate - entries: - - name: bounty-item-plasmacanister - amount: 5 - whitelist: - id: - - PlasmaCanister - -- type: pirateBounty - id: BountyContraCrate - reward: 3 - description: bounty-description-pirate - entries: - - name: bounty-item-contracrate - amount: 1 - whitelist: - id: - - CrateTradeContrabandSecureNormal - -- type: pirateBounty - id: BountyHydroTray - reward: 4 - description: bounty-description-pirate - entries: - - name: bounty-item-hydrotray - amount: 2 - whitelist: - id: - - hydroponicsTray \ No newline at end of file diff --git a/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml b/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml new file mode 100644 index 00000000000..0e8254edebb --- /dev/null +++ b/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml @@ -0,0 +1,379 @@ + +- type: pirateBounty + id: PirateBountyMail + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-mail + amount: 10 + whitelist: + components: + - Mail + blacklist: + tag: + - Trash + +- type: pirateBounty + id: PirateBountyPDA + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-pda + amount: 8 + whitelist: + id: + - BasePDA + +- type: pirateBounty + id: PirateBountyExtinguisher + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-extinguisher + amount: 5 + whitelist: + id: + - FireExtinguisher + +- type: pirateBounty + id: PirateBountyCaptainGloves + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-captainGloves + amount: 5 + whitelist: + id: + - ClothingHandsGlovesCaptain + +- type: pirateBounty + id: PirateBountyGyro + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-gyro + amount: 4 + whitelist: + id: + - ShuttleGyroscope + +- type: pirateBounty + id: PirateBountyDefib + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-defib + amount: 5 + whitelist: + id: + - BaseDefibrillator + +- type: pirateBounty + id: PirateBountyResearchDisk + reward: 5 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-researchDisk + amount: 7 + whitelist: + id: + - ResearchDisk + +- type: pirateBounty + id: PirateBountyAlcohol + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-alcohol + amount: 4 + whitelist: + id: + - BoozeDispenser + +- type: pirateBounty + id: PirateBountyThruster + reward: 4 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-thruster + amount: 4 + whitelist: + id: + - BaseThruster + +- type: pirateBounty + id: PirateBountyGravGen + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-gravGen + amount: 4 + whitelist: + id: + - GravityGenerator + +- type: pirateBounty + id: PirateBountyChemVend + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-chemVend + amount: 1 + whitelist: + id: + - VendingMachineChemicals + +- type: pirateBounty + id: PirateBountyVendingMachine + reward: 6 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-vendingmachine + amount: 3 + whitelist: + id: + - VendingMachine + +- type: pirateBounty + id: PirateBountyMercSuit + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-mercSuit + amount: 2 + whitelist: + id: + - ClothingOuterHardsuitMercenary + +- type: pirateBounty + id: PirateBountyCappy + reward: 1 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-cappy + amount: 10 + whitelist: + id: + - MobCatCappy + +- type: pirateBounty + id: PirateBountyCultistNecklace + reward: 1 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-cultistNeck + amount: 4 + whitelist: + id: + - ClothingNeckAmuletBloodCult + +- type: pirateBounty + id: PirateBountyNfsdCampaign + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-nfsdCampaign + amount: 4 + whitelist: + id: + - ClothingHeadHatNfsdSmallCampaign + - ClothingHeadHatNfsdCampaign + +- type: pirateBounty + id: PirateBountyScafSuit + reward: 5 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-scafsuit + amount: 3 + whitelist: + id: + - ClothingOuterHardsuitScaf + +- type: pirateBounty + id: PirateBountyRTG + reward: 4 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-rtg + amount: 2 + whitelist: + id: + - GeneratorRTG + +- type: pirateBounty + id: PirateBountyMercGas + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-mercgas + amount: 4 + whitelist: + id: + - ClothingMaskGasMercenary + +- type: pirateBounty + id: PirateBountyRDHardsuit + reward: 1 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-rdhardsuit + amount: 3 + whitelist: + id: + - ClothingOuterHardsuitRd + +- type: pirateBounty + id: PirateBountyMK58 + reward: 5 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-mk58 + amount: 2 + whitelist: + id: + - WeaponPistolMk58 + +- type: pirateBounty + id: PirateBountyArtifactAnalyzer + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-artifactanalyzer + amount: 4 + whitelist: + id: + - MachineArtifactAnalyzer + +- type: pirateBounty + id: PirateBountyHotplate + reward: 1 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-hotplate + amount: 5 + whitelist: + id: + - ChemistryHotplate + +- type: pirateBounty + id: PirateBountyDeepFryer + reward: 1 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-deepfryer + amount: 4 + whitelist: + id: + - KitchenDeepFryer + +- type: pirateBounty + id: PirateBountyKeyCommon + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-keycommon + amount: 5 + whitelist: + id: + - EncryptionKeyCommon + +- type: pirateBounty + id: PirateBountyMedicalFabBoard + reward: 1 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-medicalfabboard + amount: 3 + whitelist: + id: + - MedicalTechFabCircuitboard + +- type: pirateBounty + id: PirateBountyHypo + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-hypo + amount: 6 + whitelist: + id: + - Hypospray + +- type: pirateBounty + id: PirateBountyOreBox + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-orebox + amount: 3 + whitelist: + id: + - OreBox + +- type: pirateBounty + id: PirateBountyAutolathe + reward: 2 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-autolathe + amount: 3 + whitelist: + id: + - Autolathe + +- type: pirateBounty + id: PirateBountyDiamond + reward: 4 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-diamond + amount: 5 + whitelist: + id: + - MaterialDiamond + +- type: pirateBounty + id: PirateBountyGold + reward: 4 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-gold + amount: 5 + whitelist: + id: + - OreGold + - IngotGold + +- type: pirateBounty + id: PirateBountyPlasmaCanister + reward: 4 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-plasmacanister + amount: 5 + whitelist: + id: + - PlasmaCanister + +- type: pirateBounty + id: PirateBountyContraCrate + reward: 3 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-contracrate + amount: 1 + whitelist: + id: + - CrateTradeContrabandSecureNormal + +- type: pirateBounty + id: PirateBountyHydroTray + reward: 4 + description: pirate-bounty-description-pirate + entries: + - name: pirate-bounty-item-hydrotray + amount: 2 + whitelist: + id: + - hydroponicsTray From 83bf58f290d042c5945bd9e5030383066eeb4e32 Mon Sep 17 00:00:00 2001 From: Salvantrix <149609610+Salvantrix@users.noreply.github.com> Date: Wed, 19 Jun 2024 09:45:12 -0400 Subject: [PATCH 06/83] Balance Pass Balanced a couple thing Leander Suggested. --- .../_NF/Catalog/Bounties/pirate_bounties.yml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml b/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml index 0e8254edebb..2b6d20405e9 100644 --- a/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml +++ b/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml @@ -103,11 +103,11 @@ - type: pirateBounty id: PirateBountyGravGen - reward: 2 + reward: 5 description: pirate-bounty-description-pirate entries: - name: pirate-bounty-item-gravGen - amount: 4 + amount: 2 whitelist: id: - GravityGenerator @@ -147,22 +147,22 @@ - type: pirateBounty id: PirateBountyCappy - reward: 1 + reward: 10 description: pirate-bounty-description-pirate entries: - name: pirate-bounty-item-cappy - amount: 10 + amount: 1 whitelist: id: - MobCatCappy - type: pirateBounty id: PirateBountyCultistNecklace - reward: 1 + reward: 4 description: pirate-bounty-description-pirate entries: - name: pirate-bounty-item-cultistNeck - amount: 4 + amount: 1 whitelist: id: - ClothingNeckAmuletBloodCult @@ -258,11 +258,11 @@ - type: pirateBounty id: PirateBountyDeepFryer - reward: 1 + reward: 5 description: pirate-bounty-description-pirate entries: - name: pirate-bounty-item-deepfryer - amount: 4 + amount: 2 whitelist: id: - KitchenDeepFryer @@ -280,22 +280,22 @@ - type: pirateBounty id: PirateBountyMedicalFabBoard - reward: 1 + reward: 4 description: pirate-bounty-description-pirate entries: - name: pirate-bounty-item-medicalfabboard - amount: 3 + amount: 2 whitelist: id: - MedicalTechFabCircuitboard - type: pirateBounty id: PirateBountyHypo - reward: 3 + reward: 2 description: pirate-bounty-description-pirate entries: - name: pirate-bounty-item-hypo - amount: 6 + amount: 1 whitelist: id: - Hypospray From ccf72b4b3c3729aafea30c3e9d6f3d3d94f0744c Mon Sep 17 00:00:00 2001 From: Whatstone Date: Wed, 19 Jun 2024 10:53:15 -0400 Subject: [PATCH 07/83] Pirate bounty components & systems, ROUGH DRAFT. --- .../Cargo/Systems/CargoSystem.Bounty.cs | 4 + Content.Server/Cargo/Systems/CargoSystem.cs | 6 + .../_NF/Cargo/CargoSystem.PirateBounty.cs | 480 ++++++++++++++++++ .../Components/PirateBountyLabelComponent.cs | 28 + .../StationPirateBountyDatabaseComponent.cs | 48 ++ .../Pirate/PirateBountyConsoleComponent.cs | 60 +++ Content.Shared/_NF/Pirate/PirateBountyData.cs | 31 ++ .../Prototypes/PirateBountyPrototype.cs | 2 +- 8 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs create mode 100644 Content.Server/_NF/Pirate/Components/PirateBountyLabelComponent.cs create mode 100644 Content.Server/_NF/Pirate/Components/StationPirateBountyDatabaseComponent.cs create mode 100644 Content.Shared/_NF/Pirate/PirateBountyConsoleComponent.cs create mode 100644 Content.Shared/_NF/Pirate/PirateBountyData.cs rename Content.Shared/_NF/{Cargo => Pirate}/Prototypes/PirateBountyPrototype.cs (97%) diff --git a/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs b/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs index e132e4f12a3..13748ff324e 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs @@ -163,6 +163,10 @@ private void OnSold(ref EntitySoldEvent args) { foreach (var sold in args.Sold) { + // Frontier: check if this bounty's one of ours first. + if (HandlePirateBounty(sold)) + continue; + // End Frontier if (!TryGetBountyLabel(sold, out _, out var component)) continue; diff --git a/Content.Server/Cargo/Systems/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs index b127ae43667..a04837d4917 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.cs @@ -70,6 +70,9 @@ public override void Initialize() InitializeShuttle(); InitializeTelepad(); InitializeBounty(); + // Frontier: add specific initialization calls here. + InitializePirateBounty(); + // End Frontier } public override void Update(float frameTime) @@ -78,6 +81,9 @@ public override void Update(float frameTime) UpdateConsole(frameTime); UpdateTelepad(frameTime); UpdateBounty(); + // Frontier: add specific initialization calls here. + UpdatePirateBounty(); + // End Frontier } [PublicAPI] diff --git a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs new file mode 100644 index 00000000000..3b2c5432db1 --- /dev/null +++ b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs @@ -0,0 +1,480 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Server.Cargo.Components; +using Content.Server.Labels; +using Content.Server.NameIdentifier; +using Content.Server.Paper; +using Content.Shared._NF.Pirate; +using Content.Shared._NF.Pirate.Components; +using Content.Shared._NF.Pirate.Prototypes; +using Content.Shared.Access.Components; +using Content.Shared.Cargo; +using Content.Shared.Cargo.Components; +using Content.Shared.Cargo.Prototypes; +using Content.Shared.Database; +using Content.Shared.NameIdentifier; +using Content.Shared.Stacks; +using JetBrains.Annotations; +using Robust.Server.Containers; +using Robust.Shared.Containers; +using Robust.Shared.Random; +using Robust.Shared.Utility; + +namespace Content.Server.Cargo.Systems; // Needs to collide with base namespace + +public sealed partial class CargoSystem +{ + [ValidatePrototypeId] + private const string PirateBountyNameIdentifierGroup = "PirateBounty"; + + private EntityQuery _pirateBountyLabelQuery; + + // GROSS. + private void InitializePirateBounty() + { + SubscribeLocalEvent(OnPirateBountyConsoleOpened); + SubscribeLocalEvent(OnPiratePrintLabelMessage); + SubscribeLocalEvent(OnSkipPirateBountyMessage); + SubscribeLocalEvent(OnGetPirateBountyPrice); // TODO: figure out how these labels interact with the chest (does the chest RECEIVE the label component?) + //SubscribeLocalEvent(OnPirateSold); // FIXME: figure this out + SubscribeLocalEvent(OnPirateMapInit); + + _pirateBountyLabelQuery = GetEntityQuery(); + } + + private void OnPirateBountyConsoleOpened(EntityUid uid, PirateBountyConsoleComponent component, BoundUIOpenedEvent args) + { + if (_station.GetOwningStation(uid) is not { } station || + !TryComp(station, out var bountyDb)) + return; + + var untilNextSkip = bountyDb.NextSkipTime - _timing.CurTime; + _uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties, untilNextSkip)); + } + + private void OnPiratePrintLabelMessage(EntityUid uid, PirateBountyConsoleComponent component, BountyPrintLabelMessage args) + { + if (_timing.CurTime < component.NextPrintTime) + return; + + if (_station.GetOwningStation(uid) is not { } station) + return; + + if (!TryGetBountyFromId(station, args.BountyId, out var bounty)) + return; + + var label = Spawn(component.BountyLabelId, Transform(uid).Coordinates); + component.NextPrintTime = _timing.CurTime + component.PrintDelay; + SetupBountyLabel(label, station, bounty.Value); + _audio.PlayPvs(component.PrintSound, uid); + } + + private void OnSkipPirateBountyMessage(EntityUid uid, PirateBountyConsoleComponent component, BountySkipMessage args) + { + if (_station.GetOwningStation(uid) is not { } station || !TryComp(station, out var db)) + return; + + if (_timing.CurTime < db.NextSkipTime) + return; + + if (!TryGetBountyFromId(station, args.BountyId, out var bounty)) + return; + + if (args.Actor is not { Valid: true } mob) + return; + + if (TryComp(uid, out var accessReaderComponent) && + !_accessReaderSystem.IsAllowed(mob, uid, accessReaderComponent)) + { + _audio.PlayPvs(component.DenySound, uid); + return; + } + + if (!TryRemoveBounty(station, bounty.Value)) + return; + + FillBountyDatabase(station); + db.NextSkipTime = _timing.CurTime + db.SkipDelay; + var untilNextSkip = db.NextSkipTime - _timing.CurTime; + _uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip)); + _audio.PlayPvs(component.SkipSound, uid); + } + + public void SetupPirateBountyLabel(EntityUid uid, EntityUid stationId, CargoBountyData bounty, PaperComponent? paper = null, CargoBountyLabelComponent? label = null) + { + if (!Resolve(uid, ref paper, ref label) || !_protoMan.TryIndex(bounty.Bounty, out var prototype)) + return; + + label.Id = bounty.Id; + label.AssociatedStationId = stationId; + var msg = new FormattedMessage(); + msg.AddText(Loc.GetString("bounty-manifest-header", ("id", bounty.Id))); + msg.PushNewline(); + msg.AddText(Loc.GetString("bounty-manifest-list-start")); + msg.PushNewline(); + foreach (var entry in prototype.Entries) + { + msg.AddMarkup($"- {Loc.GetString("bounty-console-manifest-entry", + ("amount", entry.Amount), + ("item", Loc.GetString(entry.Name)))}"); + msg.PushNewline(); + } + _paperSystem.SetContent(uid, msg.ToMarkup(), paper); + } + + /// + /// Bounties do not sell for any currency. The reward for a bounty is + /// calculated after it is sold separately from the selling system. + /// + private void OnGetPirateBountyPrice(EntityUid uid, PirateBountyLabelComponent component, ref PriceCalculationEvent args) + { + if (args.Handled || component.Calculating) + return; + + // make sure this label was actually applied to a crate. + if (!_container.TryGetContainingContainer(uid, out var container) || container.ID != LabelSystem.ContainerName) + return; + + if (component.AssociatedStationId is not { } station || !TryComp(station, out var database)) + return; + + if (database.CheckedBounties.Contains(component.Id)) + return; + + if (!TryGetPirateBountyFromId(station, component.Id, out var bounty, database)) + return; + + if (!_protoMan.TryIndex(bounty.Value.Bounty, out var bountyPrototype) || + !IsPirateBountyComplete(container.Owner, bountyPrototype)) + return; + + database.CheckedBounties.Add(component.Id); + args.Handled = true; + + component.Calculating = true; + args.Price = bountyPrototype.Reward - _pricing.GetPrice(container.Owner); + component.Calculating = false; + } + + // Receives a bounty that's been sold. + // Returns true if the bounty has been handled, false otherwise. + private bool HandlePirateBounty(EntityUid uid) + { + if (!TryGetBountyLabel(uid, out _, out var component)) + return false; + + if (component.AssociatedStationId is not { } station || !TryGetPirateBountyFromId(station, component.Id, out var bounty)) + { + return false; + } + + if (!IsPirateBountyComplete(uid, bounty.Value)) + { + return false; + } + + TryRemovePirateBounty(station, bounty.Value); + FillPirateBountyDatabase(station); + _adminLogger.Add(LogType.Action, LogImpact.Low, $"Bounty \"{bounty.Value.Bounty}\" (id:{bounty.Value.Id}) was fulfilled"); + return false; + } + + private bool TryGetPirateBountyLabel(EntityUid uid, + [NotNullWhen(true)] out EntityUid? labelEnt, + [NotNullWhen(true)] out CargoBountyLabelComponent? labelComp) + { + labelEnt = null; + labelComp = null; + if (!_containerQuery.TryGetComponent(uid, out var containerMan)) + return false; + + // make sure this label was actually applied to a crate. + if (!_container.TryGetContainer(uid, LabelSystem.ContainerName, out var container, containerMan)) + return false; + + if (container.ContainedEntities.FirstOrNull() is not { } label || + !_bountyLabelQuery.TryGetComponent(label, out var component)) + return false; + + labelEnt = label; + labelComp = component; + return true; + } + + // TODO: Fix this stupid name + private void OnPirateMapInit(EntityUid uid, StationCargoBountyDatabaseComponent component, MapInitEvent args) + { + FillPirateBountyDatabase(uid, component); + } + + /// + /// Fills up the bounty database with random bounties. + /// + public void FillPirateBountyDatabase(EntityUid uid, StationCargoBountyDatabaseComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + while (component.Bounties.Count < component.MaxBounties) + { + if (!TryAddBounty(uid, component)) + break; + } + + UpdateBountyConsoles(); + } + + public void RerollPirateBountyDatabase(Entity entity) + { + if (!Resolve(entity, ref entity.Comp)) + return; + + entity.Comp.Bounties.Clear(); + FillPirateBountyDatabase(entity); + } + + public bool IsPirateBountyComplete(EntityUid container, out HashSet bountyEntities) + { + if (!TryGetPirateBountyLabel(container, out _, out var component)) + { + bountyEntities = new(); + return false; + } + + var station = component.AssociatedStationId; + if (station == null) + { + bountyEntities = new(); + return false; + } + + if (!TryGetPirateBountyFromId(station.Value, component.Id, out var bounty)) + { + bountyEntities = new(); + return false; + } + + return IsPirateBountyComplete(container, bounty.Value, out bountyEntities); + } + + public bool IsPirateBountyComplete(EntityUid container, PirateBountyData data) + { + return IsPirateBountyComplete(container, data, out _); + } + + public bool IsPirateBountyComplete(EntityUid container, PirateBountyData data, out HashSet bountyEntities) + { + if (!_protoMan.TryIndex(data.Bounty, out var proto)) + { + bountyEntities = new(); + return false; + } + + return IsPirateBountyComplete(container, proto.Entries, out bountyEntities); + } + + public bool IsPirateBountyComplete(EntityUid container, string id) + { + if (!_protoMan.TryIndex(id, out var proto)) + return false; + + return IsPirateBountyComplete(container, proto.Entries); + } + + public bool IsPirateBountyComplete(EntityUid container, PirateBountyPrototype prototype) + { + return IsPirateBountyComplete(container, prototype.Entries); + } + + public bool IsPirateBountyComplete(EntityUid container, IEnumerable entries) + { + return IsPirateBountyComplete(container, entries, out _); + } + + public bool IsPirateBountyComplete(EntityUid container, IEnumerable entries, out HashSet bountyEntities) + { + return IsPirateBountyComplete(GetBountyEntities(container), entries, out bountyEntities); + } + + public bool IsPirateBountyComplete(HashSet entities, IEnumerable entries, out HashSet bountyEntities) + { + bountyEntities = new(); + + foreach (var entry in entries) + { + var count = 0; + + // store entities that already satisfied an + // entry so we don't double-count them. + var temp = new HashSet(); + foreach (var entity in entities) + { + if (!entry.Whitelist.IsValid(entity, EntityManager)) + continue; + + count += _stackQuery.CompOrNull(entity)?.Count ?? 1; + temp.Add(entity); + + if (count >= entry.Amount) + break; + } + + if (count < entry.Amount) + return false; + + foreach (var ent in temp) + { + entities.Remove(ent); + bountyEntities.Add(ent); + } + } + + return true; + } + + private HashSet GetPirateBountyEntities(EntityUid uid) + { + var entities = new HashSet + { + uid + }; + if (!TryComp(uid, out var containers)) + return entities; + + foreach (var container in containers.Containers.Values) + { + foreach (var ent in container.ContainedEntities) + { + if (_bountyLabelQuery.HasComponent(ent)) + continue; + + var children = GetPirateBountyEntities(ent); + foreach (var child in children) + { + entities.Add(child); + } + } + } + + return entities; + } + + [PublicAPI] + public bool TryAddPirateBounty(EntityUid uid, StationCargoBountyDatabaseComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + // todo: consider making the cargo bounties weighted. + var allBounties = _protoMan.EnumeratePrototypes().ToList(); + var filteredBounties = new List(); + foreach (var proto in allBounties) + { + if (component.Bounties.Any(b => b.Bounty == proto.ID)) + continue; + filteredBounties.Add(proto); + } + + var pool = filteredBounties.Count == 0 ? allBounties : filteredBounties; + var bounty = _random.Pick(pool); + return TryAddBounty(uid, bounty, component); + } + + [PublicAPI] + public bool TryAddPirateBounty(EntityUid uid, string bountyId, StationPirateBountyDatabaseComponent? component = null) + { + if (!_protoMan.TryIndex(bountyId, out var bounty)) + { + return false; + } + + return TryAddPirateBounty(uid, bounty, component); + } + + public bool TryAddPirateBounty(EntityUid uid, PirateBountyPrototype bounty, StationPirateBountyDatabaseComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (component.Bounties.Count >= component.MaxBounties) + return false; + + _nameIdentifier.GenerateUniqueName(uid, BountyNameIdentifierGroup, out var randomVal); // Need a string ID for internal name, probably doesn't need to be outward facing. + component.Bounties.Add(new PirateBountyData(bounty, randomVal)); + _adminLogger.Add(LogType.Action, LogImpact.Low, $"Added bounty \"{bounty.ID}\" (id:{component.TotalBounties}) to station {ToPrettyString(uid)}"); + component.TotalBounties++; + return true; + } + + [PublicAPI] + public bool TryRemovePirateBounty(EntityUid uid, string dataId, StationPirateBountyDatabaseComponent? component = null) + { + if (!TryGetPirateBountyFromId(uid, dataId, out var data, component)) + return false; + + return TryRemovePirateBounty(uid, data.Value, component); + } + + public bool TryRemovePirateBounty(EntityUid uid, PirateBountyData data, StationPirateBountyDatabaseComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + for (var i = 0; i < component.Bounties.Count; i++) + { + if (component.Bounties[i].Id == data.Id) + { + component.Bounties.RemoveAt(i); + return true; + } + } + + return false; + } + + public bool TryGetPirateBountyFromId( + EntityUid uid, + string id, + [NotNullWhen(true)] out PirateBountyData? bounty, + StationPirateBountyDatabaseComponent? component = null) + { + bounty = null; + if (!Resolve(uid, ref component)) + return false; + + foreach (var bountyData in component.Bounties) + { + if (bountyData.Id != id) + continue; + bounty = bountyData; + break; + } + + return bounty != null; + } + + public void UpdatePirateBountyConsoles() + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out var ui)) + { + if (_station.GetOwningStation(uid) is not { } station || + !TryComp(station, out var db)) + { + continue; + } + + var untilNextSkip = db.NextSkipTime - _timing.CurTime; + _uiSystem.SetUiState((uid, ui), CargoConsoleUiKey.Bounty, new PirateBountyConsoleState(db.Bounties, untilNextSkip)); + } + } + + private void UpdatePirateBounty() + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var bountyDatabase)) + { + bountyDatabase.CheckedBounties.Clear(); + } + } +} diff --git a/Content.Server/_NF/Pirate/Components/PirateBountyLabelComponent.cs b/Content.Server/_NF/Pirate/Components/PirateBountyLabelComponent.cs new file mode 100644 index 00000000000..6a245f29d51 --- /dev/null +++ b/Content.Server/_NF/Pirate/Components/PirateBountyLabelComponent.cs @@ -0,0 +1,28 @@ +using Content.Server.Station.Systems; + +namespace Content.Server.Cargo.Components; + +/// +/// This is used for marking containers as +/// containing goods for fulfilling bounties. +/// +[RegisterComponent] +public sealed partial class PirateBountyLabelComponent : Component +{ + /// + /// The ID for the bounty this label corresponds to. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Id = string.Empty; + + /// + /// Used to prevent recursion in calculating the price. + /// + public bool Calculating; + + /// + /// The Station System to check and remove bounties from + /// + [DataField] + public EntityUid? AssociatedStationId; +} diff --git a/Content.Server/_NF/Pirate/Components/StationPirateBountyDatabaseComponent.cs b/Content.Server/_NF/Pirate/Components/StationPirateBountyDatabaseComponent.cs new file mode 100644 index 00000000000..b6fe700d6f8 --- /dev/null +++ b/Content.Server/_NF/Pirate/Components/StationPirateBountyDatabaseComponent.cs @@ -0,0 +1,48 @@ +using Content.Shared._NF.Pirate; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Server.Cargo.Components; + +/// +/// Stores all active cargo bounties for a particular station. +/// +[RegisterComponent] +public sealed partial class StationPirateBountyDatabaseComponent : Component +{ + /// + /// Maximum amount of bounties a station can have. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int MaxBounties = 6; + + /// + /// A list of all the bounties currently active for a station. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public List Bounties = new(); + + /// + /// Used to determine unique order IDs + /// + [DataField] + public int TotalBounties; + + /// + /// A list of bounty IDs that have been checked this tick. + /// Used to prevent multiplying bounty prices. + /// + [DataField] + public HashSet CheckedBounties = new(); + + /// + /// The time at which players will be able to skip the next bounty. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextSkipTime = TimeSpan.Zero; + + /// + /// The time between skipping bounties. + /// + [DataField] + public TimeSpan SkipDelay = TimeSpan.FromMinutes(15); +} diff --git a/Content.Shared/_NF/Pirate/PirateBountyConsoleComponent.cs b/Content.Shared/_NF/Pirate/PirateBountyConsoleComponent.cs new file mode 100644 index 00000000000..b7bb5dfb60d --- /dev/null +++ b/Content.Shared/_NF/Pirate/PirateBountyConsoleComponent.cs @@ -0,0 +1,60 @@ +using Robust.Shared.Audio; +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._NF.Pirate.Components; + +[RegisterComponent] +public sealed partial class PirateBountyConsoleComponent : Component +{ + /// + /// The id of the label entity spawned by the print label button. + /// + [DataField("bountyLabelId", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string BountyLabelId = "PaperCargoBountyManifest"; // TODO: make some paper + + /// + /// The time at which the console will be able to print a label again. + /// + [DataField("nextPrintTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextPrintTime = TimeSpan.Zero; + + /// + /// The time between prints. + /// + [DataField("printDelay")] + public TimeSpan PrintDelay = TimeSpan.FromSeconds(5); + + /// + /// The sound made when printing occurs + /// + [DataField("printSound")] + public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg"); + + /// + /// The sound made when the bounty is skipped. + /// + [DataField("skipSound")] + public SoundSpecifier SkipSound = new SoundPathSpecifier("/Audio/Effects/Cargo/ping.ogg"); + + /// + /// The sound made when bounty skipping is denied due to lacking access. + /// + [DataField("denySound")] + public SoundSpecifier DenySound = new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_two.ogg"); +} + +[NetSerializable, Serializable] +public sealed class PirateBountyConsoleState : BoundUserInterfaceState +{ + public List Bounties; + public TimeSpan UntilNextSkip; + + public PirateBountyConsoleState(List bounties, TimeSpan untilNextSkip) + { + Bounties = bounties; + UntilNextSkip = untilNextSkip; + } +} diff --git a/Content.Shared/_NF/Pirate/PirateBountyData.cs b/Content.Shared/_NF/Pirate/PirateBountyData.cs new file mode 100644 index 00000000000..20f52705386 --- /dev/null +++ b/Content.Shared/_NF/Pirate/PirateBountyData.cs @@ -0,0 +1,31 @@ +using Robust.Shared.Serialization; +using Robust.Shared.Prototypes; +using Content.Shared._NF.Pirate.Prototypes; + +namespace Content.Shared._NF.Pirate; + +/// +/// A data structure for storing currently available bounties. +/// +[DataDefinition, NetSerializable, Serializable] +public readonly partial record struct PirateBountyData +{ + /// + /// A unique id used to identify the bounty + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Id { get; init; } = string.Empty; + + /// + /// The prototype containing information about the bounty. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] + public ProtoId Bounty { get; init; } = string.Empty; + + public PirateBountyData(PirateBountyPrototype bounty, int uniqueIdentifier) + { + Bounty = bounty.ID; + Id = $"{bounty.IdPrefix}{uniqueIdentifier:D3}"; + } +} diff --git a/Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs b/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs similarity index 97% rename from Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs rename to Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs index bf9f11826da..f2b39893818 100644 --- a/Content.Shared/_NF/Cargo/Prototypes/PirateBountyPrototype.cs +++ b/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -namespace Content.Shared.Cargo.Prototypes; +namespace Content.Shared._NF.Pirate.Prototypes; /// /// This is a prototype for a pirate bounty, a set of items From bff0941815ce0559ef9d5a5f04855c698708d819 Mon Sep 17 00:00:00 2001 From: Whatstone Date: Wed, 19 Jun 2024 11:22:26 -0400 Subject: [PATCH 08/83] Pirate bounty/pallet console UI (ROUGH DRAFT --- .../PirateBountyConsoleBoundUserInterface.cs | 57 ++++++++++ .../PiratePalletConsoleBoundUserInterface.cs | 52 +++++++++ .../Pirate/Systems/PirateSystem.Telepad.cs | 105 ++++++++++++++++++ .../_NF/Pirate/Systems/PirateSystem.cs | 15 +++ .../_NF/Pirate/UI/PirateBountyEntry.xaml | 37 ++++++ .../_NF/Pirate/UI/PirateBountyEntry.xaml.cs | 70 ++++++++++++ .../_NF/Pirate/UI/PirateBountyMenu.xaml | 37 ++++++ .../_NF/Pirate/UI/PirateBountyMenu.xaml.cs | 36 ++++++ .../_NF/Pirate/UI/PiratePalletMenu.xaml | 11 ++ .../_NF/Pirate/UI/PiratePalletMenu.xaml.cs | 24 ++++ 10 files changed, 444 insertions(+) create mode 100644 Content.Client/_NF/Pirate/BUI/PirateBountyConsoleBoundUserInterface.cs create mode 100644 Content.Client/_NF/Pirate/BUI/PiratePalletConsoleBoundUserInterface.cs create mode 100644 Content.Client/_NF/Pirate/Systems/PirateSystem.Telepad.cs create mode 100644 Content.Client/_NF/Pirate/Systems/PirateSystem.cs create mode 100644 Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml create mode 100644 Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs create mode 100644 Content.Client/_NF/Pirate/UI/PirateBountyMenu.xaml create mode 100644 Content.Client/_NF/Pirate/UI/PirateBountyMenu.xaml.cs create mode 100644 Content.Client/_NF/Pirate/UI/PiratePalletMenu.xaml create mode 100644 Content.Client/_NF/Pirate/UI/PiratePalletMenu.xaml.cs diff --git a/Content.Client/_NF/Pirate/BUI/PirateBountyConsoleBoundUserInterface.cs b/Content.Client/_NF/Pirate/BUI/PirateBountyConsoleBoundUserInterface.cs new file mode 100644 index 00000000000..4c9bf1280bb --- /dev/null +++ b/Content.Client/_NF/Pirate/BUI/PirateBountyConsoleBoundUserInterface.cs @@ -0,0 +1,57 @@ +using Content.Client._NF.Pirate.UI; +using Content.Shared.Cargo.Components; +using JetBrains.Annotations; + +namespace Content.Client._NF.Pirate.BUI; + +[UsedImplicitly] +public sealed class PirateBountyConsoleBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private PirateBountyMenu? _menu; + + public PirateBountyConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _menu = new(); + + _menu.OnClose += Close; + + _menu.OnLabelButtonPressed += id => + { + SendMessage(new PirateBountyPrintLabelMessage(id)); + }; + + _menu.OnSkipButtonPressed += id => + { + SendMessage(new PirateBountySkipMessage(id)); + }; + + _menu.OpenCentered(); + } + + protected override void UpdateState(BoundUserInterfaceState message) + { + base.UpdateState(message); + + if (message is not PirateBountyConsoleState state) + return; + + _menu?.UpdateEntries(state.Bounties, state.UntilNextSkip); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) + return; + + _menu?.Dispose(); + } +} diff --git a/Content.Client/_NF/Pirate/BUI/PiratePalletConsoleBoundUserInterface.cs b/Content.Client/_NF/Pirate/BUI/PiratePalletConsoleBoundUserInterface.cs new file mode 100644 index 00000000000..0b72751b040 --- /dev/null +++ b/Content.Client/_NF/Pirate/BUI/PiratePalletConsoleBoundUserInterface.cs @@ -0,0 +1,52 @@ +using Content.Client._NF.Pirate.UI; +using Content.Shared._NF.Pirate.BUI; +using Content.Shared._NF.Pirate.Events; +using Robust.Client.GameObjects; + +namespace Content.Client._NF.Pirate.BUI; + +public sealed class PiratePalletConsoleBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private PiratePalletMenu? _menu; + + public PiratePalletConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _menu = new PiratePalletMenu(); + _menu.SellRequested += OnSell; + _menu.OnClose += Close; + + _menu.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _menu?.Dispose(); + } + } + + private void OnSell() + { + SendMessage(new PiratePalletSellMessage()); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (state is not PiratePalletConsoleInterfaceState palletState) + return; + + _menu?.SetEnabled(palletState.Enabled); + _menu?.SetCount(palletState.Count); + } +} diff --git a/Content.Client/_NF/Pirate/Systems/PirateSystem.Telepad.cs b/Content.Client/_NF/Pirate/Systems/PirateSystem.Telepad.cs new file mode 100644 index 00000000000..41b4e57f358 --- /dev/null +++ b/Content.Client/_NF/Pirate/Systems/PirateSystem.Telepad.cs @@ -0,0 +1,105 @@ +using Content.Shared._NF.Pirate; +using Content.Shared._NF.Pirate.Components; +using JetBrains.Annotations; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; + +namespace Content.Client._NF.Pirate.Systems; + +public sealed partial class PirateSystem +{ + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + private static readonly Animation PirateTelepadBeamAnimation = new() + { + Length = TimeSpan.FromSeconds(0.5), + AnimationTracks = + { + new AnimationTrackSpriteFlick + { + LayerKey = PirateTelepadLayers.Beam, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(new RSI.StateId("beam"), 0f) + } + } + } + }; + + private static readonly Animation PirateTelepadIdleAnimation = new() + { + Length = TimeSpan.FromSeconds(0.8), + AnimationTracks = + { + new AnimationTrackSpriteFlick + { + LayerKey = PirateTelepadLayers.Beam, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(new RSI.StateId("idle"), 0f) + } + } + } + }; + + // TODO: fluent entries for this + private const string TelepadBeamKey = "pirate-telepad-beam"; + private const string TelepadIdleKey = "pirate-telepad-idle"; + + private void InitializePirateTelepad() + { + SubscribeLocalEvent(OnPirateAppChange); + SubscribeLocalEvent(OnPirateAnimComplete); + } + + private void OnPirateAppChange(EntityUid uid, PirateTelepadComponent component, ref AppearanceChangeEvent args) + { + OnChangeData(uid, args.Sprite); + } + + private void OnPirateAnimComplete(EntityUid uid, PirateTelepadComponent component, AnimationCompletedEvent args) + { + OnChangeData(uid); + } + + private void OnChangeData(EntityUid uid, SpriteComponent? sprite = null) + { + if (!Resolve(uid, ref sprite)) + return; + + _appearance.TryGetData(uid, PirateTelepadVisuals.State, out var state); + AnimationPlayerComponent? player = null; + + switch (state) + { + case PirateTelepadState.Teleporting: + if (_player.HasRunningAnimation(uid, TelepadBeamKey)) + return; + _player.Stop(uid, player, TelepadIdleKey); + _player.Play(uid, player, PirateTelepadBeamAnimation, TelepadBeamKey); + break; + case PirateTelepadState.Unpowered: + sprite.LayerSetVisible(PirateTelepadLayers.Beam, false); + _player.Stop(uid, player, TelepadBeamKey); + _player.Stop(uid, player, TelepadIdleKey); + break; + default: + sprite.LayerSetVisible(PirateTelepadLayers.Beam, true); + + if (_player.HasRunningAnimation(uid, player, TelepadIdleKey) || + _player.HasRunningAnimation(uid, player, TelepadBeamKey)) + return; + + _player.Play(uid, player, PirateTelepadIdleAnimation, TelepadIdleKey); + break; + } + } + + [UsedImplicitly] + private enum PirateTelepadLayers : byte + { + Base = 0, + Beam = 1, + } +} diff --git a/Content.Client/_NF/Pirate/Systems/PirateSystem.cs b/Content.Client/_NF/Pirate/Systems/PirateSystem.cs new file mode 100644 index 00000000000..0b955c5b8a8 --- /dev/null +++ b/Content.Client/_NF/Pirate/Systems/PirateSystem.cs @@ -0,0 +1,15 @@ +using Content.Shared._NF.Pirate; +using Robust.Client.GameObjects; + +namespace Content.Client._NF.Pirate.Systems; + +public sealed partial class PirateSystem : SharedPirateSystem +{ + [Dependency] private readonly AnimationPlayerSystem _player = default!; + + public override void Initialize() + { + base.Initialize(); + InitializePirateTelepad(); + } +} diff --git a/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml b/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml new file mode 100644 index 00000000000..7c61323bd55 --- /dev/null +++ b/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + [DataField("bountyLabelId", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string BountyLabelId = "PaperCargoBountyManifest"; // TODO: make some paper + public string BountyLabelId = "PaperPirateBountyManifest"; // TODO: make some paper + /// + /// The id of the label entity spawned by the print label button. + /// + [DataField("bountyCrateId", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string BountyCrateId = "CratePirateBounty"; // TODO: make some paper /// /// The time at which the console will be able to print a label again. diff --git a/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs b/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs index fb699806c12..0add1563364 100644 --- a/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs +++ b/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs @@ -38,7 +38,7 @@ public sealed partial class PirateBountyPrototype : IPrototype /// Whether or not to spawn a chest for this item. /// [DataField] - public bool SummonChest = true; + public bool SpawnChest = true; /// /// A prefix appended to the beginning of a bounty's ID. diff --git a/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl b/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl index 5dbd115be76..c9edfe3c556 100644 --- a/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl +++ b/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl @@ -1,5 +1,6 @@ pirate-bounty-console-menu-title = Pirate bounty console -pirate-bounty-console-label-button-text = Summon chest +pirate-bounty-console-accept-button-chest = Accept (crate) +pirate-bounty-console-accept-button-label = Accept pirate-bounty-console-skip-button-text = Skip pirate-bounty-console-time-label = Time: [color=orange]{$time}[/color] pirate-bounty-console-reward-label = Reward: [color=limegreen]${$reward}[/color] @@ -13,6 +14,7 @@ pirate-bounty-console-manifest-reward = Reward: {$reward} DB pirate-bounty-console-description-label = [color=gray]{$description}[/color] pirate-bounty-console-id-label = {$id} + pirate-bounty-console-flavor-left = Go and plunder, me hearties! Down with NT! pirate-bounty-console-flavor-right = v0.0.1a diff --git a/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml b/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml index 03f26fba8ad..e67ece293fb 100644 --- a/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml +++ b/Resources/Prototypes/_NF/Catalog/Bounties/pirate_bounties.yml @@ -52,7 +52,7 @@ id: PirateBountyGyro reward: 4 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-gyro amount: 2 @@ -89,7 +89,7 @@ id: PirateBountyAlcohol reward: 4 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-alcohol amount: 2 @@ -101,7 +101,7 @@ id: PirateBountyThruster reward: 4 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-thruster amount: 4 @@ -114,7 +114,7 @@ id: PirateBountyGravGen reward: 5 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-gravGen amount: 2 @@ -126,7 +126,7 @@ id: PirateBountyChemVend reward: 3 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-chemVend amount: 1 @@ -138,7 +138,7 @@ id: PirateBountyVendingMachine reward: 6 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-vendingmachine amount: 3 @@ -263,7 +263,7 @@ id: PirateBountyHotplate reward: 5 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-hotplate amount: 1 @@ -275,7 +275,7 @@ id: PirateBountyDeepFryer reward: 5 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-deepfryer amount: 2 @@ -320,7 +320,7 @@ id: PirateBountyOreBox reward: 3 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-orebox amount: 2 @@ -332,7 +332,7 @@ id: PirateBountyAutolathe reward: 3 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-autolathe amount: 2 @@ -368,7 +368,7 @@ id: PirateBountyPlasmaCanister reward: 5 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-plasmacanister amount: 4 @@ -380,7 +380,7 @@ id: PirateBountyContraCrate reward: 3 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-contracrate amount: 1 @@ -392,7 +392,7 @@ id: PirateBountyHydroTray reward: 4 description: pirate-bounty-description-generic - summonChest: false + spawnChest: false entries: - name: pirate-bounty-item-hydrotray amount: 2 diff --git a/Resources/Prototypes/_NF/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/_NF/Entities/Objects/Misc/paper.yml new file mode 100644 index 00000000000..0060be0580b --- /dev/null +++ b/Resources/Prototypes/_NF/Entities/Objects/Misc/paper.yml @@ -0,0 +1,31 @@ +- type: entity + id: PaperPirateBountyManifest + parent: PaperCargoInvoice + name: pirate bounty reminder + description: A little scroll reminding you of the bounty you agreed to pilfer. How is it stained? + components: + - type: Sprite + layers: + - state: paper + color: "#f7e574" + - state: paper_words + map: ["enum.PaperVisualLayers.Writing"] + color: "#f7e574" + visible: false + - state: paper_stamp-trader + map: ["enum.PaperVisualLayers.Stamp"] + visible: false + - type: PaperVisuals # TODO: fix this up + backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png" + contentImagePath: "/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png" + backgroundModulate: "#f7e574" + contentImageModulate: "#f7e574" + backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0 + contentMargin: 16.0, 16.0, 16.0, 16.0 + headerImagePath: "/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png" + headerMargin: 0.0, 12.0, 0.0, 0.0 + - type: StaticPrice + price: 0 + # - type: GuideHelp # Frontier: removed guidebook entries + # guides: # Frontier: removed guidebook entries + # - Pirate # Frontier: add this eventually From 2fa0a57166258828043b1a057e3f67ef9c584cfa Mon Sep 17 00:00:00 2001 From: Whatstone Date: Wed, 17 Jul 2024 17:30:17 -0400 Subject: [PATCH 47/83] PirateBountyEntry: access button rewrite --- Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs b/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs index 4a43b3987af..b8397f05033 100644 --- a/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs +++ b/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs @@ -3,6 +3,7 @@ using Content.Shared._NF.Pirate.Prototypes; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; +using Robust.Client.AutoGenerated; using Robust.Shared.Prototypes; using Robust.Shared.Timing; From 6f5048628428a345dbbc4f999c7e1ed93f483b7b Mon Sep 17 00:00:00 2001 From: Whatstone Date: Fri, 19 Jul 2024 12:20:31 -0400 Subject: [PATCH 48/83] cancel vs. skip, spawning fixes --- .../_NF/Pirate/UI/PirateBountyEntry.xaml.cs | 6 +++--- .../_NF/Cargo/CargoSystem.PirateBounty.cs | 16 ++++++++++------ .../SectorPirateBountyDatabaseComponent.cs | 6 ++++++ .../en-US/_NF/cargo/pirate-bounty-console.ftl | 1 + 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs b/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs index b8397f05033..a713018ff67 100644 --- a/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs +++ b/Content.Client/_NF/Pirate/UI/PirateBountyEntry.xaml.cs @@ -22,13 +22,13 @@ public sealed partial class PirateBountyEntry : BoxContainer public bool Accepted; - public PirateBountyEntry(PirateBountyData bounty, bool accepted, TimeSpan untilNextSkip) + public PirateBountyEntry(PirateBountyData bounty, TimeSpan untilNextSkip) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); UntilNextSkip = untilNextSkip; - Accepted = accepted; + Accepted = bounty.Accepted; if (!_prototype.TryIndex(bounty.Bounty, out var bountyPrototype)) return; @@ -59,7 +59,7 @@ private void UpdateSkipButton(float deltaSeconds) if (Accepted) { SkipButton.Label.Text = Loc.GetString("pirate-bounty-console-skip-button-accepted"); - SkipButton.Disabled = true; + SkipButton.Disabled = false; return; } diff --git a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs index 239fee9ea7b..e6d7eb4195a 100644 --- a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs +++ b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs @@ -14,6 +14,7 @@ using Content.Shared.Database; using Content.Shared.NameIdentifier; using Content.Shared.Stacks; +using FastAccessors; using JetBrains.Annotations; using Robust.Server.Containers; using Robust.Shared.Containers; @@ -75,12 +76,11 @@ private void OnPirateBountyAccept(EntityUid uid, PirateBountyConsoleComponent co TryOverwritePirateBountyFromId(service, bountyData); - if (bountyData.Bounty.SpawnChest) - Spawn(component.BountyChestId, Transform(uid).Coordinates); + if (bountyPrototype.SpawnChest) + Spawn(component.BountyCrateId, Transform(uid).Coordinates); else - { Spawn(component.BountyLabelId, Transform(uid).Coordinates); - } + component.NextPrintTime = _timing.CurTime + component.PrintDelay; _audio.PlayPvs(component.PrintSound, uid); } @@ -111,7 +111,11 @@ private void OnSkipPirateBountyMessage(EntityUid uid, PirateBountyConsoleCompone return; FillPirateBountyDatabase(service); - db.NextSkipTime = _timing.CurTime + db.SkipDelay; + if (bounty.Value.Accepted) + db.NextSkipTime = _timing.CurTime + db.SkipDelay; + else + db.NextSkipTime = _timing.CurTime + db.CancelDelay; + var untilNextSkip = db.NextSkipTime - _timing.CurTime; _uiSystem.SetUiState(uid, PirateConsoleUiKey.Bounty, new PirateBountyConsoleState(db.Bounties, untilNextSkip)); _audio.PlayPvs(component.SkipSound, uid); @@ -451,7 +455,7 @@ private bool TryOverwritePirateBountyFromId( if (!Resolve(uid, ref component)) return false; - for (int i=0; i < component.Bounties.Count; i++) + for (int i = 0; i < component.Bounties.Count; i++) { if (bounty.Id == component.Bounties[i].Id) { diff --git a/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs b/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs index 0d33fadaef8..8d985371cc3 100644 --- a/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs +++ b/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs @@ -45,4 +45,10 @@ public sealed partial class SectorPirateBountyDatabaseComponent : Component /// [DataField] public TimeSpan SkipDelay = TimeSpan.FromMinutes(15); + + /// + /// The time between cancelling bounties. + /// + [DataField] + public TimeSpan CancelDelay = TimeSpan.FromMinutes(15); } diff --git a/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl b/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl index c9edfe3c556..566168263ee 100644 --- a/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl +++ b/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl @@ -2,6 +2,7 @@ pirate-bounty-console-menu-title = Pirate bounty console pirate-bounty-console-accept-button-chest = Accept (crate) pirate-bounty-console-accept-button-label = Accept pirate-bounty-console-skip-button-text = Skip +pirate-bounty-console-skip-button-accepted = Cancel pirate-bounty-console-time-label = Time: [color=orange]{$time}[/color] pirate-bounty-console-reward-label = Reward: [color=limegreen]${$reward}[/color] pirate-bounty-console-manifest-label = Manifest: [color=orange]{$item}[/color] From 81bc01e291e6ccf4f9a35823657ad2f53ea43c8d Mon Sep 17 00:00:00 2001 From: Whatstone Date: Fri, 19 Jul 2024 12:22:44 -0400 Subject: [PATCH 49/83] Undupe pirate-pallet strings --- Resources/Locale/en-US/_NF/cargo/pirate-pallet.ftl | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 Resources/Locale/en-US/_NF/cargo/pirate-pallet.ftl diff --git a/Resources/Locale/en-US/_NF/cargo/pirate-pallet.ftl b/Resources/Locale/en-US/_NF/cargo/pirate-pallet.ftl deleted file mode 100644 index 6d42d7f300e..00000000000 --- a/Resources/Locale/en-US/_NF/cargo/pirate-pallet.ftl +++ /dev/null @@ -1,6 +0,0 @@ -# Pirate pallet sale console -pirate-pallet-console-menu-title = Pirate bounty redemption console -pirate-pallet-menu-appraisal-label = Estimated Value:{" "} -pirate-pallet-menu-count-label = Number of sale items:{" "} -pirate-pallet-appraise-button = Appraise -pirate-pallet-sell-button = Sell From 1b41a26deaee70be8081150e18f1aa2b512e8fac Mon Sep 17 00:00:00 2001 From: Whatstone Date: Fri, 19 Jul 2024 12:45:11 -0400 Subject: [PATCH 50/83] 30 minute cancel --- Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs | 2 ++ .../Pirate/Components/SectorPirateBountyDatabaseComponent.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs index e6d7eb4195a..7bc08a2584b 100644 --- a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs +++ b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs @@ -83,6 +83,7 @@ private void OnPirateBountyAccept(EntityUid uid, PirateBountyConsoleComponent co component.NextPrintTime = _timing.CurTime + component.PrintDelay; _audio.PlayPvs(component.PrintSound, uid); + UpdateBountyConsoles(); } private void OnSkipPirateBountyMessage(EntityUid uid, PirateBountyConsoleComponent component, PirateBountySkipMessage args) @@ -121,6 +122,7 @@ private void OnSkipPirateBountyMessage(EntityUid uid, PirateBountyConsoleCompone _audio.PlayPvs(component.SkipSound, uid); } + // TODO: rework this to include loose items off of a pallet /// /// Bounties do not sell for any currency. The reward for a bounty is /// calculated after it is sold separately from the selling system. diff --git a/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs b/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs index 8d985371cc3..0ce25006812 100644 --- a/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs +++ b/Content.Server/_NF/Pirate/Components/SectorPirateBountyDatabaseComponent.cs @@ -50,5 +50,5 @@ public sealed partial class SectorPirateBountyDatabaseComponent : Component /// The time between cancelling bounties. /// [DataField] - public TimeSpan CancelDelay = TimeSpan.FromMinutes(15); + public TimeSpan CancelDelay = TimeSpan.FromMinutes(30); } From 2fe347d299fb6094cfa0ff2ee9dfc6498f34d6f4 Mon Sep 17 00:00:00 2001 From: Whatstone Date: Fri, 19 Jul 2024 22:13:19 -0400 Subject: [PATCH 51/83] pirate bounty chest and reminder descriptions --- .../_NF/Cargo/CargoSystem.PirateBounty.cs | 54 ++++++++++++++++++- .../Prototypes/PirateBountyPrototype.cs | 2 +- .../en-US/_NF/cargo/pirate-bounty-console.ftl | 8 ++- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs index 7bc08a2584b..bdff3dd593c 100644 --- a/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs +++ b/Content.Server/_NF/Cargo/CargoSystem.PirateBounty.cs @@ -1,6 +1,8 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server._NF.Pirate.Components; +using Content.Server.Botany.Components; +using Content.Server.Chat.V2; using Content.Server.Labels; using Content.Server.NameIdentifier; using Content.Server.Paper; @@ -77,9 +79,15 @@ private void OnPirateBountyAccept(EntityUid uid, PirateBountyConsoleComponent co TryOverwritePirateBountyFromId(service, bountyData); if (bountyPrototype.SpawnChest) - Spawn(component.BountyCrateId, Transform(uid).Coordinates); + { + var chest = Spawn(component.BountyCrateId, Transform(uid).Coordinates); + SetupPirateBountyChest(chest, bountyData, bountyPrototype); + } else - Spawn(component.BountyLabelId, Transform(uid).Coordinates); + { + var label = Spawn(component.BountyLabelId, Transform(uid).Coordinates); + SetupPirateBountyManifest(label, bountyData, bountyPrototype); + } component.NextPrintTime = _timing.CurTime + component.PrintDelay; _audio.PlayPvs(component.PrintSound, uid); @@ -122,6 +130,48 @@ private void OnSkipPirateBountyMessage(EntityUid uid, PirateBountyConsoleCompone _audio.PlayPvs(component.SkipSound, uid); } + private void SetupPirateBountyChest(EntityUid uid, PirateBountyData bounty, PirateBountyPrototype prototype) + { + _metaSystem.SetEntityName(chest, Loc.GetString("pirate-bounty-chest-name", ("id", bountyObj.Id))); + + FormattedMessage message = new FormattedMessage(); + message.AddMarkup(Loc.GetString("pirate-bounty-chest-description-start")); + foreach (var entry in prototype.Entries) + { + message.PushNewline(); + message.AddMarkup($"- {Loc.GetString("pirate-bounty-console-manifest-entry", + ("amount", entry.Amount), + ("item", Loc.GetString(entry.Name)))}"); + } + message.PushNewline(); + message.AddMarkup(Loc.GetString("pirate-bounty-console-manifest-reward", ("reward", prototype.Reward))); + + _metaSystem.SetEntityDescription(uid, message.ToMarkup()); + } + + private void SetupPirateBountyManifest(EntityUid uid, PirateBountyData bounty, PirateBountyPrototype prototype, PaperComponent? paper = null) + { + _metaSystem.SetEntityName(label, Loc.GetString("pirate-bounty-manifest-name", ("id", bountyObj.Id))); + + if (!Resolve(uid, ref paper)) + return; + + var msg = new FormattedMessage(); + msg.AddText(Loc.GetString("pirate-bounty-manifest-header", ("id", bounty.Id))); + msg.PushNewline(); + msg.AddText(Loc.GetString("pirate-bounty-manifest-list-start")); + msg.PushNewline(); + foreach (var entry in prototype.Entries) + { + msg.AddMarkup($"- {Loc.GetString("pirate-bounty-console-manifest-entry", + ("amount", entry.Amount), + ("item", Loc.GetString(entry.Name)))}"); + msg.PushNewline(); + } + msg.AddMarkup(Loc.GetString("pirate-bounty-console-manifest-reward", ("reward", prototype.Reward))); + _paperSystem.SetContent(uid, msg.ToMarkup(), paper); + } + // TODO: rework this to include loose items off of a pallet /// /// Bounties do not sell for any currency. The reward for a bounty is diff --git a/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs b/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs index 0add1563364..361bc7fe849 100644 --- a/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs +++ b/Content.Shared/_NF/Pirate/Prototypes/PirateBountyPrototype.cs @@ -44,7 +44,7 @@ public sealed partial class PirateBountyPrototype : IPrototype /// A prefix appended to the beginning of a bounty's ID. /// [DataField] - public string IdPrefix = "YAR-"; + public string IdPrefix = "ARR-"; } [DataDefinition, Serializable, NetSerializable] diff --git a/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl b/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl index 566168263ee..3feab2e1c20 100644 --- a/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl +++ b/Resources/Locale/en-US/_NF/cargo/pirate-bounty-console.ftl @@ -15,8 +15,12 @@ pirate-bounty-console-manifest-reward = Reward: {$reward} DB pirate-bounty-console-description-label = [color=gray]{$description}[/color] pirate-bounty-console-id-label = {$id} - pirate-bounty-console-flavor-left = Go and plunder, me hearties! Down with NT! pirate-bounty-console-flavor-right = v0.0.1a -pirate-bounty-manifest-header = On the chest the following words are etched: +pirate-bounty-chest-name = pirate bounty chest ({$id}) +pirate-bounty-chest-description-start = On the chest the following words are etched: + +pirate-bounty-manifest-name = pirate bounty reminder ({$id}) +pirate-bounty-manifest-header = [font size=14][bold]Pirate bounty request[/bold] ({$id})[/font] +pirate-bounty-manifest-list-start = Items to plunder: From 28f08b917c1bff8895165a7ef532dc95b342e27e Mon Sep 17 00:00:00 2001 From: Whatstone Date: Sat, 20 Jul 2024 10:58:49 -0400 Subject: [PATCH 52/83] Rough pirate contraband console --- ...ntrabandPalletConsoleBoundUserInterface.cs | 11 +++- .../Contraband/UI/ContrabandPalletMenu.xaml | 4 +- .../UI/ContrabandPalletMenu.xaml.cs | 21 ++++++-- .../_NF/Cargo/CargoSystem.PirateBounty.cs | 4 +- .../ContrabandPalletConsoleComponent.cs | 7 ++- .../Contraband/Systems/ContrabandSystem.cs | 2 +- .../Components/ContrabandPalletComponent.cs | 8 +++ .../contraband-exchange-console.ftl | 12 ++++- .../Machines/Computers/computers.yml | 50 ++++--------------- 9 files changed, 67 insertions(+), 52 deletions(-) create mode 100644 Content.Shared/_NF/Contraband/Components/ContrabandPalletComponent.cs diff --git a/Content.Client/_NF/Contraband/BUI/ContrabandPalletConsoleBoundUserInterface.cs b/Content.Client/_NF/Contraband/BUI/ContrabandPalletConsoleBoundUserInterface.cs index e35af8fa1c8..d6faca3ecd8 100644 --- a/Content.Client/_NF/Contraband/BUI/ContrabandPalletConsoleBoundUserInterface.cs +++ b/Content.Client/_NF/Contraband/BUI/ContrabandPalletConsoleBoundUserInterface.cs @@ -1,6 +1,8 @@ using Content.Client._NF.Contraband.UI; using Content.Shared._NF.Contraband.BUI; +using Content.Shared._NF.Contraband.Components; using Content.Shared._NF.Contraband.Events; +using Robust.Shared.GameObjects; using Robust.Shared.Utility; namespace Content.Client._NF.Contraband.BUI; @@ -10,16 +12,21 @@ public sealed class ContrabandPalletConsoleBoundUserInterface : BoundUserInterfa [ViewVariables] private ContrabandPalletMenu? _menu; + [ViewVariables] + private string _locPrefix = string.Empty; + public ContrabandPalletConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { + if (EntMan.TryGetComponent(owner, out var console)) + _locPrefix = console.LocStringPrefix ?? string.Empty; } protected override void Open() { base.Open(); var disclaimer = new FormattedMessage(); - disclaimer.AddText(Loc.GetString($"contraband-pallet-disclaimer")); - _menu = new ContrabandPalletMenu(); + disclaimer.AddText(Loc.GetString($"{_locPrefix}contraband-pallet-disclaimer")); + _menu = new ContrabandPalletMenu(_locPrefix); _menu.AppraiseRequested += OnAppraisal; _menu.SellRequested += OnSell; _menu.OnClose += Close; diff --git a/Content.Client/_NF/Contraband/UI/ContrabandPalletMenu.xaml b/Content.Client/_NF/Contraband/UI/ContrabandPalletMenu.xaml index 48832584656..09c3d52f03d 100644 --- a/Content.Client/_NF/Contraband/UI/ContrabandPalletMenu.xaml +++ b/Content.Client/_NF/Contraband/UI/ContrabandPalletMenu.xaml @@ -5,13 +5,13 @@ MinSize="300 196"> - -