Add cigarettes and matches to SS14 (#2522)

* Add resources for cigs/matches

* Add files for cigarettes

* Remove Shared Components

* Applied some of the suggestions

* Change priority to allow matches to be set alight by matchbox

* Added item for pack of cigars

* Add swepts resources. Fix naming

* Fix naming, implement suggestions.

* Addressed Paul's suggestions

* Remove unused resources

* Fix Paul's suggestions
This commit is contained in:
Ygg01
2021-01-11 00:17:28 +01:00
committed by GitHub
parent 2a5fda5198
commit c01b1d5c05
31 changed files with 612 additions and 1 deletions

View File

@@ -0,0 +1,66 @@
using Content.Shared.GameObjects.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Nutrition
{
[UsedImplicitly]
public class BurnStateVisualizer : AppearanceVisualizer
{
private string _burntIcon = "burnt-icon";
private string _litIcon = "lit-icon";
private string _unlitIcon = "icon";
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
if (node.TryGetNode("unlitIcon", out var unlitIcon))
{
_unlitIcon = unlitIcon.AsString();
}
if (node.TryGetNode("litIcon", out var litIcon))
{
_litIcon = litIcon.AsString();
}
if (node.TryGetNode("burntIcon", out var burntIcon))
{
_burntIcon = burntIcon.AsString();
}
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
if (component.TryGetData<SharedBurningStates>(SmokingVisuals.Smoking, out var smoking))
{
SetState(component, smoking);
}
}
private void SetState(AppearanceComponent component, SharedBurningStates burnState)
{
if (component.Owner.TryGetComponent<ISpriteComponent>(out var sprite))
{
switch (burnState)
{
case SharedBurningStates.Lit:
sprite.LayerSetState(0, _litIcon);
break;
case SharedBurningStates.Burnt:
sprite.LayerSetState(0, _burntIcon);
break;
default:
sprite.LayerSetState(0, _unlitIcon);
break;
}
}
}
}
}

View File

@@ -169,6 +169,9 @@ namespace Content.Client
"Flammable",
"CreamPie",
"CreamPied",
"Smoking",
"Matchstick",
"Matchbox",
"BlockGameArcade",
"KitchenSpike",
"Butcherable",

View File

@@ -0,0 +1,29 @@
using System.Threading.Tasks;
using Content.Shared.GameObjects.Components;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
namespace Content.Server.GameObjects.Components.Interactable
{
// TODO make changes in icons when different threshold reached
// e.g. different icons for 10% 50% 100%
[RegisterComponent]
public class MatchboxComponent : Component, IInteractUsing
{
public override string Name => "Matchbox";
public int Priority => 1;
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{
if (eventArgs.Using.TryGetComponent<MatchstickComponent>(out var matchstick)
&& matchstick.CurrentState == SharedBurningStates.Unlit)
{
matchstick.Ignite(eventArgs.User);
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,105 @@
#nullable enable
using System.Threading.Tasks;
using Content.Shared.Audio;
using Content.Shared.GameObjects.Components;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.ComponentDependencies;
using Robust.Shared.GameObjects.Components.Timers;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Interactable
{
[RegisterComponent]
[ComponentReference(typeof(IHotItem))]
public class MatchstickComponent : Component, IHotItem, IInteractUsing
{
public override string Name => "Matchstick";
private SharedBurningStates _currentState = SharedBurningStates.Unlit;
/// <summary>
/// How long will matchstick last in seconds.
/// </summary>
[ViewVariables(VVAccess.ReadOnly)] private int _duration;
/// <summary>
/// Sound played when you ignite the matchstick.
/// </summary>
private string? _igniteSound;
/// <summary>
/// Point light component. Gives matches a glow in dark effect.
/// </summary>
[ComponentDependency]
private readonly PointLightComponent? _pointLightComponent = default!;
/// <summary>
/// Current state to matchstick. Can be <code>Unlit</code>, <code>Lit</code> or <code>Burnt</code>.
/// </summary>
[ViewVariables]
public SharedBurningStates CurrentState
{
get => _currentState;
private set
{
_currentState = value;
if (_pointLightComponent != null)
{
_pointLightComponent.Enabled = _currentState == SharedBurningStates.Lit;
}
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(SmokingVisuals.Smoking, _currentState);
}
}
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _duration, "duration", 10);
serializer.DataField(ref _igniteSound, "igniteSound", null);
}
bool IHotItem.IsCurrentlyHot()
{
return CurrentState == SharedBurningStates.Lit;
}
public void Ignite(IEntity user)
{
// Play Sound
if (!string.IsNullOrEmpty(_igniteSound))
{
EntitySystem.Get<AudioSystem>().PlayFromEntity(_igniteSound, Owner,
AudioHelpers.WithVariation(0.125f).WithVolume(-0.125f));
}
// Change state
CurrentState = SharedBurningStates.Lit;
Owner.SpawnTimer(_duration * 1000, () => CurrentState = SharedBurningStates.Burnt);
}
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{
if (eventArgs.Target.TryGetComponent<IHotItem>(out var hotItem)
&& hotItem.IsCurrentlyHot()
&& CurrentState == SharedBurningStates.Unlit)
{
Ignite(eventArgs.User);
return true;
}
return false;
}
}
}

View File

@@ -28,7 +28,8 @@ namespace Content.Server.GameObjects.Components.Interactable
[RegisterComponent]
[ComponentReference(typeof(ToolComponent))]
[ComponentReference(typeof(IToolComponent))]
public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange
[ComponentReference(typeof(IHotItem))]
public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange, IHotItem
{
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
@@ -73,6 +74,11 @@ namespace Content.Server.GameObjects.Components.Interactable
}
}
bool IHotItem.IsCurrentlyHot()
{
return WelderLit;
}
public override void Initialize()
{
base.Initialize();
@@ -285,5 +291,7 @@ namespace Content.Server.GameObjects.Components.Interactable
{
Dirty();
}
}
}

