Bows & arrows (#19771)

This commit is contained in:
Kara
2023-09-22 02:45:21 -07:00
committed by GitHub
parent 1ba1ab6d61
commit f8d194b117
51 changed files with 507 additions and 22 deletions

View File

@@ -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
}

View File

@@ -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);
}
}
}

View 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.Item;
using Content.Shared.Stacks; using Content.Shared.Stacks;
using Content.Shared.Storage; using Content.Shared.Storage;
@@ -15,11 +16,9 @@ public sealed class ItemSystem : SharedItemSystem
if (!Container.TryGetContainingContainer(uid, out var container) || if (!Container.TryGetContainingContainer(uid, out var container) ||
!TryComp<StorageComponent>(container.Owner, out var storage)) !TryComp<StorageComponent>(container.Owner, out var storage))
{
return; return;
}
_storage.RecalculateStorageUsed(storage); _storage.RecalculateStorageUsed(container.Owner, storage);
_storage.UpdateUI(container.Owner, storage); _storage.UpdateUI(container.Owner, storage);
} }
} }

View File

@@ -9,7 +9,6 @@ using Content.Shared.Projectiles;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Events;
using Content.Shared.Effects;
namespace Content.Server.Projectiles; namespace Content.Server.Projectiles;
@@ -30,7 +29,8 @@ public sealed class ProjectileSystem : SharedProjectileSystem
private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref StartCollideEvent args) private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref StartCollideEvent args)
{ {
// This is so entities that shouldn't get a collision are ignored. // 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; return;
var target = args.OtherEntity; var target = args.OtherEntity;
@@ -60,7 +60,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem
_adminLogger.Add(LogType.BulletHit, _adminLogger.Add(LogType.BulletHit,
HasComp<ActorComponent>(target) ? LogImpact.Extreme : LogImpact.High, 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) if (!deleted)

View File

@@ -29,6 +29,12 @@ public sealed partial class EmbeddableProjectileComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("removalTime"), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite), DataField("removalTime"), AutoNetworkedField]
public float? RemovalTime = 3f; 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> /// <summary>
/// How far into the entity should we offset (0 is wherever we collided). /// How far into the entity should we offset (0 is wherever we collided).
/// </summary> /// </summary>

View File

@@ -15,13 +15,14 @@ public sealed partial class ProjectileComponent : Component
/// <summary> /// <summary>
/// User that shot this projectile. /// User that shot this projectile.
/// </summary> /// </summary>
[DataField("shooter"), AutoNetworkedField] public EntityUid Shooter; [DataField("shooter"), AutoNetworkedField]
public EntityUid? Shooter;
/// <summary> /// <summary>
/// Weapon used to shoot. /// Weapon used to shoot.
/// </summary> /// </summary>
[DataField("weapon"), AutoNetworkedField] [DataField("weapon"), AutoNetworkedField]
public EntityUid Weapon; public EntityUid? Weapon;
[DataField("ignoreShooter"), AutoNetworkedField] [DataField("ignoreShooter"), AutoNetworkedField]
public bool IgnoreShooter = true; public bool IgnoreShooter = true;
@@ -41,5 +42,14 @@ public sealed partial class ProjectileComponent : Component
[DataField("soundForce")] [DataField("soundForce")]
public bool ForceSound = false; 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; public bool DamagedEntity;
} }

View File

@@ -73,6 +73,14 @@ public abstract partial class SharedProjectileSystem : EntitySystem
_physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform); _physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform);
_transform.AttachToGridOrMap(uid, 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 // Land it just coz uhhh yeah
var landEv = new LandEvent(args.User, true); var landEv = new LandEvent(args.User, true);
RaiseLocalEvent(uid, ref landEv); RaiseLocalEvent(uid, ref landEv);
@@ -81,6 +89,9 @@ public abstract partial class SharedProjectileSystem : EntitySystem
private void OnEmbedThrowDoHit(EntityUid uid, EmbeddableProjectileComponent component, ThrowDoHitEvent args) private void OnEmbedThrowDoHit(EntityUid uid, EmbeddableProjectileComponent component, ThrowDoHitEvent args)
{ {
if (!component.EmbedOnThrow)
return;
Embed(uid, args.Target, component); Embed(uid, args.Target, component);
} }
@@ -91,7 +102,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem
// Raise a specific event for projectiles. // Raise a specific event for projectiles.
if (TryComp<ProjectileComponent>(uid, out var projectile)) 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); RaiseLocalEvent(uid, ref ev);
} }
} }

View File

@@ -66,6 +66,11 @@ namespace Content.Shared.Storage.Components
[DataField("containerWhitelist")] [DataField("containerWhitelist")]
public HashSet<string>? 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();
} }
} }

View File

