]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Bows & arrows (#19771)
authorKara <lunarautomaton6@gmail.com>
Fri, 22 Sep 2023 09:45:21 +0000 (02:45 -0700)
committerGitHub <noreply@github.com>
Fri, 22 Sep 2023 09:45:21 +0000 (02:45 -0700)
51 files changed:
Content.Client/Storage/Components/StorageContainerVisualsComponent.cs [new file with mode: 0644]
Content.Client/Storage/Systems/StorageContainerVisualsSystem.cs [new file with mode: 0644]
Content.Server/Item/ItemSystem.cs
Content.Server/Projectiles/ProjectileSystem.cs
Content.Shared/Projectiles/EmbeddableProjectileComponent.cs
Content.Shared/Projectiles/ProjectileComponent.cs
Content.Shared/Projectiles/SharedProjectileSystem.cs
Content.Shared/Storage/Components/ItemMapperComponent.cs
Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
Content.Shared/Storage/SharedStorageComponent.cs [new file with mode: 0644]
Content.Shared/Storage/StorageComponent.cs
Content.Shared/Throwing/ThrowingSystem.cs
Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs
Content.Shared/Weapons/Reflect/SharedReflectSystem.cs
Content.Shared/Wieldable/Components/WieldableComponent.cs
Content.Shared/Wieldable/WieldableSystem.cs
Resources/Audio/Items/attributions.yml
Resources/Audio/Items/bow_pull.ogg [new file with mode: 0644]
Resources/Audio/Weapons/Guns/Misc/arrow_nock.ogg [new file with mode: 0644]
Resources/Audio/Weapons/Guns/Misc/attributions.yml [new file with mode: 0644]
Resources/Prototypes/Catalog/Fills/Lockers/misc.yml
Resources/Prototypes/Entities/Clothing/Belt/quiver.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml [new file with mode: 0644]
Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml [new file with mode: 0644]
Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_bow.yml [new file with mode: 0644]
Resources/Prototypes/Recipes/Construction/weapons.yml
Resources/Prototypes/tags.yml
Resources/Textures/Clothing/Belt/quiver.rsi/equipped-BELT.png [new file with mode: 0644]
Resources/Textures/Clothing/Belt/quiver.rsi/fill-1.png [new file with mode: 0644]
Resources/Textures/Clothing/Belt/quiver.rsi/fill-2.png [new file with mode: 0644]
Resources/Textures/Clothing/Belt/quiver.rsi/fill-3.png [new file with mode: 0644]
Resources/Textures/Clothing/Belt/quiver.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Clothing/Belt/quiver.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/equipped-BACKPACK.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-left.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/inhand-right.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded-arrow.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/unwielded.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-arrow.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-left.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded-inhand-right.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-left.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/inhand-right.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/rod.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tail.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tip.png [new file with mode: 0644]

diff --git a/Content.Client/Storage/Components/StorageContainerVisualsComponent.cs b/Content.Client/Storage/Components/StorageContainerVisualsComponent.cs
new file mode 100644 (file)
index 0000000..9f07867
--- /dev/null
@@ -0,0 +1,29 @@
+using Content.Client.Chemistry.Visualizers;
+
+namespace Content.Client.Storage.Components;
+
+/// <summary>
+///     Essentially a version of <see cref="SolutionContainerVisualsComponent"/> fill level handling but for item storage.
+///     Depending on the fraction of storage that's filled, will change the sprite at <see cref="FillLayer"/> to the nearest
+///     fill level, up to <see cref="MaxFillLevels"/>.
+/// </summary>
+[RegisterComponent]
+public sealed partial class StorageContainerVisualsComponent : Component
+{
+    [DataField("maxFillLevels")]
+    public int MaxFillLevels = 0;
+
+    /// <summary>
+    ///     A prefix to use for the fill states., i.e. {FillBaseName}{fill level} for the state
+    /// </summary>
+    [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 (file)
index 0000000..a13d6cb
--- /dev/null
@@ -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;
+
+/// <inheritdoc cref="StorageContainerVisualsComponent"/>
+public sealed class StorageContainerVisualsSystem : VisualizerSystem<StorageContainerVisualsComponent>
+{
+    protected override void OnAppearanceChange(EntityUid uid, StorageContainerVisualsComponent component, ref AppearanceChangeEvent args)
+    {
+        if (args.Sprite == null)
+            return;
+
+        if (!AppearanceSystem.TryGetData<int>(uid, StorageVisuals.StorageUsed, out var used, args.Component))
+            return;
+
+        if (!AppearanceSystem.TryGetData<int>(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);
+        }
+    }
+}
index 55fb5aae0913043bc988ae85f0da171da6b73a31..efb99ae65334260c813214f8c4aa6f4c407d349f 100644 (file)
@@ -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<StorageComponent>(container.Owner, out var storage))
-        {
             return;
-        }
 
-        _storage.RecalculateStorageUsed(storage);
+        _storage.RecalculateStorageUsed(container.Owner, storage);
         _storage.UpdateUI(container.Owner, storage);
     }
 }