View File

@@ -0,0 +1,107 @@
#nullable enable
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Items.Clothing;
using Content.Shared.GameObjects.Components;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.ComponentDependencies;
using Robust.Shared.GameObjects.Components.Timers;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Nutrition
{
/// <summary>
/// This item acts as a representation for smokable consumables.
///
/// To smoke a cigar, you need:
/// <list type="bullet">
/// <item><description> a hot item (implements IHotItem interface)</description></item>
/// <item><description> that's a alight.</description></item>
/// <item><description> for the target cigar be Unlit. Lit cigars are already lit and butt's don't have any "fuel" left.</description></item>
///</list>
/// TODO: Add reagents that interact when smoking
/// TODO: Allow suicide via excessive Smoking
/// </summary>
[RegisterComponent]
public class SmokingComponent : Component, IInteractUsing, IHotItem
{
public override string Name => "Smoking";
private SharedBurningStates _currentState = SharedBurningStates.Unlit;
[ComponentDependency] private readonly ClothingComponent? _clothingComponent = default!;
[ComponentDependency] private readonly AppearanceComponent? _appearanceComponent = default!;
/// <summary>
/// Duration represents how long will this item last.
/// Generally it ticks down whether it's time-based
/// or consumption-based.
/// </summary>
[ViewVariables] private int _duration;
/// <summary>
/// What is the temperature of the cigar?
///
/// For a regular cigar, the temp approaches around 400°C or 580°C
/// dependant on where you measure.
/// </summary>
[ViewVariables] private float _temperature;
[ViewVariables]
private SharedBurningStates CurrentState
{
get => _currentState;
set
{
_currentState = value;
if (_clothingComponent != null)
{
switch (_currentState)
{
case SharedBurningStates.Lit:
_clothingComponent.EquippedPrefix = "lit";
_clothingComponent.ClothingEquippedPrefix = "lit";
break;
default:
_clothingComponent.EquippedPrefix = "unlit";
_clothingComponent.ClothingEquippedPrefix = "unlit";
break;
}
}
_appearanceComponent?.SetData(SmokingVisuals.Smoking, _currentState);
}
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _duration, "duration", 30);
serializer.DataField(ref _temperature, "temperature", 673.15f);
}
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{
if (eventArgs.Using.TryGetComponent(out IHotItem? lighter)
&& lighter.IsCurrentlyHot()
&& CurrentState == SharedBurningStates.Unlit
)
{
CurrentState = SharedBurningStates.Lit;
// TODO More complex handling of cigar consumption
Owner.SpawnTimer(_duration * 1000, () => CurrentState = SharedBurningStates.Burnt);
return true;
}
return false;
}
bool IHotItem.IsCurrentlyHot()
{
return _currentState == SharedBurningStates.Lit;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components
{
[Serializable, NetSerializable]
public enum SharedBurningStates : byte
{
Unlit,
Lit,
Burnt,
}
}

View File

@@ -0,0 +1,11 @@
using System;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components
{
[Serializable, NetSerializable]
public enum SmokingVisuals : byte
{
Smoking,
}
}

View File

@@ -0,0 +1,17 @@
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
namespace Content.Shared.Interfaces.GameObjects.Components
{
/// <summary>
/// This interface gives components hot quality when they are used.
/// E.g if you hold a lit match or a welder then it will be hot,
/// presuming match is lit or the welder is on respectively.
/// However say you hold an item that is always hot like lava rock,
/// it will be permanently hot.
/// </summary>
public interface IHotItem
{
bool IsCurrentlyHot();
}
}

Binary file not shown.

View File

@@ -4,3 +4,6 @@
description: A vending machine containing smoking supplies.
animationDuration: 2.1
spriteName: cigs
startingInventory:
CigarettePack: 20
Matchbox: 10

View File

@@ -0,0 +1,42 @@
- type: entity
name: "Base Cigarette"
id: BaseCigarette
parent: BaseItem
abstract: true
components:
- type: Sprite
sprite: Objects/Consumable/Fancy/mask_cig.rsi
netsync: false
state: icon
- type: Clothing
sprite: Objects/Consumable/Fancy/mask_cig.rsi
Slots: [ mask ]
HeldPrefix: unlit
size: 1
- type: Smoking
duration: 30
- type: Appearance
visuals:
- type: BurnStateVisualizer
- type: entity
id: Cigarette
parent: BaseCigarette
name: cigarette
description: "If you want to get cancer, might as well do it in style."
- type: entity
id: CigarettePack
parent: SmallboxItem
name: cigarette pack
description: "Pack of cigarettes"
components:
- type: Sprite
sprite: Objects/Consumable/Fancy/cigarettes.rsi
layers:
- state: cig
- type: StorageFill
contents:
- name: Cigarette
amount: 6

View File

@@ -0,0 +1,53 @@
- type: entity
id: SmallboxItem
parent: BaseItem
abstract: true
components:
- type: Storage
capacity: 10
- type: Item
size: 6
- type: entity
name: match stick
parent: BaseItem
id: Matchstick
description: "A simple match stick, used for lighting fine smokables."
components:
- type: Sprite
netsync: false
sprite: Objects/Tools/matches.rsi
layers:
- state: match_unlit
- type: Item
size: 1
sprite: Objects/Tools/matches.rsi
- type: Matchstick
duration: 10
igniteSound: /Audio/Items/match_strike.ogg
- type: PointLight
enabled: false
radius: 1.1
color: darkorange
- type: Appearance
visuals:
- type: BurnStateVisualizer
unlitIcon: match_unlit
litIcon: match_lit
burntIcon: match_burnt
- type: entity
name: match box
parent: SmallboxItem
id: Matchbox
description: "A small box of Almost But Not Quite Plasma Premium Matches."
components:
- type: Matchbox
- type: Sprite
sprite: Objects/Tools/matches.rsi
layers:
- state: matchbox
- type: StorageFill
contents:
- name: Matchstick
amount: 6

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

View File

@@ -0,0 +1,23 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "cig",
"directions": 1
},
{
"name": "cig_empty",
"directions": 1
},
{
"name": "cig_open",
"directions": 1
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

View File

@@ -0,0 +1,85 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "unlit-equipped-MASK",
"directions": 4
},
{
"name": "lit-equipped-MASK",
"directions": 4,
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
],
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
],
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
],
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "burnt-icon",
"directions": 1
},
{
"name": "icon",
"directions": 1
},
{
"name": "lit-icon",
"directions": 1,
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

View File

@@ -0,0 +1,46 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "match_burnt",
"directions": 1
},
{
"name": "match_lit",
"directions": 1,
"delays": [
[
0.2,
0.2,
0.2
]
]
},
{
"name": "match_unlit",
"directions": 1
},
{
"name": "matchbox",
"directions": 1
},
{
"name": "matchbox_almostempty",
"directions": 1
},
{
"name": "matchbox_almostfull",
"directions": 1
},
{
"name": "matchbox_e",
"directions": 1
}
]
}