@@ -92,7 +92,7 @@ public abstract class SharedStorageSystem : EntitySystem
if (component.Container == default) if (component.Container == default)
return; return;
RecalculateStorageUsed(component); RecalculateStorageUsed(uid, component);
UpdateStorageVisualization(uid, component); UpdateStorageVisualization(uid, component);
UpdateUI(uid, component); UpdateUI(uid, component);
Dirty(uid, component); Dirty(uid, component);
@@ -394,7 +394,7 @@ public abstract class SharedStorageSystem : EntitySystem
_appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsUiOpen); _appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsUiOpen);
} }
public void RecalculateStorageUsed(StorageComponent storageComp) public void RecalculateStorageUsed(EntityUid uid, StorageComponent storageComp)
{ {
storageComp.StorageUsed = 0; storageComp.StorageUsed = 0;
@@ -406,6 +406,9 @@ public abstract class SharedStorageSystem : EntitySystem
var size = itemComp.Size; var size = itemComp.Size;
storageComp.StorageUsed += 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) public int GetAvailableSpace(EntityUid uid, StorageComponent? component = null)

View File

@@ -130,6 +130,8 @@ namespace Content.Shared.Storage
Open, Open,
HasContents, HasContents,
CanLock, CanLock,
Locked Locked,
StorageUsed,
Capacity
} }
} }

View File

@@ -106,7 +106,8 @@ public sealed class ThrowingSystem : EntitySystem
return; 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; return;
var comp = EnsureComp<ThrownItemComponent>(uid); var comp = EnsureComp<ThrownItemComponent>(uid);

View File

@@ -64,7 +64,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem
component.Amount <= 0 || component.Amount <= 0 ||
component.Whitelist?.IsValid(args.OtherEntity, EntityManager) == false || component.Whitelist?.IsValid(args.OtherEntity, EntityManager) == false ||
!TryComp<ProjectileComponent>(uid, out var projectile) || !TryComp<ProjectileComponent>(uid, out var projectile) ||
!projectile.Weapon.IsValid()) projectile.Weapon == null)
{ {
return; return;
} }
@@ -72,7 +72,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem
// Markers are exclusive, deal with it. // Markers are exclusive, deal with it.
var marker = EnsureComp<DamageMarkerComponent>(args.OtherEntity); var marker = EnsureComp<DamageMarkerComponent>(args.OtherEntity);
marker.Damage = new DamageSpecifier(component.Damage); marker.Damage = new DamageSpecifier(component.Damage);
marker.Marker = projectile.Weapon; marker.Marker = projectile.Weapon.Value;
marker.EndTime = _timing.CurTime + component.Duration; marker.EndTime = _timing.CurTime + component.Duration;
component.Amount--; component.Amount--;
Dirty(marker); Dirty(marker);

View File

@@ -119,7 +119,7 @@ public abstract class SharedReflectSystem : EntitySystem
if (Resolve(projectile, ref projectileComp, false)) 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.Shooter = user;
projectileComp.Weapon = user; projectileComp.Weapon = user;

View File

@@ -1,5 +1,6 @@
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Wieldable.Components; namespace Content.Shared.Wieldable.Components;
@@ -33,3 +34,9 @@ public sealed partial class WieldableComponent : Component
[DataField("wieldTime")] [DataField("wieldTime")]
public float WieldTime = 1.5f; public float WieldTime = 1.5f;
} }
[Serializable, NetSerializable]
public enum WieldableVisuals : byte
{
Wielded
}

View File

@@ -24,6 +24,7 @@ public sealed class WieldableSystem : EntitySystem
[Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -224,6 +225,7 @@ public sealed class WieldableSystem : EntitySystem
var ev = new ItemWieldedEvent(); var ev = new ItemWieldedEvent();
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);
_appearance.SetData(uid, WieldableVisuals.Wielded, true);
Dirty(component); Dirty(component);
args.Handled = true; 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); ("user", args.User.Value), ("item", uid)), args.User.Value, Filter.PvsExcept(args.User.Value), true);
} }
_appearance.SetData(uid, WieldableVisuals.Wielded, false);
Dirty(component); Dirty(component);
_virtualItemSystem.DeleteInHandsMatching(args.User.Value, uid); _virtualItemSystem.DeleteInHandsMatching(args.User.Value, uid);
} }

View File

@@ -62,3 +62,8 @@
license: "CC-BY-4.0" license: "CC-BY-4.0"
copyright: "User volivieri on freesound.org. Modified by Velcroboy on github." copyright: "User volivieri on freesound.org. Modified by Velcroboy on github."
source: "https://freesound.org/people/volivieri/sounds/37190/" 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/"

Binary file not shown.

Binary file not shown.

View 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/"

View File

@@ -204,6 +204,8 @@
prob: 0.2 prob: 0.2
- id: ClothingHandsGlovesColorYellow - id: ClothingHandsGlovesColorYellow
prob: 0.05 prob: 0.05
- id: ClothingBeltQuiver
prob: 0.02
- id: ClothingBeltUtility - id: ClothingBeltUtility
prob: 0.10 prob: 0.10
- id: ClothingHeadHatCone - id: ClothingHeadHatCone

View 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-

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -118,3 +118,25 @@
description: Crude and falling apart. Why would you make this? description: Crude and falling apart. Why would you make this?
icon: { sprite: Objects/Weapons/Melee/shields.rsi, state: makeshift-icon } icon: { sprite: Objects/Weapons/Melee/shields.rsi, state: makeshift-icon }
objectType: Item 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

View File

@@ -16,6 +16,9 @@
- type: Tag - type: Tag
id: ArtifactFragment id: ArtifactFragment
- type: Tag
id: Arrow
- type: Tag - type: Tag
id: ATVKeys id: ATVKeys

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

View 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"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

View File

@@ -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
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

View File

@@ -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
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B