index 61d67a469b520e86e12cefd2115a267401db27c6..60fc0c3b5cda558253558ae45bbaba6cba0a5087 100644 (file)
@@ -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<ActorComponent>(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)
index cf9c15a10da883311fb73f072d883228b9f03a90..cde7e637d4a8a59fe652d6dc2a724d8771842115 100644 (file)
@@ -29,6 +29,12 @@ public sealed partial class EmbeddableProjectileComponent : Component
     [ViewVariables(VVAccess.ReadWrite), DataField("removalTime"), AutoNetworkedField]
     public float? RemovalTime = 3f;
 
+    /// <summary>
+    ///     Whether this entity will embed when thrown, or only when shot as a projectile.
+    /// </summary>
+    [ViewVariables(VVAccess.ReadWrite), DataField("embedOnThrow"), AutoNetworkedField]
+    public bool EmbedOnThrow = true;
+
     /// <summary>
     /// How far into the entity should we offset (0 is wherever we collided).
     /// </summary>
index 1e77e3954cec6ab67ed9278a884fc11f438b5fb3..276e0943e0213adef93a068524e776335faf53df 100644 (file)
@@ -15,13 +15,14 @@ public sealed partial class ProjectileComponent : Component
     /// <summary>
     /// User that shot this projectile.
     /// </summary>
-    [DataField("shooter"), AutoNetworkedField] public EntityUid Shooter;
+    [DataField("shooter"), AutoNetworkedField]
+    public EntityUid? Shooter;
 
     /// <summary>
     /// Weapon used to shoot.
     /// </summary>
     [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;
 
+    /// <summary>
+    ///     Whether this projectile will only collide with entities if it was shot from a gun (if <see cref="Weapon"/> is not null)
+    /// </summary>
+    [DataField("onlyCollideWhenShot")]
+    public bool OnlyCollideWhenShot = false;
+
+    /// <summary>
+    ///     Whether this projectile has already damaged an entity.
+    /// </summary>
     public bool DamagedEntity;
 }
index 5d4046556a2b629212cb1d04ffd8965ebe71e528..92465be2e58c129ab703610fa111720f63c81dc5 100644 (file)
@@ -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<ProjectileComponent>(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<ProjectileComponent>(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);
         }
     }
index 4512503fdefbc70b6d3e73d6de0ec4014d9624f0..fd83120af0c659e9e48c82659cfd65183e61a352 100644 (file)
@@ -66,6 +66,11 @@ namespace Content.Shared.Storage.Components
         [DataField("containerWhitelist")]
         public HashSet<string>? ContainerWhitelist;
 
-        public readonly List<string> SpriteLayers = new();
+        /// <summary>
+        ///     The list of map layer keys that are valid targets for changing in <see cref="MapLayers"/>
+        ///     Can be initialized if already existing on the sprite, or inferred automatically
+        /// </summary>
+        [DataField("spriteLayers")]
+        public List<string> SpriteLayers = new();
     }
 }
