diff --git a/Content.Shared/Construction/Components/BlockAnchorOnComponent.cs b/Content.Shared/Construction/Components/BlockAnchorOnComponent.cs new file mode 100644 index 0000000000..0ade0dba62 --- /dev/null +++ b/Content.Shared/Construction/Components/BlockAnchorOnComponent.cs @@ -0,0 +1,24 @@ +using Content.Shared.Construction.EntitySystems; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared.Construction.Components; + +/// +/// Will not allow anchoring if there is an anchored item in the same tile that fails the . +/// +[RegisterComponent, NetworkedComponent, Access(typeof(BlockAnchorOnSystem))] +public sealed partial class BlockAnchorOnComponent : Component +{ + /// + /// If not null, entities that match this whitelist are allowed. + /// + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// If not null, entities that match this blacklist are not allowed. + /// + [DataField] + public EntityWhitelist? Blacklist; +} diff --git a/Content.Shared/Construction/EntitySystems/BlockAnchorOnSystem.cs b/Content.Shared/Construction/EntitySystems/BlockAnchorOnSystem.cs new file mode 100644 index 0000000000..46550fb0fc --- /dev/null +++ b/Content.Shared/Construction/EntitySystems/BlockAnchorOnSystem.cs @@ -0,0 +1,82 @@ +using Content.Shared.Construction.Components; +using Content.Shared.Popups; +using Content.Shared.Whitelist; +using Robust.Shared.Map.Components; + +namespace Content.Shared.Construction.EntitySystems; + +/// +/// Prevents anchoring an item in the same tile as an item matching the . +/// +/// +public sealed class BlockAnchorOnSystem : EntitySystem +{ + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedTransformSystem _xform = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAnchorStateChanged); + SubscribeLocalEvent(OnAnchorAttempt); + } + + /// + /// Handles the . + /// + private void OnAnchorStateChanged(Entity ent, ref AnchorStateChangedEvent args) + { + if (!args.Anchored) + return; + + if (!HasOverlap((ent, ent.Comp, Transform(ent)))) + return; + + _popup.PopupPredicted(Loc.GetString("anchored-already-present"), ent, null); + _xform.Unanchor(ent, Transform(ent)); + } + + /// + /// Handles the . + /// + private void OnAnchorAttempt(Entity ent, ref AnchorAttemptEvent args) + { + if (args.Cancelled) + return; + + if (!HasOverlap((ent, ent.Comp, Transform(ent)))) + return; + + _popup.PopupPredicted(Loc.GetString("anchored-already-present"), ent, args.User); + args.Cancel(); + } + + /// + /// Check if there is any anchored overlap with non whitelisted or blacklisted entities. + /// + /// True if there is, false if there isn't + private bool HasOverlap(Entity ent) + { + if (ent.Comp2.GridUid is not { } grid || !TryComp(grid, out var gridComp)) + return false; + + var indices = _map.TileIndicesFor(grid, gridComp, ent.Comp2.Coordinates); + var enumerator = _map.GetAnchoredEntitiesEnumerator(grid, gridComp, indices); + + while (enumerator.MoveNext(out var otherEnt)) + { + // Don't match yourself. + if (otherEnt == ent) + continue; + + if (!_whitelist.CheckBoth(otherEnt, ent.Comp1.Blacklist, ent.Comp1.Whitelist)) + return true; + } + + return false; + } +} diff --git a/Content.Shared/Storage/Components/AnchoredStorageFilterComponent.cs b/Content.Shared/Storage/Components/AnchoredStorageFilterComponent.cs new file mode 100644 index 0000000000..c3cde90cab --- /dev/null +++ b/Content.Shared/Storage/Components/AnchoredStorageFilterComponent.cs @@ -0,0 +1,28 @@ +using Content.Shared.Storage.EntitySystems; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared.Storage.Components; + +/// +/// Entities with this component will eject all items that match the whitelist / blacklist when anchored. +/// It also doesn't allow any items to be inserted that fit the whitelist / blacklist while anchored. +/// +/// +/// If you have a smuggler stash that has a player inside of it, you want to eject the player before its anchored so they don't get stuck +/// +[RegisterComponent, NetworkedComponent, Access(typeof(AnchoredStorageFilterSystem))] +public sealed partial class AnchoredStorageFilterComponent : Component +{ + /// + /// If not null, entities that do not match this whitelist will be ejected. + /// + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// If not null, entities that match this blacklist will be ejected.. + /// + [DataField] + public EntityWhitelist? Blacklist; +} diff --git a/Content.Shared/Storage/EntitySystems/AnchoredStorageFilterSystem.cs b/Content.Shared/Storage/EntitySystems/AnchoredStorageFilterSystem.cs new file mode 100644 index 0000000000..ea98fc2852 --- /dev/null +++ b/Content.Shared/Storage/EntitySystems/AnchoredStorageFilterSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared.Storage.Components; +using Content.Shared.Whitelist; +using Robust.Shared.Containers; + +namespace Content.Shared.Storage.EntitySystems; + +/// +/// Ejects items that do not match a from a storage when it is anchored. +/// +/// +public sealed class AnchoredStorageFilterSystem : EntitySystem +{ + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAnchorStateChanged); + SubscribeLocalEvent(OnInsertAttempt); + } + + /// + /// Handles the . + /// + private void OnAnchorStateChanged(Entity ent, ref AnchorStateChangedEvent args) + { + if (!args.Anchored) + return; + + if (!TryComp(ent, out var storage)) + return; + + foreach (var item in storage.StoredItems.Keys) + { + if (!_whitelist.CheckBoth(item, ent.Comp.Blacklist, ent.Comp.Whitelist)) + _container.RemoveEntity(ent, item); + } + } + + /// + /// Handles the . + /// + private void OnInsertAttempt(Entity ent, ref ContainerIsInsertingAttemptEvent args) + { + if (args.Cancelled) + return; + + if (Transform(ent).Anchored && !_whitelist.CheckBoth(args.EntityUid, ent.Comp.Blacklist, ent.Comp.Whitelist)) + args.Cancel(); + } +} diff --git a/Resources/Locale/en-US/construction/components/block-anchor-component.ftl b/Resources/Locale/en-US/construction/components/block-anchor-component.ftl new file mode 100644 index 0000000000..cc6fcc95ea --- /dev/null +++ b/Resources/Locale/en-US/construction/components/block-anchor-component.ftl @@ -0,0 +1 @@ +anchored-already-present = There's already something anchored here! diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 4d618d45dc..7d93dab869 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -463,3 +463,6 @@ uplink-business-card-desc = A business card that you can give to someone to demo uplink-fake-mindshield-name = Fake Mindshield uplink-fake-mindshield-desc = A togglable implant capable of mimicking the same transmissions a real mindshield puts out when on, tricking capable Heads-up displays into thinking you have a mindshield (Nanotrasen brand implanter not provided.) + +uplink-smuggler-satchel-name = Smuggler's Satchel +uplink-smuggler-satchel-desc = A handy, suspicious looking satchel. Just flat enough to fit underneath floor tiles. diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml index 7b000e30ad..4b5688a46f 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml @@ -98,4 +98,5 @@ ClothingUniformJumpskirtTacticool: 1 ToyFigurinePassenger: 1 ToyFigurineGreytider: 1 + ClothingBackpackSatchelSmugglerUnanchored: 1 # DO NOT ADD MORE, USE UNIFORM DYING diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 086c29304c..f4f1d754c4 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -2148,3 +2148,16 @@ whitelist: - Chef - Mime + +- type: listing + id: UplinkSmugglerSatchel + name: uplink-smuggler-satchel-name + description: uplink-smuggler-satchel-desc + productEntity: ClothingBackpackSatchelSmugglerUnanchored + discountCategory: usualDiscounts + discountDownTo: + Telecrystal: 1 + cost: + Telecrystal: 2 + categories: + - UplinkDeception diff --git a/Resources/Prototypes/Entities/Clothing/Back/smuggler.yml b/Resources/Prototypes/Entities/Clothing/Back/smuggler.yml new file mode 100644 index 0000000000..c9d7f61890 --- /dev/null +++ b/Resources/Prototypes/Entities/Clothing/Back/smuggler.yml @@ -0,0 +1,120 @@ +- type: entity + abstract: true + id: BaseSubfloorAnchorStorage + components: + - type: Appearance + - type: SubFloorHide + - type: Anchorable + - type: CollideOnAnchor + - type: Transform + anchored: false + - type: AnchoredStorageFilter + blacklist: + components: + - HumanoidAppearance # for forks with felines + - type: BlockAnchorOn + blacklist: + components: + - AnchoredStorageFilter + - type: Visibility + layer: 1 + +- type: entity + abstract: true + parent: BaseSubfloorAnchorStorage + id: BaseSubfloorAnchorStorageAnchored + placement: + mode: SnapgridCenter + components: + - type: Transform + anchored: true + - type: Physics + canCollide: false + bodyType: Static + +- type: entity + parent: [ BaseSubfloorAnchorStorageAnchored, ClothingBackpackSatchel, BaseMinorContraband ] + id: ClothingBackpackSatchelSmuggler + name: smuggler's satchel + suffix: Empty + description: A dingy, suspicious looking satchel. + components: + - type: Sprite + sprite: Clothing/Back/Satchels/smuggler.rsi + state: icon + +- type: entity + parent: [ BaseSubfloorAnchorStorage, ClothingBackpackSatchel, BaseMinorContraband ] + id: ClothingBackpackSatchelSmugglerUnanchored + name: smuggler's satchel + suffix: Empty, Unanchored + description: A dingy, suspicious looking satchel. + components: + - type: Sprite + sprite: Clothing/Back/Satchels/smuggler.rsi + state: icon + +- type: entity + parent: [ BaseSubfloorAnchorStorageAnchored, BriefcaseSyndie, BaseMinorContraband ] + id: BriefcaseSmugglerCash + name: smuggler's briefcase + suffix: Smuggler, Do Not Map + components: + - type: EntityTableContainerFill + containers: + storagebase: !type:AllSelector + children: + - id: SpaceCash5000 + amount: !type:RangeNumberSelector + range: 1, 11 + +- type: entity + parent: [ BaseSubfloorAnchorStorageAnchored, ClothingBackpackDuffelClown, BaseMinorContraband ] + id: ClothingBackpackDuffelClownSmuggler + name: smuggler's clown duffel bag + suffix: Smuggler, Do Not Map + components: + - type: EntityTableContainerFill + containers: + storagebase: !type:AllSelector + children: + - id: SpeedLoaderCap + amount: !type:RangeNumberSelector + range: 4, 8 + - !type:GroupSelector + children: + - id: RevolverCapGun + amount: !type:RangeNumberSelector + range: 4, 8 + weight: 95 + - id: RevolverCapGunFake + amount: !type:RangeNumberSelector + range: 1, 8 + weight: 5 + +- type: entity + parent: ClothingBackpackSatchelSmuggler + id: ClothingBackpackSatchelSmugglerFilled + suffix: Smuggler, Do Not Map + components: + - type: Sprite + sprite: Clothing/Back/Satchels/smuggler.rsi + state: icon + - type: EntityTableContainerFill + containers: + storagebase: !type:NestedSelector + tableId: FillSmugglerBackpack + +- type: entity + parent: MarkerBase + id: RandomSatchelSpawner + name: random smuggler's satchel spawner + suffix: Do Not Map + components: + - type: Sprite + layers: + - sprite: Clothing/Back/Satchels/smuggler.rsi + state: icon + - type: EntityTableSpawner + table: !type:NestedSelector + tableId: RandomSatchelTable diff --git a/Resources/Prototypes/Entities/Clothing/Back/smuggler_tables.yml b/Resources/Prototypes/Entities/Clothing/Back/smuggler_tables.yml new file mode 100644 index 0000000000..b89f451cbb --- /dev/null +++ b/Resources/Prototypes/Entities/Clothing/Back/smuggler_tables.yml @@ -0,0 +1,673 @@ +#Table +- type: entityTable + id: RandomSatchelTable + table: !type:GroupSelector + children: + - id: ClothingBackpackSatchelSmugglerFilled + weight: 85 + - id: BriefcaseSmugglerCash + weight: 10 + - id: ClothingBackpackDuffelClownSmuggler + weight: 5 + +#Table +- type: entityTable + id: FillSmugglerBackpack + table: !type:GroupSelector + children: + - !type:NestedSelector + tableId: RandomSatchelTable1 + - !type:NestedSelector + tableId: RandomSatchelTable2 + - !type:NestedSelector + tableId: RandomSatchelTable3 + - !type:NestedSelector + tableId: RandomSatchelTable4 + - !type:NestedSelector + tableId: RandomSatchelTable5 + - !type:NestedSelector + tableId: RandomSatchelTable6 + +- type: entityTable + id: RandomSatchelTable1 + table: !type:AllSelector + children: + - !type:NestedSelector + tableId: RandomSatchelGenericTable + - !type:NestedSelector + tableId: RandomSatchelFunnyTable + - !type:NestedSelector + tableId: RandomSatchelClothingTable + - !type:NestedSelector + tableId: RandomSatchelCannabisTable + - !type:NestedSelector + tableId: RandomSatchelGizmosTable + - !type:NestedSelector + tableId: RandomSatchelChemsTable + +- type: entityTable + id: RandomSatchelFunnyTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 20 + - id: WhoopieCushion + - id: RubberChicken + - id: PlasticBanana + amount: !type:RangeNumberSelector + range: 1, 5 + - id: PillSpaceDrugs + amount: !type:RangeNumberSelector + range: 1, 2 + - id: StrangePill + amount: !type:RangeNumberSelector + range: 1, 5 + +- type: entityTable + id: RandomSatchelCannabisTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 4 + - id: Joint + amount: !type:RangeNumberSelector + range: 1, 5 + - id: Blunt + amount: !type:RangeNumberSelector + range: 1, 5 + - id: SmokingPipeFilledCannabis + amount: !type:RangeNumberSelector + range: 1, 5 + - id: GroundCannabis + amount: !type:RangeNumberSelector + range: 1, 15 + +- type: entityTable + id: RandomSatchelGizmosTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 40 + - id: TimerTrigger + amount: !type:RangeNumberSelector + range: 1, 2 + - id: SignalTrigger + amount: !type:RangeNumberSelector + range: 1, 2 + - id: VoiceTrigger + amount: !type:RangeNumberSelector + range: 1, 2 + - id: ProximitySensor + +- type: entityTable + id: RandomSatchelChemsTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 20 + - id: ChemistryBottleUnstableMutagen + amount: !type:RangeNumberSelector + range: 1, 5 + - id: ChemistryBottleLeft4Zed + amount: !type:RangeNumberSelector + range: 1, 5 + - id: ChemistryBottleEZNutrient + amount: !type:RangeNumberSelector + range: 1, 5 + - id: ChemistryBottleRobustHarvest + amount: !type:RangeNumberSelector + range: 1, 5 + - id: ChemistryBottleEpinephrine + amount: !type:RangeNumberSelector + range: 1, 5 + - id: ChemistryBottleEphedrine + amount: !type:RangeNumberSelector + range: 1, 5 + - id: ChemistryBottleOmnizine + - id: ChemistryBottleCognizine + - id: ChemistryBottleToxin + - id: ChemistryBottleNocturine + - id: VestineChemistryVial + +- type: entityTable + id: RandomSatchelTable2 + table: !type:AllSelector + children: + - !type:NestedSelector + tableId: RandomSatchelTobaccoTable + - !type:NestedSelector + tableId: RandomSatchelPartyTable + - !type:NestedSelector + tableId: RandomSatchelClothingTable + - !type:NestedSelector + tableId: RandomSatchelPayloadTable + - !type:NestedSelector + tableId: RandomSatchelCircuitboardsTable + +- type: entityTable + id: RandomSatchelTobaccoTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 8 + - id: CigPackSyndicate + weight: 0.5 + - id: CigCartonGreen + - id: CigCartonRed + - id: CigCartonGreen + - id: CigCartonBlack + - id: CigarCase + amount: !type:RangeNumberSelector + range: 1, 2 + - id: CigarGoldCase + weight: 0.25 + amount: !type:RangeNumberSelector + range: 1, 2 + +- type: entityTable + id: RandomSatchelPartyTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 2 + - id: GlowstickBase + amount: !type:RangeNumberSelector + range: 1, 5 + - id: GlowstickRed + amount: !type:RangeNumberSelector + range: 1, 5 + - id: GlowstickPurple + amount: !type:RangeNumberSelector + range: 1, 5 + - id: GlowstickYellow + amount: !type:RangeNumberSelector + range: 1, 5 + - id: GlowstickBlue + amount: !type:RangeNumberSelector + range: 1, 5 + +- type: entityTable + id: RandomSatchelClothingTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 3 + - id: ClothingEyesGlassesOutlawGlasses + - id: ClothingEyesEyepatch + - id: ClothingHandsGlovesNitrile + - id: ClothingHeadHatOutlawHat + - id: ClothingMaskItalianMoustache + - id: ClothingHandsGlovesCombat + - id: ClothingNeckScarfStripedSyndieRed + +- type: entityTable + id: RandomSatchelPayloadTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 45 + - id: FlashPayload + amount: !type:RangeNumberSelector + range: 1, 2 + - id: ChemicalPayload + amount: !type:RangeNumberSelector + range: 1, 2 + - id: ExplosivePayload + amount: !type:RangeNumberSelector + range: 1, 2 + +- type: entityTable + id: RandomSatchelCircuitboardsTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 15 + - id: ChemDispenserMachineCircuitboard + - id: SyndicateMicrowaveMachineCircuitboard + - id: HydroponicsTrayMachineCircuitboard + - id: DawInstrumentMachineCircuitboard + - id: PortableGeneratorPacmanMachineCircuitboard + - id: PortableGeneratorSuperPacmanMachineCircuitboard + - id: HellfireFreezerMachineCircuitBoard + - id: HellfireHeaterMachineCircuitBoard + - id: ReagentGrinderMachineCircuitboard + - id: ReagentGrinderIndustrialMachineCircuitboard + - id: BoozeDispenserMachineCircuitboard + - id: MiniGravityGeneratorCircuitboard + - id: AmmoTechFabCircuitboard + - id: CryoPodMachineCircuitboard + - id: PowerCageRechargerCircuitboard + - id: ShuttleConsoleCircuitboard + - id: TurboItemRechargerCircuitboard + +- type: entityTable + id: RandomSatchelTable3 + table: !type:AllSelector + children: + - !type:NestedSelector + tableId: RandomSatchelPresentsOrToysTable + - !type:NestedSelector + tableId: RandomSatchelCashTable + - !type:NestedSelector + tableId: RandomSatchelWeaponTable + - !type:NestedSelector + tableId: RandomSatchelBurgerTable + - !type:NestedSelector + tableId: RandomSatchelGenericTable + - !type:NestedSelector + tableId: RandomSatchelKeysTable + +- type: entityTable + id: RandomSatchelPresentsOrToysTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 5 + - id: PresentRandom + amount: !type:RangeNumberSelector + range: 1, 3 + - id: ToyFigurineHamlet + - id: ToyFigurineSpaceDragon + - id: ToyFigurineQueen + - id: ToyFigurineRatKing + - id: PresentRandomUnsafe + weight: 0.001 + +- type: entityTable + id: RandomSatchelCashTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 2 + amount: !type:RangeNumberSelector + range: 1, 4 + - id: SpaceCash1000 + weight: 2 + amount: !type:RangeNumberSelector + range: 1, 4 + - id: SpaceCash2500 + amount: !type:RangeNumberSelector + range: 1, 4 + - id: SpaceCash5000 + weight: 0.25 + amount: !type:RangeNumberSelector + range: 1, 4 + - id: SpaceCash10000 + weight: 0.005 + amount: !type:RangeNumberSelector + range: 1, 4 + - id: SpaceCash1000000 + prob: 0.0001 + - id: SpaceCash + weight: 0.01 + amount: !type:RangeNumberSelector + range: 1, 10 + +- type: entityTable + id: RandomSatchelWeaponTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 100 + - id: Katana + - id: ThrowingStar + amount: !type:RangeNumberSelector + range: 1, 5 + +- type: entityTable + id: RandomSatchelBurgerTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 10 + - id: FoodBurgerAppendix + amount: !type:RangeNumberSelector + range: 1, 5 + - id: FoodBurgerEmpowered + amount: !type:RangeNumberSelector + range: 1, 5 + - id: FoodBurgerClown + amount: !type:RangeNumberSelector + range: 1, 5 + - id: FoodBurgerGhost + amount: !type:RangeNumberSelector + range: 1, 5 + +- type: entityTable + id: RandomSatchelGenericTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 15 + - id: RemoteSignaller + - id: PersonalAI + - id: WeaponFlareGun + - id: ModularReceiver + - id: RifleStock + - id: DrinkSpaceGlue + amount: !type:RangeNumberSelector + range: 1, 2 + - id: DrinkSpaceLube + amount: !type:RangeNumberSelector + range: 1, 2 + - id: CrazyGlue + amount: !type:RangeNumberSelector + range: 1, 2 + +- type: entityTable + id: RandomSatchelKeysTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 50 + - id: EncryptionKeyCommon + - id: EncryptionKeyCargo + - id: EncryptionKeyService + - id: EncryptionKeyRobo + - id: EncryptionKeyScience + - id: EncryptionKeyMedical + - id: EncryptionKeyEngineering + - id: EncryptionKeySecurity + weight: 0.5 + - id: EncryptionKeyCommand + weight: 0.25 + - id: EncryptionKeyStationMaster + weight: 0.01 + +- type: entityTable + id: RandomSatchelTable4 + table: !type:AllSelector + children: + - !type:NestedSelector + tableId: RandomSatchelMaterialsTable + - !type:NestedSelector + tableId: RandomSatchelImplantersTable + - !type:NestedSelector + tableId: RandomSatchelCellsTable + - !type:NestedSelector + tableId: RandomSatchelSyndicateTable + - !type:NestedSelector + tableId: RandomSatchelToolsTable + +- type: entityTable + id: RandomSatchelMaterialsTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 6 + - !type:GroupSelector + children: + - id: MaterialDiamond1 + - !type:GroupSelector + children: + - id: MaterialBananium1 + weight: 2 + - id: MaterialBananium + - !type:GroupSelector + children: + - id: IngotGold1 + weight: 2 + - id: IngotGold + - !type:GroupSelector + children: + - id: IngotSilver1 + weight: 2 + - id: IngotSilver + - !type:GroupSelector + children: + - id: SheetPlasma1 + weight: 2 + - id: SheetPlasma10 + - id: SheetPlasma + weight: 0.50 + - !type:GroupSelector + children: + - id: SheetUranium1 + weight: 2 + - id: SheetUranium + +- type: entityTable + id: RandomSatchelImplantersTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 3 + - id: LightImplanter + - id: BikeHornImplanter + - id: SadTromboneImplanter + +- type: entityTable + id: RandomSatchelCellsTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 15 + - id: PowerCellHyper + - id: PowerCellMicroreactor + - id: PowerCellHigh + +- type: entityTable + id: RandomSatchelSyndicateTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 50 + - id: Telecrystal1 + amount: !type:RangeNumberSelector + range: 1, 3 + - id: GatfruitSeeds + - id: ToySword + - id: NukeDiskFake + - id: RadioJammer + - id: SoapSyndie + - id: SingularityToy + +- type: entityTable + id: RandomSatchelToolsTable + table: !type:GroupSelector + children: + - id: Crowbar + - id: Multitool + - id: ClothingHandsGlovesColorYellow + - id: Screwdriver + - id: ClothingHeadHatWeldingMaskFlame + - id: WelderExperimental + weight: 0.50 + +- type: entityTable + id: RandomSatchelTable5 + table: !type:AllSelector + children: + - !type:NestedSelector + tableId: RandomSatchelAlcoholTable + - !type:NestedSelector + tableId: RandomSatchelInstrumentTable + - !type:NestedSelector + tableId: RandomSatchelMedsTable + - !type:NestedSelector + tableId: RandomSatchelMysteriesTable + +- type: entityTable + id: RandomSatchelAlcoholTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 5 + - id: DrinkCognacBottleFull + amount: !type:RangeNumberSelector + range: 1, 4 + - id: DrinkGildlagerBottleFull + amount: !type:RangeNumberSelector + range: 1, 4 + - id: DrinkPatronBottleFull + amount: !type:RangeNumberSelector + range: 1, 4 + - id: DrinkRumBottleFull + amount: !type:RangeNumberSelector + range: 1, 4 + +- type: entityTable + id: RandomSatchelInstrumentTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 15 + - id: SeashellInstrument + - id: MusicalLungInstrument + - id: HelicopterInstrument + - id: GunpetInstrument + - id: RockGuitarInstrument + - id: BassGuitarInstrument + +- type: entityTable + id: RandomSatchelMedsTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 10 + - id: SyringeAmbuzol + - id: SyringeHyronalin + - id: SyringeDermaline + - id: SyringeBicaridine + - id: SyringeTranexamicAcid + - id: SyringeInaprovaline + - id: SyringeEphedrine + - id: Gauze + - id: Bloodpack + - id: RegenerativeMesh + - id: MedicatedSuture + - id: EmergencyMedipen + amount: !type:RangeNumberSelector + range: 1, 5 + - id: AntiPoisonMedipen + amount: !type:RangeNumberSelector + range: 1, 5 + - id: BruteAutoInjector + amount: !type:RangeNumberSelector + range: 1, 5 + - id: BurnAutoInjector + amount: !type:RangeNumberSelector + range: 1, 5 + - id: SpaceMedipen + amount: !type:RangeNumberSelector + range: 1, 5 + - id: Stimpack + - id: CombatMedipen + +- type: entityTable + id: RandomSatchelMysteriesTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 15 + - id: EggSpider + weight: 5 + - id: ArtifactFragment1 + amount: !type:RangeNumberSelector + range: 1, 2 + weight: 10 + - id: AnomalyCorePyroclastic + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreGravity + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreIce + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreFlesh + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreLiquid + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreBluespace + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreElectricity + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreFlora + amount: !type:RangeNumberSelector + range: 1, 3 + - id: AnomalyCoreShadow + amount: !type:RangeNumberSelector + range: 1, 3 + +- type: entityTable + id: RandomSatchelTable6 + table: !type:AllSelector + children: + - !type:NestedSelector + tableId: RandomSatchelGearTable + - !type:NestedSelector + tableId: RandomSatchelGadgetsTable + - !type:NestedSelector + tableId: CubeTable + +- type: entityTable + id: RandomSatchelGearTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 8 + - id: JetpackMiniFilled + - id: HandheldGPSBasic + - id: WelderIndustrialAdvanced + - id: HandheldStationMap + - id: PinpointerStation + +- type: entityTable + id: RandomSatchelGadgetsTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 30 + - id: HolofanProjector + - id: HoloprojectorField + - id: HoloprojectorSecurity + - id: DeviceQuantumSpinInverter + amount: !type:ConstantNumberSelector + value: 2 + - id: SpectralLocator + - id: ArabianLamp + weight: 0.50 + - id: ChameleonProjector + weight: 0.25 + +- type: entityTable + id: CubeTable + table: !type:GroupSelector + children: + - id: SpaceCash100 + weight: 8 + - id: MonkeyCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: KoboldCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: CowCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: GoatCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: MothroachCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: MouseCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: CockroachCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: SpaceCarpCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: SpaceTickCube + amount: !type:RangeNumberSelector + range: 1, 10 + - id: AbominationCube + amount: !type:RangeNumberSelector + range: 1, 10 diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index f942cafe6c..41655a4871 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -640,6 +640,19 @@ blacklist: - External # don't space everything +- type: entity + parent: BaseGameRule + id: SmugglerStashVariationPass + components: + - type: StationEvent + earliestStart: 0 + duration: 1 + minimumPlayers: 1 + maxOccurrences: 2 + weight: 10 + - type: RandomSpawnRule + prototype: RandomSatchelSpawner + - type: entity parent: BaseGameRule id: DerelictCyborgSpawn diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index a6c552e2e4..87f8981d8d 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -443,3 +443,5 @@ - id: BloodbathPuddleMessVariationPass prob: 0.01 orGroup: puddleMess + - id: SmugglerStashVariationPass + prob: 0.90 diff --git a/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/equipped-BACKPACK.png b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..c24f815bc1 Binary files /dev/null and b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/icon.png b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/icon.png new file mode 100644 index 0000000000..a32ce14950 Binary files /dev/null and b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/inhand-left.png b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/inhand-left.png new file mode 100644 index 0000000000..2f5f5f35cd Binary files /dev/null and b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/inhand-right.png b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/inhand-right.png new file mode 100644 index 0000000000..7952889f7d Binary files /dev/null and b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/meta.json b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/meta.json new file mode 100644 index 0000000000..d3b44ffaa2 --- /dev/null +++ b/Resources/Textures/Clothing/Back/Satchels/smuggler.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/a8056c6ba7f5367934ef829116e57d743226e1f0", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +}