diff --git a/Content.Client/_White/CoinDice/CoinDiceSystem.cs b/Content.Client/_White/CoinDice/CoinDiceSystem.cs new file mode 100644 index 0000000000..a2d4279f5b --- /dev/null +++ b/Content.Client/_White/CoinDice/CoinDiceSystem.cs @@ -0,0 +1,21 @@ +using Content.Shared._White.CoinDice; +using Robust.Client.GameObjects; + +namespace Content.Client._White.CoinDice; + +public sealed class CoinDiceSystem : SharedCoinDiceSystem +{ + protected override void UpdateVisuals(EntityUid uid, CoinDiceComponent? die = null) + { + if (!Resolve(uid, ref die) || !TryComp(uid, out SpriteComponent? sprite)) + return; + + var state = sprite.LayerGetState(0).Name; + if (state == null) + return; + + var prefix = state.Substring(0, state.IndexOf('_')); + sprite.LayerSetState(0, $"{prefix}_{die.CurrentValue}"); + } + +} diff --git a/Content.Server/_White/CoinDice/CoinDiceSystem.cs b/Content.Server/_White/CoinDice/CoinDiceSystem.cs new file mode 100644 index 0000000000..7b3ce46a72 --- /dev/null +++ b/Content.Server/_White/CoinDice/CoinDiceSystem.cs @@ -0,0 +1,41 @@ +using Content.Shared._White.CoinDice; +using Content.Shared.Popups; +using JetBrains.Annotations; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Random; + +namespace Content.Server._White.CoinDice; + +[UsedImplicitly] +public sealed class CoinDiceSystem : SharedCoinDiceSystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Roll(EntityUid uid, CoinDiceComponent? die = null) + { + if (!Resolve(uid, ref die)) + return; + + var roll = _random.Next(1, die.Sides + 1); + SetCurrentSide(uid, roll, die); + var coindiceResult = ""; + switch (die.CurrentValue) + { + case 1: + coindiceResult = "орёл"; + break; + case 2: + coindiceResult = "решка"; + break; + default: + coindiceResult = "ребро"; + break; + } + + _popup.PopupEntity(Loc.GetString("coindice-component-on-roll-land", ("die", uid), ("currentSide", coindiceResult)), uid); + _audio.PlayPvs(die.Sound, uid); + } +} diff --git a/Content.Shared/_White/CoinDice/CoinDiceComponent.cs b/Content.Shared/_White/CoinDice/CoinDiceComponent.cs new file mode 100644 index 0000000000..5101ae5417 --- /dev/null +++ b/Content.Shared/_White/CoinDice/CoinDiceComponent.cs @@ -0,0 +1,36 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._White.CoinDice; + +[RegisterComponent, NetworkedComponent, Access(typeof(SharedCoinDiceSystem))] +[AutoGenerateComponentState(true)] +public sealed partial class CoinDiceComponent : Component +{ + [DataField] + public SoundSpecifier Sound { get; private set; } = new SoundCollectionSpecifier("Dice"); + + /// + /// Multiplier for the value of a die. Applied after the . + /// + [DataField] + public int Multiplier { get; private set; } = 1; + + /// + /// Quantity that is subtracted from the value of a die. Can be used to make dice that start at "0". Applied + /// before the + /// + [DataField] + public int Offset { get; private set; } = 0; + + [DataField] + public int Sides { get; private set; } = 20; + + /// + /// The currently displayed value. + /// + [DataField] + [AutoNetworkedField] + public int CurrentValue { get; set; } = 20; + +} diff --git a/Content.Shared/_White/CoinDice/SharedCoinDiceSystem.cs b/Content.Shared/_White/CoinDice/SharedCoinDiceSystem.cs new file mode 100644 index 0000000000..fc563960cc --- /dev/null +++ b/Content.Shared/_White/CoinDice/SharedCoinDiceSystem.cs @@ -0,0 +1,104 @@ +using Content.Shared.Examine; +using Content.Shared.Interaction.Events; +using Content.Shared.Throwing; +using Robust.Shared.Timing; + +namespace Content.Shared._White.CoinDice; + +public abstract class SharedCoinDiceSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _gameTiming = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUseInHand); + SubscribeLocalEvent(OnLand); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnDiceAfterHandleState); + } + + private void OnDiceAfterHandleState(EntityUid uid, CoinDiceComponent component, ref AfterAutoHandleStateEvent args) + { + UpdateVisuals(uid, component); + } + + private void OnUseInHand(EntityUid uid, CoinDiceComponent component, UseInHandEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + Roll(uid, component); + } + + private void OnLand(EntityUid uid, CoinDiceComponent component, ref LandEvent args) + { + Roll(uid, component); + } + + private void OnExamined(EntityUid uid, CoinDiceComponent dice, ExaminedEvent args) + { + //No details check, since the sprite updates to show the side. + using (args.PushGroup(nameof(CoinDiceComponent))) + { + args.PushMarkup(Loc.GetString("coindice-component-on-examine-message-part-1")); + var coindiceResult = ""; + switch (dice.CurrentValue) + { + case 1: + coindiceResult = "орёл"; + break; + case 2: + coindiceResult = "решка"; + break; + default: + coindiceResult = "ребро"; + break; + } + args.PushMarkup(Loc.GetString("coindice-component-on-examine-message-part-2", + ("currentSide", coindiceResult))); + } + } + + public void SetCurrentSide(EntityUid uid, int side, CoinDiceComponent? die = null) + { + if (!Resolve(uid, ref die)) + return; + + if (side < 1 || side > die.Sides) + { + Log.Error($"Attempted to set die {ToPrettyString(uid)} to an invalid side ({side})."); + return; + } + + die.CurrentValue = (side - die.Offset) * die.Multiplier; + Dirty(uid, die); + UpdateVisuals(uid, die); + } + + public void SetCurrentValue(EntityUid uid, int value, CoinDiceComponent? die = null) + { + if (!Resolve(uid, ref die)) + return; + + if (value % die.Multiplier != 0 || value / die.Multiplier + die.Offset < 1) + { + Log.Error($"Attempted to set die {ToPrettyString(uid)} to an invalid value ({value})."); + return; + } + + SetCurrentSide(uid, value / die.Multiplier + die.Offset, die); + } + + protected virtual void UpdateVisuals(EntityUid uid, CoinDiceComponent? die = null) + { + // See client system. + } + + public virtual void Roll(EntityUid uid, CoinDiceComponent? die = null) + { + // See the server system, client cannot predict rolling. + } + +} diff --git a/Resources/Locale/ru-RU/dice/dice-component.ftl b/Resources/Locale/ru-RU/dice/dice-component.ftl index 0c0ddb6e88..483f50e92b 100644 --- a/Resources/Locale/ru-RU/dice/dice-component.ftl +++ b/Resources/Locale/ru-RU/dice/dice-component.ftl @@ -1,3 +1,9 @@ dice-component-on-examine-message-part-1 = Кость c [color=lightgray]{ $sidesAmount }[/color] сторонами. dice-component-on-examine-message-part-2 = Она приземлилась на [color=white]{ $currentSide }[/color]. dice-component-on-roll-land = { CAPITALIZE($die) } приземляется на { $currentSide }. + +# CoinDice + +coindice-component-on-examine-message-part-1 = Как и любая другая монетка, имеет две стороны. +coindice-component-on-examine-message-part-2 = Сейчас на вас смотрит - [color=white]{ $currentSide }[/color]. +coindice-component-on-roll-land = { CAPITALIZE($die) } приземляется и вам выпадает - { $currentSide }. diff --git a/Resources/Prototypes/_White/Fluff/fluff.yml b/Resources/Prototypes/_White/Fluff/fluff.yml index fea07c33e8..297fd4a048 100644 --- a/Resources/Prototypes/_White/Fluff/fluff.yml +++ b/Resources/Prototypes/_White/Fluff/fluff.yml @@ -596,20 +596,23 @@ sprite: White/Fluff/Serafim547/salvage.rsi - type: entity - parent: BaseDice + parent: BaseItem id: VulpCoin name: Золотая монета suffix: fluff description: Коллекционная чеканная монета с родины вульпканин, редкая находка обладающая не столь реальной, сколько символической ценностью. components: - - type: Dice + - type: UseDelay + - type: CoinDice sound: collection: CoinDrop sides: 2 - currentValue: 2 + currentValue: 1 - type: Sprite sprite: White/Fluff/Serafim547/vulp_coin.rsi - state: coin_2 + state: coin_1 + - type: Item + size: Tiny # Skrimex diff --git a/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_1.png b/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_1.png index 91bac2bbff..2d3ae3fb0c 100644 Binary files a/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_1.png and b/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_1.png differ diff --git a/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_2.png b/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_2.png index 671d686882..bb9b72909e 100644 Binary files a/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_2.png and b/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/coin_2.png differ diff --git a/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/meta.json b/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/meta.json index e0a701d6ba..e9968cb62a 100644 --- a/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/meta.json +++ b/Resources/Textures/White/Fluff/Serafim547/vulp_coin.rsi/meta.json @@ -14,4 +14,4 @@ "name": "coin_2" } ] -} +} \ No newline at end of file