index 6f1336a53b45baaf52af6ddb27efa860aa0b02a1..5faec99fd5b7a9d339163f88d12456f9bda62afc 100644 (file)
@@ -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 (file)
index 0000000..e69de29
index 0a924365a42ac0e14d8d4d2509f89bf48876a443..fdcf06bf5d5f11b72ccffe2ed73959a2ed076e04 100644 (file)
@@ -130,6 +130,8 @@ namespace Content.Shared.Storage
         Open,
         HasContents,
         CanLock,
-        Locked
+        Locked,
+        StorageUsed,
+        Capacity
     }
 }
index e98beb96c9e9b7ac3d295d2dc7df4766464dd538..35bfc069eb0f82a0e8aaa11111bf777084e8c715 100644 (file)
@@ -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<ThrownItemComponent>(uid);
index 7289b232dc6b854d8e2249fe3278a918a9001727..119b10218d8a75c9b564a082749eb53867bb54ba 100644 (file)
@@ -64,7 +64,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem
             component.Amount <= 0 ||
             component.Whitelist?.IsValid(args.OtherEntity, EntityManager) == false ||
             !TryComp<ProjectileComponent>(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<DamageMarkerComponent>(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);
index f6193c6898acec179a0ba7930819032a7b5edab8..ffa8180e1a728ad0d82e2f6293fe1fe0f6c190d3 100644 (file)
@@ -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;
index 5a8c533c29a1bdd3335f24620f9782943db6a73b..050b6382150bd51053e89cbe3b88f3ee0e0b6650 100644 (file)
@@ -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
+}
index d4d83dfdf71a578712796dad7f645f2708a5ea7b..bf5aa1b723099cf7b1bb852925b5a55a8402d9a3 100644 (file)
@@ -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);
     }
index 267d6f3a0a2a266348b80183530f5a2ce0e694cd..b69704ce696f702fc7e7160462d9d10768d570c5 100644 (file)
@@ -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 (file)
index 0000000..728489b
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 (file)
index 0000000..2285c47
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 (file)
index 0000000..066c262
--- /dev/null
@@ -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
index 32c1cfb506b43219e7d3bb02fd8b31a13ae040fd..9ed3acc04933ab550e456e2c76c3e2ce72a88266 100644 (file)
           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 (file)
index 0000000..10332e4
--- /dev/null
@@ -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 (file)
index 0000000..95282ee
--- /dev/null
@@ -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 (file)
index 0000000..7112d07
--- /dev/null
@@ -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 (file)
index 0000000..346b49c
--- /dev/null
@@ -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 (file)
index 0000000..33808fc
--- /dev/null
@@ -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
index 9d8be9360176925cf7908a3a724e3261c1bc9d8d..25da0d10733a2ed0536a4024b0ea4bc2a54271e0 100644 (file)
@@ -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
   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
index db260b5155a0cabf7a730121ecddf4d5bc048a4e..61acbe2ba874a29e6eed81bc03ae1c135402f0ff 100644 (file)
@@ -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
   id: CluwneHorn
 
 - type: Tag #Ohioans die happy
-  id: Corn 
+  id: Corn
 
 - type: Tag
   id: Coldsauce
 
 - 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 (file)
index 0000000..951e442
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 (file)
index 0000000..3b46a22
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 (file)
index 0000000..3fcf6fa
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 (file)
index 0000000..8870c88
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 (file)
index 0000000..c719b30
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 (file)
index 0000000..9f9ed50
--- /dev/null
@@ -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 (file)
index 0000000..b09e803
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 (file)
index 0000000..2ed02fb
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 (file)
index 0000000..c281a19
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 (file)
index 0000000..f19b112
--- /dev/null
@@ -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 (file)
index 0000000..d1417b7
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 (file)
index 0000000..c5dc002
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 (file)
index 0000000..69419f9
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 (file)
index 0000000..75a9329
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 (file)
index 0000000..87451fe
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 (file)
index 0000000..41d15ef
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 (file)
index 0000000..668bed8
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 (file)
index 0000000..42e1ebc
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 (file)
index 0000000..b8313f7
--- /dev/null
@@ -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 (file)
index 0000000..935df1f
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 (file)
index 0000000..235f318
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 (file)
index 0000000..31c4ed7
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 (file)
index 0000000..e4e7952
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/tip.png differ