Bows & arrows (#19771)
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
0
Content.Shared/Storage/SharedStorageComponent.cs
Normal file
@@ -130,6 +130,8 @@ namespace Content.Shared.Storage
|
||||
Open,
|
||||
HasContents,
|
||||
CanLock,
|
||||
Locked
|
||||
Locked,
|
||||
StorageUsed,
|
||||
Capacity
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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/"
|
||||
BIN
Resources/Audio/Items/bow_pull.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Misc/arrow_nock.ogg
Normal file
4
Resources/Audio/Weapons/Guns/Misc/attributions.yml
Normal file
@@ -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/"
|
||||
@@ -204,6 +204,8 @@
|
||||
prob: 0.2
|
||||
- id: ClothingHandsGlovesColorYellow
|
||||
prob: 0.05
|
||||
- id: ClothingBeltQuiver
|
||||
prob: 0.02
|
||||
- id: ClothingBeltUtility
|
||||
prob: 0.10
|
||||
- id: ClothingHeadHatCone
|
||||
|
||||
22
Resources/Prototypes/Entities/Clothing/Belt/quiver.yml
Normal file
@@ -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-
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
- type: Tag
|
||||
id: ArtifactFragment
|
||||
|
||||
- type: Tag
|
||||
id: Arrow
|
||||
|
||||
- type: Tag
|
||||
id: ATVKeys
|
||||
|
||||
|
||||
BIN
Resources/Textures/Clothing/Belt/quiver.rsi/equipped-BELT.png
Normal file
|
After Width: | Height: | Size: 510 B |
BIN
Resources/Textures/Clothing/Belt/quiver.rsi/fill-1.png
Normal file
|
After Width: | Height: | Size: 116 B |
BIN
Resources/Textures/Clothing/Belt/quiver.rsi/fill-2.png
Normal file
|
After Width: | Height: | Size: 129 B |
BIN
Resources/Textures/Clothing/Belt/quiver.rsi/fill-3.png
Normal file
|
After Width: | Height: | Size: 133 B |
BIN
Resources/Textures/Clothing/Belt/quiver.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 473 B |
27
Resources/Textures/Clothing/Belt/quiver.rsi/meta.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 588 B |
|
After Width: | Height: | Size: 584 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 354 B |
|
After Width: | Height: | Size: 511 B |
|
After Width: | Height: | Size: 349 B |
|
After Width: | Height: | Size: 415 B |
|
After Width: | Height: | Size: 410 B |
BIN
Resources/Textures/Objects/Weapons/Guns/Bow/bow.rsi/wielded.png
Normal file
|
After Width: | Height: | Size: 596 B |
|
After Width: | Height: | Size: 435 B |
|
After Width: | Height: | Size: 440 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 161 B |