diff --git a/Content.Client/Storage/Components/StorageContainerVisualsComponent.cs b/Content.Client/Storage/Components/StorageContainerVisualsComponent.cs new file mode 100644 index 0000000000..9f07867da8 --- /dev/null +++ b/Content.Client/Storage/Components/StorageContainerVisualsComponent.cs @@ -0,0 +1,29 @@ +using Content.Client.Chemistry.Visualizers; + +namespace Content.Client.Storage.Components; + +/// +/// Essentially a version of fill level handling but for item storage. +/// Depending on the fraction of storage that's filled, will change the sprite at to the nearest +/// fill level, up to . +/// +[RegisterComponent] +public sealed partial class StorageContainerVisualsComponent : Component +{ + [DataField("maxFillLevels")] + public int MaxFillLevels = 0; + + /// + /// A prefix to use for the fill states., i.e. {FillBaseName}{fill level} for the state + /// + [DataField("fillBaseName")] + public string? FillBaseName; + + [DataField("layer")] + public StorageContainerVisualLayers FillLayer = StorageContainerVisualLayers.Fill; +} + +public enum StorageContainerVisualLayers : byte +{ + Fill +} diff --git a/Content.Client/Storage/Systems/StorageContainerVisualsSystem.cs b/Content.Client/Storage/Systems/StorageContainerVisualsSystem.cs new file mode 100644 index 0000000000..a13d6cba22 --- /dev/null +++ b/Content.Client/Storage/Systems/StorageContainerVisualsSystem.cs @@ -0,0 +1,44 @@ +using Content.Client.Storage.Components; +using Content.Shared.Rounding; +using Content.Shared.Storage; +using Robust.Client.GameObjects; + +namespace Content.Client.Storage.Systems; + +/// +public sealed class StorageContainerVisualsSystem : VisualizerSystem +{ + protected override void OnAppearanceChange(EntityUid uid, StorageContainerVisualsComponent component, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + if (!AppearanceSystem.TryGetData(uid, StorageVisuals.StorageUsed, out var used, args.Component)) + return; + + if (!AppearanceSystem.TryGetData(uid, StorageVisuals.Capacity, out var capacity, args.Component)) + return; + + var fraction = used / (float) capacity; + + if (!args.Sprite.LayerMapTryGet(component.FillLayer, out var fillLayer)) + return; + + var closestFillSprite = Math.Min(ContentHelpers.RoundToNearestLevels(fraction, 1, component.MaxFillLevels + 1), + component.MaxFillLevels); + + if (closestFillSprite > 0) + { + if (component.FillBaseName == null) + return; + + args.Sprite.LayerSetVisible(fillLayer, true); + var stateName = component.FillBaseName + closestFillSprite; + args.Sprite.LayerSetState(fillLayer, stateName); + } + else + { + args.Sprite.LayerSetVisible(fillLayer, false); + } + } +} diff --git a/Content.Server/Item/ItemSystem.cs b/Content.Server/Item/ItemSystem.cs index 55fb5aae09..efb99ae653 100644 --- a/Content.Server/Item/ItemSystem.cs +++ b/Content.Server/Item/ItemSystem.cs @@ -1,4 +1,5 @@ -using Content.Server.Storage.EntitySystems; +using Content.Server.Storage.Components; +using Content.Server.Storage.EntitySystems; using Content.Shared.Item; using Content.Shared.Stacks; using Content.Shared.Storage; @@ -15,11 +16,9 @@ public sealed class ItemSystem : SharedItemSystem if (!Container.TryGetContainingContainer(uid, out var container) || !TryComp(container.Owner, out var storage)) - { return; - } - _storage.RecalculateStorageUsed(storage); + _storage.RecalculateStorageUsed(container.Owner, storage); _storage.UpdateUI(container.Owner, storage); } } diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs index 61d67a469b..60fc0c3b5c 100644 --- a/Content.Server/Projectiles/ProjectileSystem.cs +++ b/Content.Server/Projectiles/ProjectileSystem.cs @@ -9,7 +9,6 @@ using Content.Shared.Projectiles; using Robust.Server.GameObjects; using Robust.Shared.Player; using Robust.Shared.Physics.Events; -using Content.Shared.Effects; namespace Content.Server.Projectiles; @@ -30,7 +29,8 @@ public sealed class ProjectileSystem : SharedProjectileSystem private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref StartCollideEvent args) { // This is so entities that shouldn't get a collision are ignored. - if (args.OurFixtureId != ProjectileFixture || !args.OtherFixture.Hard || component.DamagedEntity) + if (args.OurFixtureId != ProjectileFixture || !args.OtherFixture.Hard + || component.DamagedEntity || component is { Weapon: null, OnlyCollideWhenShot: true }) return; var target = args.OtherEntity; @@ -60,7 +60,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem _adminLogger.Add(LogType.BulletHit, HasComp(target) ? LogImpact.Extreme : LogImpact.High, - $"Projectile {ToPrettyString(uid):projectile} shot by {ToPrettyString(component.Shooter):user} hit {otherName:target} and dealt {modifiedDamage.Total:damage} damage"); + $"Projectile {ToPrettyString(uid):projectile} shot by {ToPrettyString(component.Shooter!.Value):user} hit {otherName:target} and dealt {modifiedDamage.Total:damage} damage"); } if (!deleted) diff --git a/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs b/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs index cf9c15a10d..cde7e637d4 100644 --- a/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs +++ b/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs @@ -29,6 +29,12 @@ public sealed partial class EmbeddableProjectileComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("removalTime"), AutoNetworkedField] public float? RemovalTime = 3f; + /// + /// Whether this entity will embed when thrown, or only when shot as a projectile. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("embedOnThrow"), AutoNetworkedField] + public bool EmbedOnThrow = true; + /// /// How far into the entity should we offset (0 is wherever we collided). /// diff --git a/Content.Shared/Projectiles/ProjectileComponent.cs b/Content.Shared/Projectiles/ProjectileComponent.cs index 1e77e3954c..276e0943e0 100644 --- a/Content.Shared/Projectiles/ProjectileComponent.cs +++ b/Content.Shared/Projectiles/ProjectileComponent.cs @@ -15,13 +15,14 @@ public sealed partial class ProjectileComponent : Component /// /// User that shot this projectile. /// - [DataField("shooter"), AutoNetworkedField] public EntityUid Shooter; + [DataField("shooter"), AutoNetworkedField] + public EntityUid? Shooter; /// /// Weapon used to shoot. /// [DataField("weapon"), AutoNetworkedField] - public EntityUid Weapon; + public EntityUid? Weapon; [DataField("ignoreShooter"), AutoNetworkedField] public bool IgnoreShooter = true; @@ -41,5 +42,14 @@ public sealed partial class ProjectileComponent : Component [DataField("soundForce")] public bool ForceSound = false; + /// + /// Whether this projectile will only collide with entities if it was shot from a gun (if is not null) + /// + [DataField("onlyCollideWhenShot")] + public bool OnlyCollideWhenShot = false; + + /// + /// Whether this projectile has already damaged an entity. + /// public bool DamagedEntity; } diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index 5d4046556a..92465be2e5 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -73,6 +73,14 @@ public abstract partial class SharedProjectileSystem : EntitySystem _physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform); _transform.AttachToGridOrMap(uid, xform); + // Reset whether the projectile has damaged anything if it successfully was removed + if (TryComp(uid, out var projectile)) + { + projectile.Shooter = null; + projectile.Weapon = null; + projectile.DamagedEntity = false; + } + // Land it just coz uhhh yeah var landEv = new LandEvent(args.User, true); RaiseLocalEvent(uid, ref landEv); @@ -81,6 +89,9 @@ public abstract partial class SharedProjectileSystem : EntitySystem private void OnEmbedThrowDoHit(EntityUid uid, EmbeddableProjectileComponent component, ThrowDoHitEvent args) { + if (!component.EmbedOnThrow) + return; + Embed(uid, args.Target, component); } @@ -91,7 +102,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem // Raise a specific event for projectiles. if (TryComp(uid, out var projectile)) { - var ev = new ProjectileEmbedEvent(projectile.Shooter, projectile.Weapon, args.Target); + var ev = new ProjectileEmbedEvent(projectile.Shooter!.Value, projectile.Weapon!.Value, args.Target); RaiseLocalEvent(uid, ref ev); } } diff --git a/Content.Shared/Storage/Components/ItemMapperComponent.cs b/Content.Shared/Storage/Components/ItemMapperComponent.cs index 4512503fde..fd83120af0 100644 --- a/Content.Shared/Storage/Components/ItemMapperComponent.cs +++ b/Content.Shared/Storage/Components/ItemMapperComponent.cs @@ -66,6 +66,11 @@ namespace Content.Shared.Storage.Components [DataField("containerWhitelist")] public HashSet? ContainerWhitelist; - public readonly List SpriteLayers = new(); + /// + /// The list of map layer keys that are valid targets for changing in + /// Can be initialized if already existing on the sprite, or inferred automatically + /// + [DataField("spriteLayers")] + public List SpriteLayers = new(); } } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 6f1336a53b..5faec99fd5 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -92,7 +92,7 @@ public abstract class SharedStorageSystem : EntitySystem if (component.Container == default) return; - RecalculateStorageUsed(component); + RecalculateStorageUsed(uid, component); UpdateStorageVisualization(uid, component); UpdateUI(uid, component); Dirty(uid, component); @@ -394,7 +394,7 @@ public abstract class SharedStorageSystem : EntitySystem _appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsUiOpen); } - public void RecalculateStorageUsed(StorageComponent storageComp) + public void RecalculateStorageUsed(EntityUid uid, StorageComponent storageComp) { storageComp.StorageUsed = 0; @@ -406,6 +406,9 @@ public abstract class SharedStorageSystem : EntitySystem var size = itemComp.Size; storageComp.StorageUsed += size; } + + _appearance.SetData(uid, StorageVisuals.StorageUsed, storageComp.StorageUsed); + _appearance.SetData(uid, StorageVisuals.Capacity, storageComp.StorageCapacityMax); } public int GetAvailableSpace(EntityUid uid, StorageComponent? component = null) diff --git a/Content.Shared/Storage/SharedStorageComponent.cs b/Content.Shared/Storage/SharedStorageComponent.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Content.Shared/Storage/StorageComponent.cs b/Content.Shared/Storage/StorageComponent.cs index 0a924365a4..fdcf06bf5d 100644 --- a/Content.Shared/Storage/StorageComponent.cs +++ b/Content.Shared/Storage/StorageComponent.cs @@ -130,6 +130,8 @@ namespace Content.Shared.Storage Open, HasContents, CanLock, - Locked + Locked, + StorageUsed, + Capacity } } diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index e98beb96c9..35bfc069eb 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -106,7 +106,8 @@ public sealed class ThrowingSystem : EntitySystem return; } - if (projectileQuery.HasComponent(uid)) + // Allow throwing if this projectile only acts as a projectile when shot, otherwise disallow + if (projectileQuery.TryGetComponent(uid, out var proj) && !proj.OnlyCollideWhenShot) return; var comp = EnsureComp(uid); diff --git a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs index 7289b232dc..119b10218d 100644 --- a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs +++ b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs @@ -64,7 +64,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem component.Amount <= 0 || component.Whitelist?.IsValid(args.OtherEntity, EntityManager) == false || !TryComp(uid, out var projectile) || - !projectile.Weapon.IsValid()) + projectile.Weapon == null) { return; } @@ -72,7 +72,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem // Markers are exclusive, deal with it. var marker = EnsureComp(args.OtherEntity); marker.Damage = new DamageSpecifier(component.Damage); - marker.Marker = projectile.Weapon; + marker.Marker = projectile.Weapon.Value; marker.EndTime = _timing.CurTime + component.Duration; component.Amount--; Dirty(marker); diff --git a/Content.Shared/Weapons/Reflect/SharedReflectSystem.cs b/Content.Shared/Weapons/Reflect/SharedReflectSystem.cs index f6193c6898..ffa8180e1a 100644 --- a/Content.Shared/Weapons/Reflect/SharedReflectSystem.cs +++ b/Content.Shared/Weapons/Reflect/SharedReflectSystem.cs @@ -119,7 +119,7 @@ public abstract class SharedReflectSystem : EntitySystem if (Resolve(projectile, ref projectileComp, false)) { - _adminLogger.Add(LogType.BulletHit, LogImpact.Medium, $"{ToPrettyString(user)} reflected {ToPrettyString(projectile)} from {ToPrettyString(projectileComp.Weapon)} shot by {projectileComp.Shooter}"); + _adminLogger.Add(LogType.BulletHit, LogImpact.Medium, $"{ToPrettyString(user)} reflected {ToPrettyString(projectile)} from {ToPrettyString(projectileComp.Weapon!.Value)} shot by {projectileComp.Shooter!.Value}"); projectileComp.Shooter = user; projectileComp.Weapon = user; diff --git a/Content.Shared/Wieldable/Components/WieldableComponent.cs b/Content.Shared/Wieldable/Components/WieldableComponent.cs index 5a8c533c29..050b638215 100644 --- a/Content.Shared/Wieldable/Components/WieldableComponent.cs +++ b/Content.Shared/Wieldable/Components/WieldableComponent.cs @@ -1,5 +1,6 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Serialization; namespace Content.Shared.Wieldable.Components; @@ -33,3 +34,9 @@ public sealed partial class WieldableComponent : Component [DataField("wieldTime")] public float WieldTime = 1.5f; } + +[Serializable, NetSerializable] +public enum WieldableVisuals : byte +{ + Wielded +} diff --git a/Content.Shared/Wieldable/WieldableSystem.cs b/Content.Shared/Wieldable/WieldableSystem.cs index d4d83dfdf7..bf5aa1b723 100644 --- a/Content.Shared/Wieldable/WieldableSystem.cs +++ b/Content.Shared/Wieldable/WieldableSystem.cs @@ -24,6 +24,7 @@ public sealed class WieldableSystem : EntitySystem [Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; public override void Initialize() { @@ -224,6 +225,7 @@ public sealed class WieldableSystem : EntitySystem var ev = new ItemWieldedEvent(); RaiseLocalEvent(uid, ref ev); + _appearance.SetData(uid, WieldableVisuals.Wielded, true); Dirty(component); args.Handled = true; @@ -254,6 +256,8 @@ public sealed class WieldableSystem : EntitySystem ("user", args.User.Value), ("item", uid)), args.User.Value, Filter.PvsExcept(args.User.Value), true); } + _appearance.SetData(uid, WieldableVisuals.Wielded, false); + Dirty(component); _virtualItemSystem.DeleteInHandsMatching(args.User.Value, uid); } diff --git a/Resources/Audio/Items/attributions.yml b/Resources/Audio/Items/attributions.yml index 267d6f3a0a..b69704ce69 100644 --- a/Resources/Audio/Items/attributions.yml +++ b/Resources/Audio/Items/attributions.yml @@ -62,3 +62,8 @@ license: "CC-BY-4.0" copyright: "User volivieri on freesound.org. Modified by Velcroboy on github." source: "https://freesound.org/people/volivieri/sounds/37190/" + +- files: ["bow_pull.ogg"] + license: "CC-BY-3.0" + copyright: "User jzdnvdoosj on freesound.org. Converted to ogg by mirrorcult" + source: "https://freesound.org/people/jzdnvdoosj/sounds/626262/" \ No newline at end of file diff --git a/Resources/Audio/Items/bow_pull.ogg b/Resources/Audio/Items/bow_pull.ogg new file mode 100644 index 0000000000..728489b976 Binary files /dev/null and b/Resources/Audio/Items/bow_pull.ogg differ diff --git a/Resources/Audio/Weapons/Guns/Misc/arrow_nock.ogg b/Resources/Audio/Weapons/Guns/Misc/arrow_nock.ogg new file mode 100644 index 0000000000..2285c47edf Binary files /dev/null and b/Resources/Audio/Weapons/Guns/Misc/arrow_nock.ogg differ diff --git a/Resources/Audio/Weapons/Guns/Misc/attributions.yml b/Resources/Audio/Weapons/Guns/Misc/attributions.yml new file mode 100644 index 0000000000..066c26206e --- /dev/null +++ b/Resources/Audio/Weapons/Guns/Misc/attributions.yml @@ -0,0 +1,4 @@ +- files: ["arrow_nock.ogg"] + license: "CC-BY-NC-4.0" + copyright: "Created by LiamG_SFX, converted to ogg by mirrorcult" + source: "https://freesound.org/people/LiamG_SFX/sounds/322224/" \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml index 32c1cfb506..9ed3acc049 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml @@ -204,6 +204,8 @@ prob: 0.2 - id: ClothingHandsGlovesColorYellow prob: 0.05 + - id: ClothingBeltQuiver + prob: 0.02 - id: ClothingBeltUtility prob: 0.10 - id: ClothingHeadHatCone diff --git a/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml b/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml new file mode 100644 index 0000000000..10332e46aa --- /dev/null +++ b/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml @@ -0,0 +1,22 @@ +- type: entity + parent: ClothingBeltStorageBase + id: ClothingBeltQuiver + name: quiver + description: Can hold up to 15 arrows, and fits snug around your waist. + components: + - type: Sprite + sprite: Clothing/Belt/quiver.rsi + layers: + - state: icon + - map: [ "enum.StorageContainerVisualLayers.Fill" ] + visible: false + - type: Clothing + - type: Storage + capacity: 150 + whitelist: + tags: + - Arrow + - type: Appearance + - type: StorageContainerVisuals + maxFillLevels: 3 + fillBaseName: fill- diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml new file mode 100644 index 0000000000..95282ee63a --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml @@ -0,0 +1,81 @@ +- type: entity + name: bow + parent: BaseItem + id: BaseBow + description: The original rooty tooty point and shooty. + abstract: true + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Bow/bow.rsi + - type: Item + size: 60 + - type: Clothing + quickEquip: false + slots: + - Back + - type: Wieldable + wieldTime: 0.5 + wieldSound: + path: /Audio/Items/bow_pull.ogg + - type: GunRequiresWield + - type: Gun + minAngle: 0 + maxAngle: 5 + fireRate: 1 + selectedMode: SemiAuto + availableModes: + - SemiAuto + soundGunshot: + collection: BulletMiss + soundEmpty: null + - type: ItemSlots + slots: + arrow: + name: Arrow + startingItem: null + insertSound: /Audio/Weapons/Guns/Misc/arrow_nock.ogg + whitelist: + tags: + - Arrow + - type: ContainerContainer + containers: + arrow: !type:ContainerSlot + - type: ContainerAmmoProvider + container: arrow + +- type: entity + id: BowImprovised + parent: BaseBow + components: + - type: Sprite + layers: + - state: unwielded + map: [ base ] + - state: unwielded-arrow + map: [ arrow ] + visible: false + # to elucidate whats intended here: + # arrow is inserted -> ItemMapper sets layer with map `arrow` to visible + # bow is wielded -> generic vis sets states of layers with map `arrow` and `base` + # arrow is removed -> itemmapper sets layer with map `arrow` to invisible + - type: Appearance + - type: ItemMapper + spriteLayers: + - arrow + mapLayers: + arrow: + whitelist: + tags: + - Arrow + - type: GenericVisualizer + visuals: + enum.WieldableVisuals.Wielded: + arrow: + True: { state: wielded-arrow } + False: { state: unwielded-arrow } + base: + True: { state: wielded } + False: { state: unwielded } + - type: Construction + graph: ImprovisedBow + node: ImprovisedBow diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml new file mode 100644 index 0000000000..7112d07f2f --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml @@ -0,0 +1,84 @@ +- type: entity + parent: BaseItem + id: BaseArrow + abstract: true + components: + - type: Item + size: 10 + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/arrows.rsi + - type: Fixtures + fixtures: + fix1: + shape: !type:PhysShapeCircle + radius: 0.2 + density: 5 + mask: + - ItemMask + restitution: 0.3 + friction: 0.2 + projectile: + shape: + !type:PhysShapeAabb + bounds: "-0.1,-0.1,0.1,0.1" + hard: false + mask: + - Impassable + - BulletImpassable + - type: EmbeddableProjectile + sound: /Audio/Weapons/star_hit.ogg + embedOnThrow: false + - type: ThrowingAngle + angle: 0 + - type: Ammo + muzzleFlash: null + - type: Tag + tags: + - Arrow + - type: Projectile + deleteOnCollide: false + onlyCollideWhenShot: true + damage: + types: + Piercing: 25 + +- type: entity + parent: BaseArrow + id: ArrowRegular + name: arrow + description: You can feel the power of the steppe within you. + components: + - type: Sprite + layers: + - state: tail + color: red + - state: rod + color: brown + - state: tip + - type: Projectile + damage: + types: + Piercing: 35 + +- type: entity + parent: BaseArrow + id: ArrowImprovised + name: glass shard arrow + description: The greyshirt's preferred projectile. + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/arrows.rsi + layers: + - state: tail + color: white + - state: rod + color: darkgray + - state: tip + color: lightblue + - type: Projectile + damage: + types: + Piercing: 25 + - type: Construction + graph: ImprovisedArrow + node: ImprovisedArrow diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml new file mode 100644 index 0000000000..346b49cf2f --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml @@ -0,0 +1,23 @@ +- type: constructionGraph + id: ImprovisedArrow + start: start + graph: + - node: start + edges: + - to: ImprovisedArrow + steps: + - material: MetalRod + amount: 1 + doAfter: 0.5 + - material: Cloth + amount: 1 + doAfter: 0.5 + - tag: GlassShard + name: Glass Shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard1 + doAfter: 0.5 + + - node: ImprovisedArrow + entity: ArrowImprovised diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_bow.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_bow.yml new file mode 100644 index 0000000000..33808fc0ac --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_bow.yml @@ -0,0 +1,17 @@ +- type: constructionGraph + id: ImprovisedBow + start: start + graph: + - node: start + edges: + - to: ImprovisedBow + steps: + - material: WoodPlank + amount: 10 + doAfter: 4 + - material: Cloth + amount: 5 + doAfter: 4 + + - node: ImprovisedBow + entity: BowImprovised diff --git a/Resources/Prototypes/Recipes/Construction/weapons.yml b/Resources/Prototypes/Recipes/Construction/weapons.yml index 9d8be93601..25da0d1073 100644 --- a/Resources/Prototypes/Recipes/Construction/weapons.yml +++ b/Resources/Prototypes/Recipes/Construction/weapons.yml @@ -40,7 +40,7 @@ category: construction-category-weapons description: A uranium shard with a piece of cloth wrapped around it. icon: { sprite: Objects/Weapons/Melee/uranium_shiv.rsi, state: icon } - objectType: Item + objectType: Item - type: construction name: crude spear @@ -118,3 +118,25 @@ description: Crude and falling apart. Why would you make this? icon: { sprite: Objects/Weapons/Melee/shields.rsi, state: makeshift-icon } objectType: Item + +- type: construction + name: glass shard arrow + id: ImprovisedArrow + graph: ImprovisedArrow + startNode: start + targetNode: ImprovisedArrow + category: construction-category-weapons + description: An arrow tipped with pieces of a glass shard, for use with a bow. + icon: { sprite: Objects/Weapons/Guns/Bow/bow.rsi, state: wielded-arrow } + objectType: Item + +- type: construction + name: improvised bow + id: ImprovisedBow + graph: ImprovisedBow + startNode: start + targetNode: ImprovisedBow + category: construction-category-weapons + description: A shoddily constructed bow made out of wood and cloth. It's not much, but it's gotten the job done for millennia. + icon: { sprite: Objects/Weapons/Guns/Bow/bow.rsi, state: unwielded } + objectType: Item diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index db260b5155..61acbe2ba8 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -16,6 +16,9 @@ - type: Tag id: ArtifactFragment +- type: Tag + id: Arrow + - type: Tag id: ATVKeys @@ -26,7 +29,7 @@ id: Balloon - type: Tag - id: BaseballBat + id: BaseballBat - type: Tag id: BBQsauce @@ -306,7 +309,7 @@ id: CluwneHorn - type: Tag #Ohioans die happy - id: Corn + id: Corn - type: Tag id: Coldsauce @@ -1014,7 +1017,7 @@ - type: Tag id: WallmountSubstationElectronics - + - type: Tag id: WeaponPistolCHIMPUpgradeKit diff --git a/Resources/Textures/Clothing/Belt/quiver.rsi/equipped-BELT.png b/Resources/Textures/Clothing/Belt/quiver.rsi/equipped-BELT.png new file mode 100644 index 0000000000..951e4421f0 Binary files /dev/null and b/Resources/Textures/Clothing/Belt/quiver.rsi/equipped-BELT.png differ diff --git a/Resources/Textures/Clothing/Belt/quiver.rsi/fill-1.png b/Resources/Textures/Clothing/Belt/quiver.rsi/fill-1.png new file mode 100644 index 0000000000..3b46a22c61 Binary files /dev/null and b/Resources/Textures/Clothing/Belt/quiver.rsi/fill-1.png differ diff --git a/Resources/Textures/Clothing/Belt/quiver.rsi/fill-2.png b/Resources/Textures/Clothing/Belt/quiver.rsi/fill-2.png new file mode 100644 index 0000000000..3fcf6fa919 Binary files /dev/null and b/Resources/Textures/Clothing/Belt/quiver.rsi/fill-2.png differ diff --git a/Resources/Textures/Clothing/Belt/quiver.rsi/fill-3.png b/Resources/Textures/Clothing/Belt/quiver.rsi/fill-3.png new file mode 100644 index 0000000000..8870c8892f Binary files /dev/null and b/Resources/Textures/Clothing/Belt/quiver.rsi/fill-3.png differ diff --git a/Resources/Textures/Clothing/Belt/quiver.rsi/icon.png b/Resources/Textures/Clothing/Belt/quiver.rsi/icon.png new file mode 100644 index 0000000000..c719b3030c Binary files /dev/null and b/Resources/Textures/Clothing/Belt/quiver.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Belt/quiver.rsi/meta.json b/Resources/Textures/Clothing/Belt/quiver.rsi/meta.json new file mode 100644 index 0000000000..9f9ed50989 --- /dev/null +++ b/Resources/Textures/Clothing/Belt/quiver.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "tgstation at a373b4cb08298523d40acc14f9c390a0c403fc31, modified by mirrorcult", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..b09e803ed6 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-left.png new file mode 100644 index 0000000000..2ed02fb5a5 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-right.png new file mode 100644 index 0000000000..c281a19870 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/meta.json new file mode 100644 index 0000000000..f19b1121c1 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/meta.json @@ -0,0 +1,43 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "tgstation at a373b4cb08298523d40acc14f9c390a0c403fc31, equipped-BACKPACK and wielded sprites added by mirrorcult", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "unwielded" + }, + { + "name": "unwielded-arrow" + }, + { + "name": "wielded" + }, + { + "name": "wielded-arrow" + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded-arrow.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded-arrow.png new file mode 100644 index 0000000000..d1417b707f Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded-arrow.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded.png new file mode 100644 index 0000000000..c5dc00243c Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-arrow.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-arrow.png new file mode 100644 index 0000000000..69419f9a7b Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-arrow.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-left.png new file mode 100644 index 0000000000..75a9329f70 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-right.png new file mode 100644 index 0000000000..87451fed6c Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded.png b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded.png new file mode 100644 index 0000000000..41d15ef89a Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-left.png new file mode 100644 index 0000000000..668bed84d1 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-right.png new file mode 100644 index 0000000000..42e1ebc3a6 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json new file mode 100644 index 0000000000..b8313f7810 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "tgstation at a373b4cb08298523d40acc14f9c390a0c403fc31, sprites modified and cut into layers by mirrorcult", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "tail" + }, + { + "name": "rod" + }, + { + "name": "tip" + }, + { + "name": "solution" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/rod.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/rod.png new file mode 100644 index 0000000000..935df1f13d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/rod.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution.png new file mode 100644 index 0000000000..235f318e60 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tail.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tail.png new file mode 100644 index 0000000000..31c4ed7e1f Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tail.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tip.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tip.png new file mode 100644 index 0000000000..e4e795295d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tip.png differ