diff --git a/Content.Shared/Blocking/BlockingSystem.cs b/Content.Shared/Blocking/BlockingSystem.cs new file mode 100644 index 0000000000..813fbdf306 --- /dev/null +++ b/Content.Shared/Blocking/BlockingSystem.cs @@ -0,0 +1,194 @@ +using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; +using Content.Shared.Hands; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Physics; +using Content.Shared.Popups; +using Content.Shared.Toggleable; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Dynamics; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Blocking; + +public sealed class BlockingSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly FixtureSystem _fixtureSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEquip); + SubscribeLocalEvent(OnUnequip); + + SubscribeLocalEvent(OnGetActions); + SubscribeLocalEvent(OnToggleAction); + + SubscribeLocalEvent(OnShutdown); + } + + private void OnEquip(EntityUid uid, BlockingComponent component, GotEquippedHandEvent args) + { + component.User = args.User; + + //To make sure that this bodytype doesn't get set as anything but the original + if (TryComp(args.User, out var physicsComponent) && physicsComponent.BodyType != BodyType.Static + && !TryComp(args.User, out var blockingUserComponent)) + { + var userComp = EnsureComp(args.User); + userComp.BlockingItem = uid; + userComp.OriginalBodyType = physicsComponent.BodyType; + } + } + + private void OnUnequip(EntityUid uid, BlockingComponent component, GotUnequippedHandEvent args) + { + BlockingShutdownHelper(uid, component, args.User); + } + + private void OnGetActions(EntityUid uid, BlockingComponent component, GetItemActionsEvent args) + { + if (component.BlockingToggleAction == null + && _proto.TryIndex(component.BlockingToggleActionId, out InstantActionPrototype? act)) + { + component.BlockingToggleAction = new(act); + } + + if (component.BlockingToggleAction != null) + args.Actions.Add(component.BlockingToggleAction); + } + + private void OnToggleAction(EntityUid uid, BlockingComponent component, ToggleActionEvent args) + { + if(args.Handled) + return; + + if (component.IsBlocking) + StopBlocking(uid, component, args.Performer); + else + StartBlocking(uid, component, args.Performer); + + args.Handled = true; + } + + private void OnShutdown(EntityUid uid, BlockingComponent component, ComponentShutdown args) + { + //In theory the user should not be null when this fires off + if (component.User != null) + { + _actionsSystem.RemoveProvidedActions(component.User.Value, uid); + BlockingShutdownHelper(uid, component, component.User.Value); + } + } + + /// + /// Called where you want the user to start blocking + /// Creates a new hard fixture to bodyblock + /// Also makes the user static to prevent prediction issues + /// + /// The entity with the blocking component + /// The + /// The entity who's using the item to block + /// + public bool StartBlocking(EntityUid item, BlockingComponent component, EntityUid user) + { + if (component.IsBlocking) return false; + + var xform = Transform(user); + + var shieldName = Name(item); + + var msgUser = Loc.GetString("action-popup-blocking-user", ("shield", shieldName)); + var msgOther = Loc.GetString("action-popup-blocking-other", ("blockerName", Name(user)), ("shield", shieldName)); + + if (component.BlockingToggleAction != null) + { + _transformSystem.AnchorEntity(xform); + if (!xform.Anchored) + { + var msgError = Loc.GetString("action-popup-blocking-user-cant-block"); + _popupSystem.PopupEntity(msgError, user, Filter.Entities(user)); + return false; + } + _actionsSystem.SetToggled(component.BlockingToggleAction, true); + _popupSystem.PopupEntity(msgUser, user, Filter.Entities(user)); + _popupSystem.PopupEntity(msgOther, user, Filter.Pvs(user).RemoveWhereAttachedEntity(e => e == user)); + } + + if (TryComp(user, out var physicsComponent)) + { + var fixture = new Fixture(physicsComponent, component.Shape) + { + ID = BlockingComponent.BlockFixtureID, + Hard = true, + CollisionLayer = (int) CollisionGroup.WallLayer + }; + + _fixtureSystem.TryCreateFixture(physicsComponent, fixture); + } + + component.IsBlocking = true; + + return true; + } + + /// + /// Called where you want the user to stop blocking. + /// + /// The entity with the blocking component + /// The + /// The entity who's using the item to block + /// + public bool StopBlocking(EntityUid item, BlockingComponent component, EntityUid user) + { + if (!component.IsBlocking) return false; + + var xform = Transform(user); + + var shieldName = Name(item); + + var msgUser = Loc.GetString("action-popup-blocking-disabling-user", ("shield", shieldName)); + var msgOther = Loc.GetString("action-popup-blocking-disabling-other", ("blockerName", Name(user)), ("shield", shieldName)); + + //If the component blocking toggle isn't null, grab the users SharedBlockingUserComponent and PhysicsComponent + //then toggle the action to false, unanchor the user, remove the hard fixture + //and set the users bodytype back to their original type + if (component.BlockingToggleAction != null && TryComp(user, out var blockingUserComponent) + && TryComp(user, out var physicsComponent)) + { + _transformSystem.Unanchor(xform); + _actionsSystem.SetToggled(component.BlockingToggleAction, false); + _fixtureSystem.DestroyFixture(physicsComponent, BlockingComponent.BlockFixtureID); + physicsComponent.BodyType = blockingUserComponent.OriginalBodyType; + _popupSystem.PopupEntity(msgUser, user, Filter.Entities(user)); + _popupSystem.PopupEntity(msgOther, user, Filter.Pvs(user).RemoveWhereAttachedEntity(e => e == user)); + } + + component.IsBlocking = false; + + return true; + } + + /// + /// Called where you want someone to stop blocking and to remove the from them + /// + /// The item the component is attached to + /// The + /// The person holding the blocking item + private void BlockingShutdownHelper(EntityUid uid, BlockingComponent component, EntityUid user) + { + if (component.IsBlocking) + StopBlocking(uid, component, user); + + RemComp(user); + component.User = null; + } + +} diff --git a/Content.Shared/Blocking/BlockingUserSystem.cs b/Content.Shared/Blocking/BlockingUserSystem.cs new file mode 100644 index 0000000000..a14d42c293 --- /dev/null +++ b/Content.Shared/Blocking/BlockingUserSystem.cs @@ -0,0 +1,60 @@ +using Content.Shared.Audio; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.Hands.EntitySystems; +using Robust.Shared.Audio; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Blocking; + +public sealed class BlockingUserSystem : EntitySystem +{ + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly BlockingSystem _blockingSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnUserDamageModified); + + SubscribeLocalEvent(OnAnchorChanged); + } + + private void OnAnchorChanged(EntityUid uid, BlockingUserComponent component, ref AnchorStateChangedEvent args) + { + if (!args.Anchored) + return; + + if (TryComp(component.BlockingItem, out var blockComp) && blockComp.IsBlocking) + { + _blockingSystem.StopBlocking(component.BlockingItem.Value, blockComp, uid); + } + } + + private void OnDamageChanged(EntityUid uid, BlockingUserComponent component, DamageChangedEvent args) + { + if (component.BlockingItem != null) + { + RaiseLocalEvent(component.BlockingItem.Value, args); + } + } + + private void OnUserDamageModified(EntityUid uid, BlockingUserComponent component, DamageModifyEvent args) + { + if (TryComp(component.BlockingItem, out var blockingComponent)) + { + if (_proto.TryIndex(blockingComponent.PassiveBlockDamageModifer, out DamageModifierSetPrototype? passiveblockModifier) && !blockingComponent.IsBlocking) + args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, passiveblockModifier); + + if (_proto.TryIndex(blockingComponent.ActiveBlockDamageModifier, out DamageModifierSetPrototype? activeBlockModifier) && blockingComponent.IsBlocking) + { + args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, activeBlockModifier); + SoundSystem.Play(blockingComponent.BlockSound.GetSound(), Filter.Pvs(component.Owner, entityManager: EntityManager), component.Owner, AudioHelpers.WithVariation(0.2f)); + } + } + } +} diff --git a/Content.Shared/Blocking/Components/BlockingComponent.cs b/Content.Shared/Blocking/Components/BlockingComponent.cs new file mode 100644 index 0000000000..abdd032a3c --- /dev/null +++ b/Content.Shared/Blocking/Components/BlockingComponent.cs @@ -0,0 +1,64 @@ +using Content.Shared.Actions.ActionTypes; +using Content.Shared.Sound; +using Robust.Shared.Physics.Collision.Shapes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Blocking; + +/// +/// This component goes on an item that you want to use to block +/// +[RegisterComponent] +public sealed class BlockingComponent : Component +{ + /// + /// The entity that's blocking + /// + [ViewVariables] + public EntityUid? User; + + /// + /// Is it currently blocking? + /// + [ViewVariables] + public bool IsBlocking; + + /// + /// The ID for the fixture that's dynamically created when blocking + /// + public const string BlockFixtureID = "blocking-active"; + + /// + /// The shape of the blocking fixture that will be dynamically spawned + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("shape")] + public IPhysShape Shape = new PhysShapeCircle {Radius = 0.5F}; + + /// + /// The damage modifer to use while passively blocking + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("passiveBlockModifier")] + public string PassiveBlockDamageModifer = "Metallic"; + + /// + /// The damage modifier to use while actively blocking. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("activeBlockModifier")] + public string ActiveBlockDamageModifier = "Metallic"; + + [DataField("blockingToggleActionId", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string BlockingToggleActionId = "ToggleBlock"; + + [DataField("blockingToggleAction")] + public InstantAction? BlockingToggleAction; + + /// + /// The sound to be played when you get hit while actively blocking + /// + [ViewVariables] + [DataField("blockSound")] + public SoundSpecifier BlockSound = new SoundPathSpecifier("/Audio/Weapons/block_metal1.ogg"); +} diff --git a/Content.Shared/Blocking/Components/BlockingUserComponent.cs b/Content.Shared/Blocking/Components/BlockingUserComponent.cs new file mode 100644 index 0000000000..6292d7b9c3 --- /dev/null +++ b/Content.Shared/Blocking/Components/BlockingUserComponent.cs @@ -0,0 +1,31 @@ +using Content.Shared.Damage; +using Robust.Shared.Physics; + +namespace Content.Shared.Blocking; + +/// +/// This component gets dynamically added to an Entity via the +/// +[RegisterComponent] +public sealed class BlockingUserComponent : Component +{ + /// + /// The entity that's being used to block + /// + [ViewVariables] + [DataField("blockingItem")] + public EntityUid? BlockingItem; + + [ViewVariables] + [DataField("modifiers")] + public DamageModifierSet Modifiers = default!; + + /// + /// Stores the entities original bodytype + /// Used so that it can be put back to what it was after anchoring + /// + [ViewVariables] + [DataField("originalBodyType")] + public BodyType OriginalBodyType; + +} diff --git a/Resources/Audio/Weapons/block_metal1.ogg b/Resources/Audio/Weapons/block_metal1.ogg new file mode 100644 index 0000000000..c0f98249cd Binary files /dev/null and b/Resources/Audio/Weapons/block_metal1.ogg differ diff --git a/Resources/Audio/Weapons/licenses.txt b/Resources/Audio/Weapons/licenses.txt index 747730fba5..1dd99f9e2b 100644 --- a/Resources/Audio/Weapons/licenses.txt +++ b/Resources/Audio/Weapons/licenses.txt @@ -4,4 +4,6 @@ grille_hit.ogg taken from https://github.com/tgstation/tgstation/blob/803ca4537d slash.ogg taken from https://github.com/tgstation/tgstation/blob/5d264fbea0124e5af511af3fed24203e196d108b/sound/weapons/slash.ogg under CC BY-SA 3.0 -tap.ogg taken from https://github.com/tgstation/tgstation/blob/803ca4537df35cf252b056d8460d510be8a4f353/sound/weapons/tap.ogg under CC BY-SA 3.0 \ No newline at end of file +tap.ogg taken from https://github.com/tgstation/tgstation/blob/803ca4537df35cf252b056d8460d510be8a4f353/sound/weapons/tap.ogg under CC BY-SA 3.0 + +block_metal1.ogg taken from https://github.com/Citadel-Station-13/Citadel-Station-13/commit/31c5996a5db8cce0cb431cb1dc20d99cac83f268 under CC BY-SA 3.0 \ No newline at end of file diff --git a/Resources/Locale/en-US/actions/actions/blocking.ftl b/Resources/Locale/en-US/actions/actions/blocking.ftl new file mode 100644 index 0000000000..48bbe7d83b --- /dev/null +++ b/Resources/Locale/en-US/actions/actions/blocking.ftl @@ -0,0 +1,10 @@ +action-name-blocking = Block +action-description-blocking = Raise or lower your shield. + +action-popup-blocking-user = You raise your {$shield}! +action-popup-blocking-disabling-user = You lower your {$shield}! + +action-popup-blocking-other = {$blockerName} raises their {$shield}! +action-popup-blocking-disabling-other = {$blockerName} lowers their {$shield}! + +action-popup-blocking-user-cant-block = The gravity here prevents you from blocking. diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index 0e37ae4969..c6aa383550 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -54,3 +54,11 @@ description: vending-machine-action-description useDelay: 30 event: !type:VendingMachineSelfDispenseEvent + +- type: instantAction + id: ToggleBlock + name: action-name-blocking + description: action-description-blocking + icon: Objects/Weapons/Melee/shields.rsi/teleriot-icon.png + iconOn: Objects/Weapons/Melee/shields.rsi/teleriot-on.png + event: !type:ToggleActionEvent diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 8b9472462d..8492908a15 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -158,6 +158,7 @@ - Flash - Handcuffs - Stunbaton + - RiotShield - FlashPayload - type: technology diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml index 004b017fac..d6a2cd6aea 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml @@ -11,6 +11,9 @@ ClothingEyesGlassesSunglasses: 2 ClothingBeltSecurityWebbing: 5 Zipties: 12 + RiotShield: 2 + RiotLaserShield: 2 + RiotBulletShield: 2 # security officers need to follow a diet regimen! contrabandInventory: FoodDonutHomer: 12 diff --git a/Resources/Prototypes/Damage/containers.yml b/Resources/Prototypes/Damage/containers.yml index 2fde20d34a..523edd88ff 100644 --- a/Resources/Prototypes/Damage/containers.yml +++ b/Resources/Prototypes/Damage/containers.yml @@ -15,3 +15,12 @@ - Heat - Shock - Structural # this probably should be in separate container + +- type: damageContainer + id: Shield + supportedGroups: + - Brute + supportedTypes: + - Heat + + diff --git a/Resources/Prototypes/Damage/modifier_sets.yml b/Resources/Prototypes/Damage/modifier_sets.yml index 8444bb30cb..c446cfe876 100644 --- a/Resources/Prototypes/Damage/modifier_sets.yml +++ b/Resources/Prototypes/Damage/modifier_sets.yml @@ -151,3 +151,138 @@ Bloodloss: 0.0 # no double dipping Cellular: 0.0 +# Represents what a riot shield should block passively +# Each shield will probably have their own passive and active modifier sets +# Honestly it should not be too high +- type: damageModifierSet + id: PassiveRiotShieldBlock + coefficients: + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 + Heat: 0.9 + +# Represents what a riot shield should block while active +# Should be a higher reduction because you're anchored +- type: damageModifierSet + id: ActiveRiotShieldBlock + coefficients: + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.8 + Heat: 0.8 + flatReductions: + Blunt: 1 + Slash: 1 + Piercing: 1 + Heat: 1 + +- type: damageModifierSet + id: PassiveRiotLaserShieldBlock + coefficients: + Heat: 0.8 + +- type: damageModifierSet + id: ActiveRiotLaserShieldBlock + coefficients: + Heat: 0.7 + flatReductions: + Heat: 2 + +- type: damageModifierSet + id: PassiveRiotBulletShieldBlock + coefficients: + Blunt: 0.8 + Piercing: 0.8 + +- type: damageModifierSet + id: ActiveRiotBulletShieldBlock + coefficients: + Blunt: 0.7 + Piercing: 0.7 + flatReductions: + Blunt: 1.5 + Piercing: 1.5 + +#It's made from wood, so it should probably take more heat/laser damage +- type: damageModifierSet + id: PassiveBucklerBlock + coefficients: + Blunt: 0.95 + Slash: 0.95 + Piercing: 0.95 + Heat: 2 + +- type: damageModifierSet + id: ActiveBucklerBlock + coefficients: + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 2 + flatReductions: + Blunt: 1 + Slash: 1 + Piercing: 1 + +#It's a really crummy shield +- type: damageModifierSet + id: PassiveMakeshiftBlock + coefficients: + Blunt: 0.95 + Slash: 0.95 + Piercing: 0.95 + Heat: 0.9 + +- type: damageModifierSet + id: ActiveMakeshiftBlock + coefficients: + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.8 + flatReductions: + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 1 + +#Clockwork generally takes more laser/heat damage +- type: damageModifierSet + id: PassiveClockworkShieldBlock + coefficients: + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.8 + Heat: 1.5 + +- type: damageModifierSet + id: ActiveClockworkShieldBlock + coefficients: + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 1.5 + flatReductions: + Blunt: 1 + Slash: 1 + Piercing: 1 + +#Mirror shield should reflect heat/laser eventually, but be relatively weak to everything else. +- type: damageModifierSet + id: PassiveMirrorShieldBlock + coefficients: + Blunt: 1.2 + Slash: 1.2 + Piercing: 1.2 + Heat: .7 + +- type: damageModifierSet + id: ActiveMirrorShieldBlock + coefficients: + Blunt: 1.2 + Slash: 1.2 + Piercing: 1.2 + Heat: .6 + flatReductions: + Heat: 1 diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml new file mode 100644 index 0000000000..6fc6fdb43f --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -0,0 +1,194 @@ +- type: entity + name: base shield + parent: BaseItem + id: BaseShield + description: A shield! + abstract: true + components: + - type: Sprite + sprite: Objects/Weapons/Melee/shields.rsi + state: riot-icon + netsync: false + - type: Item + sprite: Objects/Weapons/Melee/shields.rsi + size: 100 + HeldPrefix: riot + - type: Blocking + passiveBlockModifier: PassiveRiotShieldBlock + activeBlockModifier: ActiveRiotShieldBlock + blockingToggleAction: + name: action-name-blocking + description: action-description-blocking + icon: Objects/Weapons/Melee/shields.rsi/teleriot-icon.png + iconOn: Objects/Weapons/Melee/shields.rsi/teleriot-on.png + event: !type:ToggleActionEvent + - type: Damageable + damageContainer: Shield + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 40 #This is probably enough damage before it breaks + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel: + min: 5 + max: 5 + SheetGlass: + min: 5 + max: 5 + +#Security Shields + +- type: entity + name: riot shield + parent: BaseShield + id: RiotShield + description: A large tower shield. Good for controlling crowds. + +- type: entity + name: riot laser shield + parent: BaseShield + id: RiotLaserShield + description: A riot shield built for withstanding lasers, but not much else. + components: + - type: Sprite + state: riot_laser-icon + - type: Item + HeldPrefix: riot_laser + - type: Blocking + passiveBlockModifier: PassiveRiotLaserShieldBlock + activeBlockModifier: ActiveRiotLaserShieldBlock + +- type: entity + name: riot bullet shield + parent: BaseShield + id: RiotBulletShield + description: A ballistic riot shield built for withstanding bullets, but not much else. + components: + - type: Sprite + state: riot_bullet-icon + - type: Item + HeldPrefix: riot_bullet + - type: Blocking + passiveBlockModifier: PassiveRiotBulletShieldBlock + activeBlockModifier: ActiveRiotBulletShieldBlock + +#Craftable shields + +- type: entity + name: wooden buckler + parent: BaseShield + id: WoodenBuckler + description: A small round wooden makeshift shield. + components: + - type: Sprite + state: buckler-icon + - type: Item + HeldPrefix: buckler + - type: Blocking + passiveBlockModifier: PassiveBucklerBlock + activeBlockModifier: ActiveBucklerBlock + - type: Construction + graph: WoodenBuckler + node: woodenBuckler + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 30 #Weaker shield + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + MaterialWoodPlank: + min: 5 + max: 5 + +- type: entity + name: makeshift shield + parent: BaseShield + id: MakeshiftShield + description: A rundown looking shield, not good for much. + components: + - type: Sprite + state: makeshift-icon + - type: Item + HeldPrefix: metal + - type: Blocking + passiveBlockModifier: PassiveMakeshiftBlock + activeBlockModifier: ActiveMakeshiftBlock + - type: Construction + graph: MakeshiftShield + node: makeshiftShield + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 20 #Very weak shield + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel: + min: 1 + max: 2 + +#Magic/Cult Shields (give these to wizard for now) + +- type: entity + name: Clockwork Shield + parent: BaseShield + id: ClockworkShield + description: Ratvar oyrffrf lbh jvgu uvf cebgrpgvba. + components: + - type: Sprite + state: ratvarian-icon + - type: Item + HeldPrefix: ratvarian + - type: Blocking + passiveBlockModifier: PassiveClockworkShieldBlock + activeBlockModifier: ActiveClockworkShieldBlock + #Have it break into brass when clock cult is in + +- type: entity + name: Mirror Shield + parent: BaseShield + id: MirrorShield + description: Eerily glows red... you hear the geometer whispering + components: + - type: Sprite + state: mirror-icon + - type: Item + HeldPrefix: mirror + - type: Blocking + passiveBlockModifier: PassiveMirrorShieldBlock + activeBlockModifier: ActiveMirrorShieldBlock + blockSound: !type:SoundPathSpecifier + path: /Audio/Effects/glass_step.ogg + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 40 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: /Audio/Effects/glass_break1.ogg + - !type:SpawnEntitiesBehavior + spawn: + SheetGlass: + min: 5 + max: 5 diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 8b82310d90..1c7fbfa064 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -305,6 +305,7 @@ - Flash - Handcuffs - Stunbaton + - RiotShield - CartridgePistol - ShellShotgun - CartridgeLightRifle diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/makeshift_shield.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/makeshift_shield.yml new file mode 100644 index 0000000000..0411179189 --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/makeshift_shield.yml @@ -0,0 +1,17 @@ +- type: constructionGraph + id: MakeshiftShield + start: start + graph: + - node: start + edges: + - to: makeshiftShield + steps: + - material: Cable + amount: 15 + doAfter: 2 + - material: Steel + amount: 30 + doAfter: 2 + + - node: makeshiftShield + entity: MakeshiftShield diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/wooden_buckler.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/wooden_buckler.yml new file mode 100644 index 0000000000..ea549328a4 --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/wooden_buckler.yml @@ -0,0 +1,24 @@ +- type: constructionGraph + id: WoodenBuckler + start: start + graph: + - node: start + edges: + - to: woodenBuckler + steps: + - tag: Handcuffs + icon: + sprite: Objects/Misc/cablecuffs.rsi + state: cuff + color: red + name: cuffs + doAfter: 2 + - material: WoodPlank + amount: 20 + doAfter: 2 + - material: Steel + amount: 10 + doAfter: 2 + + - node: woodenBuckler + entity: WoodenBuckler diff --git a/Resources/Prototypes/Recipes/Construction/weapons.yml b/Resources/Prototypes/Recipes/Construction/weapons.yml index e130075b8a..81bbbbf1fb 100644 --- a/Resources/Prototypes/Recipes/Construction/weapons.yml +++ b/Resources/Prototypes/Recipes/Construction/weapons.yml @@ -31,3 +31,24 @@ icon: Objects/Weapons/Guns/Battery/makeshift.rsi/icon.png objectType: Item +- type: construction + name: wooden buckler + id: WoodenBuckler + graph: WoodenBuckler + startNode: start + targetNode: woodenBuckler + category: Weapons + description: A nicely carved wooden shield! + icon: Objects/Weapons/Melee/shields.rsi/buckler-icon.png + objectType: Item + +- type: construction + name: makeshift shield + id: MakeshiftShield + graph: MakeshiftShield + startNode: start + targetNode: makeshiftShield + category: Weapons + description: Crude and falling apart. Why would you make this? + icon: Objects/Weapons/Melee/shields.rsi/makeshift-icon.png + objectType: Item diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml index b3475a18f5..170c364d94 100644 --- a/Resources/Prototypes/Recipes/Lathes/security.yml +++ b/Resources/Prototypes/Recipes/Lathes/security.yml @@ -19,6 +19,17 @@ Steel: 300 Plastic: 300 +- type: latheRecipe + id: RiotShield + icon: + sprite: Objects/Weapons/Melee/shields.rsi + state: riot-icon + result: RiotShield + completetime: 4 + materials: + Steel: 400 + Glass: 400 + - type: latheRecipe id: Flash icon: diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-icon.png new file mode 100644 index 0000000000..a3d5f13be2 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-inhand-left.png new file mode 100644 index 0000000000..0eaa616fe6 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-inhand-right.png new file mode 100644 index 0000000000..14a8b2560a Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/buckler-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-icon.png new file mode 100644 index 0000000000..13dd52422e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-left.png new file mode 100644 index 0000000000..46294e5432 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-right-on.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-right-on.png new file mode 100644 index 0000000000..bdea4cdae8 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-right-on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-right.png new file mode 100644 index 0000000000..ca89fa559e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-on.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-on.png new file mode 100644 index 0000000000..9ea7f2796b Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield-on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield1-inhand-left-on.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield1-inhand-left-on.png new file mode 100644 index 0000000000..3c8a2b3809 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/eshield1-inhand-left-on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/makeshift-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/makeshift-icon.png new file mode 100644 index 0000000000..3c5cdb61dc Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/makeshift-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/meta.json new file mode 100644 index 0000000000..d44aa92605 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/meta.json @@ -0,0 +1,195 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/Citadel-Station-13/Citadel-Station-13/commit/84223c65f5caf667a84f3c0f49bc2a41cdc6c4e3", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "riot-icon" + }, + { + "name": "riot-inhand-right", + "directions": 4 + }, + { + "name": "riot-inhand-left", + "directions": 4 + }, + { + "name": "riot_laser-icon" + }, + { + "name": "riot_laser-inhand-right", + "directions": 4 + }, + { + "name": "riot_laser-inhand-left", + "directions": 4 + }, + { + "name": "riot_bullet-icon" + }, + { + "name": "riot_bullet-inhand-right", + "directions": 4 + }, + { + "name": "riot_bullet-inhand-left", + "directions": 4 + }, + { + "name": "ratvarian-icon" + }, + { + "name": "ratvarian-inhand-right", + "directions": 4 + }, + { + "name": "ratvarian-inhand-left", + "directions": 4 + }, + { + "name": "mirror-icon", + "delays": [ + [ + 0.5, + 0.05, + 0.1, + 0.1 + ] + ] + }, + { + "name": "mirror-inhand-right", + "directions": 4, + "delays": [ + [ + 0.5, + 0.05, + 0.1, + 0.1 + ], + [ + 0.5, + 0.05, + 0.1, + 0.1 + ], + [ + 0.5, + 0.05, + 0.1, + 0.1 + ], + [ + 0.5, + 0.05, + 0.1, + 0.1 + ] + ] + }, + { + "name": "mirror-inhand-left", + "directions": 4, + "delays": [ + [ + 0.5, + 0.05, + 0.1, + 0.1 + ], + [ + 0.5, + 0.05, + 0.1, + 0.1 + ], + [ + 0.5, + 0.05, + 0.1, + 0.1 + ], + [ + 0.5, + 0.05, + 0.1, + 0.1 + ] + ] + }, + { + "name": "buckler-icon" + }, + { + "name": "buckler-inhand-right", + "directions": 4 + }, + { + "name": "buckler-inhand-left", + "directions": 4 + }, + { + "name": "metal-icon" + }, + { + "name": "metal-inhand-right", + "directions": 4 + }, + { + "name": "metal-inhand-left", + "directions": 4 + }, + { + "name": "makeshift-icon" + }, + { + "name": "teleriot-icon" + }, + { + "name": "teleriot-inhand-right", + "directions": 4 + }, + { + "name": "teleriot-inhand-left", + "directions": 4 + }, + { + "name": "teleriot-on" + }, + { + "name": "teleriot-inhand-right-on", + "directions": 4 + }, + { + "name": "teleriot-inhand-left-on", + "directions": 4 + }, + { + "name": "eshield-icon" + }, + { + "name": "eshield-inhand-right", + "directions": 4 + }, + { + "name": "eshield-inhand-left", + "directions": 4 + }, + { + "name": "eshield-on" + }, + { + "name": "eshield-inhand-right-on", + "directions": 4 + }, + { + "name": "eshield1-inhand-left-on", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-icon.png new file mode 100644 index 0000000000..809691e9a5 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-inhand-left.png new file mode 100644 index 0000000000..dfc21c1e58 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-inhand-right.png new file mode 100644 index 0000000000..22d3727dd3 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/metal-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-icon.png new file mode 100644 index 0000000000..22ff0de071 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-inhand-left.png new file mode 100644 index 0000000000..23e00c0734 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-inhand-right.png new file mode 100644 index 0000000000..0ce6509226 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/mirror-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-icon.png new file mode 100644 index 0000000000..4988d84e43 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-inhand-left.png new file mode 100644 index 0000000000..0f6bb836f6 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-inhand-right.png new file mode 100644 index 0000000000..a0cb5577cd Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/ratvarian-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-icon.png new file mode 100644 index 0000000000..29b2087910 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-inhand-left.png new file mode 100644 index 0000000000..f4d5743d0d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-inhand-right.png new file mode 100644 index 0000000000..2765e99f20 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-icon.png new file mode 100644 index 0000000000..3efef44a6f Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-inhand-left.png new file mode 100644 index 0000000000..2dfe40f052 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-inhand-right.png new file mode 100644 index 0000000000..468f4ea089 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_bullet-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-icon.png new file mode 100644 index 0000000000..dd00a61e41 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-inhand-left.png new file mode 100644 index 0000000000..d0cad8761c Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-inhand-right.png new file mode 100644 index 0000000000..f29fe962d9 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/riot_laser-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-icon.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-icon.png new file mode 100644 index 0000000000..a3a42435dd Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-left-on.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-left-on.png new file mode 100644 index 0000000000..02fc79343e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-left-on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-left.png new file mode 100644 index 0000000000..e2e170d529 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-right-on.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-right-on.png new file mode 100644 index 0000000000..0174ec54bc Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-right-on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-right.png new file mode 100644 index 0000000000..9d56b04c18 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-on.png b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-on.png new file mode 100644 index 0000000000..8cb575af35 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/shields.rsi/teleriot-on.png differ