diff --git a/Content.Server/Gatherable/GatherableSystem.cs b/Content.Server/Gatherable/GatherableSystem.cs index 0c3ba4b09b..ee518fba46 100644 --- a/Content.Server/Gatherable/GatherableSystem.cs +++ b/Content.Server/Gatherable/GatherableSystem.cs @@ -1,12 +1,10 @@ -using System.Threading; +using System.Threading; using Content.Server.DoAfter; using Content.Server.Gatherable.Components; using Content.Shared.Damage; using Content.Shared.EntityList; using Content.Shared.Interaction; using Content.Shared.Tag; -using Robust.Shared.Audio; -using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -14,10 +12,11 @@ namespace Content.Server.Gatherable; public sealed class GatherableSystem : EntitySystem { + [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly IRobustRandom _random = null!; - [Dependency] private readonly TagSystem _tagSystem = Get(); + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override void Initialize() @@ -64,11 +63,12 @@ public sealed class GatherableSystem : EntitySystem // Complete the gathering process _damageableSystem.TryChangeDamage(ev.Resource, tool.Damage, origin: ev.Player); - SoundSystem.Play(tool.GatheringSound.GetSound(), Filter.Pvs(ev.Resource, entityManager: EntityManager), ev.Resource); + _audio.PlayPvs(tool.GatheringSound, ev.Resource); tool.GatheringEntities.Remove(ev.Resource); // Spawn the loot! - if (component.MappedLoot == null) return; + if (component.MappedLoot == null) + return; var playerPos = Transform(ev.Player).MapPosition; @@ -76,7 +76,8 @@ public sealed class GatherableSystem : EntitySystem { if (tag != "All") { - if (!_tagSystem.HasTag(tool.Owner, tag)) continue; + if (!_tagSystem.HasTag(tool.Owner, tag)) + continue; } var getLoot = _prototypeManager.Index(table); var spawnLoot = getLoot.GetSpawns(); diff --git a/Content.Server/Mining/Components/OreVeinComponent.cs b/Content.Server/Mining/Components/OreVeinComponent.cs new file mode 100644 index 0000000000..8acf18f20c --- /dev/null +++ b/Content.Server/Mining/Components/OreVeinComponent.cs @@ -0,0 +1,32 @@ +using Content.Shared.Mining; +using Content.Shared.Random; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Mining.Components; + +/// +/// Defines an entity that will drop a random ore after being destroyed. +/// +[RegisterComponent] +public sealed class OreVeinComponent : Component +{ + /// + /// How often an entity will be seeded with ore. Note: the amount of ore + /// that is dropped is dependent on the ore prototype. + /// + [DataField("oreChance")] + public float OreChance = 0.1f; + + /// + /// The weighted random prototype used for determining what ore will be dropped. + /// + [DataField("oreRarityPrototypeId", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? OreRarityPrototypeId; + + /// + /// The ore that this entity holds. + /// If set in the prototype, it will not be overriden. + /// + [DataField("currentOre", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string? CurrentOre; +} diff --git a/Content.Server/Mining/MiningSystem.cs b/Content.Server/Mining/MiningSystem.cs new file mode 100644 index 0000000000..5cc953ee94 --- /dev/null +++ b/Content.Server/Mining/MiningSystem.cs @@ -0,0 +1,52 @@ +using Content.Server.Mining.Components; +using Content.Shared.Destructible; +using Content.Shared.Mining; +using Content.Shared.Random; +using Content.Shared.Random.Helpers; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Mining; + +/// +/// This handles creating ores when the entity is destroyed. +/// +public sealed class MiningSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + /// + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnDestruction); + } + + private void OnDestruction(EntityUid uid, OreVeinComponent component, DestructionEventArgs args) + { + if (component.CurrentOre == null) + return; + + var proto = _proto.Index(component.CurrentOre); + + if (proto.OreEntity == null) + return; + + var coords = Transform(uid).Coordinates; + var toSpawn = _random.Next(proto.MinOreYield, proto.MaxOreYield); + for (var i = 0; i < toSpawn; i++) + { + Spawn(proto.OreEntity, coords.Offset(_random.NextVector2(0.3f))); + } + } + + private void OnMapInit(EntityUid uid, OreVeinComponent component, MapInitEvent args) + { + if (component.CurrentOre != null || component.OreRarityPrototypeId == null || !_random.Prob(component.OreChance)) + return; + + component.CurrentOre = _proto.Index(component.OreRarityPrototypeId).Pick(_random); + } +} diff --git a/Content.Shared/Mining/OrePrototype.cs b/Content.Shared/Mining/OrePrototype.cs new file mode 100644 index 0000000000..f2dbe2cc68 --- /dev/null +++ b/Content.Shared/Mining/OrePrototype.cs @@ -0,0 +1,27 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Mining; + +/// +/// This is a prototype for defining ores that generate in rock +/// +[Prototype("ore")] +[DataDefinition] +public sealed class OrePrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; } = default!; + + [DataField("oreEntity", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? OreEntity; + + [DataField("minOreYield")] + public int MinOreYield = 1; + + [DataField("maxOreYield")] + public int MaxOreYield = 1; + + //TODO: add sprites for ores for things like mining analyzer +} diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml index 25d5318c2d..7becc1cf57 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml @@ -13,7 +13,7 @@ - type: GatheringTool damage: types: - Piercing: 25 + Structural: 50 - type: ItemCooldown - type: MeleeWeapon damage: @@ -39,7 +39,7 @@ - type: GatheringTool damage: types: - Piercing: 35 + Structural: 75 gatheringTime: 0.50 MaxGatheringEntities: 2 - type: ItemCooldown diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index 487c2bec64..e535d20c79 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -9,8 +9,6 @@ whitelist: tags: - Pickaxe - loot: - Pickaxe: MiningLootTableLowYield - type: Sprite sprite: Structures/Walls/asteroid_rock.rsi state: full @@ -42,6 +40,9 @@ - type: IconSmooth key: walls base: rock_ + - type: OreVein + oreChance: 0.2 + oreRarityPrototypeId: RandomOreDistributionStandard - type: entity id: AsteroidRockMining @@ -54,5 +55,6 @@ whitelist: tags: - Pickaxe - loot: - Pickaxe: MiningLootTable + - type: OreVein + oreChance: 0.33 + oreRarityPrototypeId: RandomOreDistributionStandard diff --git a/Resources/Prototypes/LootTables/mining_loot_table.yml b/Resources/Prototypes/LootTables/mining_loot_table.yml deleted file mode 100644 index c1122a03ac..0000000000 --- a/Resources/Prototypes/LootTables/mining_loot_table.yml +++ /dev/null @@ -1,47 +0,0 @@ -- type: entityLootTable - id: MiningLootTable - entries: - - prob: 0.5 #null value, doesn't drop anything - orGroup: Asteroid - - id: SteelOre1 - prob: 0.125 - orGroup: Asteroid - - id: GoldOre1 - prob: 0.025 - orGroup: Asteroid - - id: SpaceQuartz1 - prob: 0.10 - orGroup: Asteroid - - id: PlasmaOre1 - prob: 0.05 - orGroup: Asteroid - - id: SilverOre1 - prob: 0.0125 - orGroup: Asteroid - - id: UraniumOre1 - prob: 0.0125 - orGroup: Asteroid - -- type: entityLootTable - id: MiningLootTableLowYield - entries: - - prob: 0.75 #null value, doesn't drop anything - orGroup: Asteroid - - id: SteelOre1 - prob: 0.0125 - orGroup: Asteroid - - id: GoldOre1 - prob: 0.0025 - orGroup: Asteroid - - id: SpaceQuartz1 - prob: 0.0125 - orGroup: Asteroid - - id: PlasmaOre1 - prob: 0.00625 - orGroup: Asteroid - - id: SilverOre1 - prob: 0.005 - orGroup: Asteroid - - id: UraniumOre1 - prob: 0.005 - orGroup: Asteroid diff --git a/Resources/Prototypes/ore.yml b/Resources/Prototypes/ore.yml new file mode 100644 index 0000000000..7c7c7a6e54 --- /dev/null +++ b/Resources/Prototypes/ore.yml @@ -0,0 +1,45 @@ +- type: ore + id: OreSteel + oreEntity: SteelOre1 + minOreYield: 3 + maxOreYield: 7 + +- type: ore + id: OreSpaceQuartz + oreEntity: SpaceQuartz1 + minOreYield: 3 + maxOreYield: 7 + +- type: ore + id: OreGold + oreEntity: GoldOre1 + minOreYield: 2 + maxOreYield: 5 + +- type: ore + id: OrePlasma + oreEntity: PlasmaOre1 + minOreYield: 2 + maxOreYield: 5 + +- type: ore + id: OreSilver + oreEntity: SilverOre1 + minOreYield: 1 + maxOreYield: 3 + +- type: ore + id: OreUranium + oreEntity: UraniumOre1 + minOreYield: 1 + maxOreYield: 3 + +- type: weightedRandom + id: RandomOreDistributionStandard + weights: + OreSteel: 10 + OreSpaceQuartz: 8 + OreGold: 2 + OrePlasma: 4 + OreSilver: 1 + OreUranium: 1 \ No newline at end of file