Skip to content
This repository was archived by the owner on Aug 22, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Content.Client/E20/E20System.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Content.Shared.E20;
using Robust.Client.GameObjects;

namespace Content.Client.E20;

public sealed class E20System : SharedE20System
{
protected override void UpdateVisuals(EntityUid uid, E20Component? die = null)
{
if (!Resolve(uid, ref die) || !TryComp(uid, out SpriteComponent? sprite))
return;


// TODO maybe just move each diue to its own RSI?
var state = sprite.LayerGetState(0).Name;
if (state == null)
return;

var prefix = state.Substring(0, state.IndexOf('_'));
sprite.LayerSetState(0, $"{prefix}_{die.CurrentValue}");
}
}
407 changes: 407 additions & 0 deletions Content.Server/E20/E20System.Events.cs

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions Content.Server/E20/E20System.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Content.Server.Chat.Systems;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Polymorph.Systems;
using Content.Shared.E20;
using Content.Shared.Explosion.Components;
using Content.Shared.Popups;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;

namespace Content.Server.E20;

public partial class E20System : SharedE20System
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly TriggerSystem _triggerSystem = default!;
[Dependency] private readonly PolymorphSystem _polymorphSystem = default!;

private readonly List<EventsDelegate> _eventsList = new();

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ActiveTimerTriggerComponent, ComponentRemove>(OnTimerRemove);
Events();
}

private void Events()
{
_eventsList.Add(FullDestructionEvent);
_eventsList.Add(DieEvent);
_eventsList.Add(AngryMobsSpawnEvent);
_eventsList.Add(ItemsDestructionEvent);
_eventsList.Add(MonkeyPolymorphEvent);
_eventsList.Add(SpeedReduceEvent);
_eventsList.Add(ThrowingEvent);
_eventsList.Add(ExplosionEvent);
_eventsList.Add(DiseaseEvent);
_eventsList.Add(NothingEvent);
_eventsList.Add(CookieEvent);
_eventsList.Add(RejuvenateEvent);
_eventsList.Add(MoneyEvent);
_eventsList.Add(RevolverEvent);
_eventsList.Add(MagicWandEvent);
_eventsList.Add(SlaveEvent);
_eventsList.Add(RandomSyndieBundleEvent);
_eventsList.Add(FullAccessEvent);
_eventsList.Add(DamageResistEvent);
_eventsList.Add(ChangelingTransformationEvent);
}

private delegate void EventsDelegate(EntityUid uid, E20Component comp);

private void E20Picker(EntityUid uid, E20Component comp)
{
ExplosionEvent(uid, comp);
_polymorphSystem.PolymorphEntity(uid, "DiceShard");
}

private void DiceOfFatePicker(EntityUid uid, E20Component comp)
{
comp.IsUsed = true;

if (comp.CurrentValue > 0 && comp.CurrentValue <= _eventsList.Count)
{
_eventsList[comp.CurrentValue - 1]?.Invoke(uid, comp);
}

if (comp.IsUsed)
{
_polymorphSystem.PolymorphEntity(uid, "DiceShard");
}
}

private void OnTimerRemove(EntityUid uid, ActiveTimerTriggerComponent comp, ComponentRemove args)
{
if (!HasComp<E20Component>(uid))
{
return;
}

E20Component e20 = EntityManager.GetComponent<E20Component>(uid);

if (e20.DiceType == "E20")
{
E20Picker(uid, e20);
return;
}

DiceOfFatePicker(uid, e20);
}

protected override void TimerEvent(EntityUid uid, E20Component? die = null)
{
if (!Resolve(uid, ref die))
return;

_triggerSystem.HandleTimerTrigger(uid, uid, die.Delay, 1, 0, die.Beep);

if (!((die.DiceType == "E20") & ((die.CurrentValue == 1) | (die.CurrentValue == 20))))
return;

_audio.PlayPvs(die.SoundDie, uid);
_chat.TrySendInGameICMessage(uid, Loc.GetString("DIE"), InGameICChatType.Speak, true);
}

/*protected override void Roll(EntityUid uid, E20Component? die = null)
{
if (!Resolve(uid, ref die))
return;

var roll = _random.Next(1, die.Sides + 1);
SetCurrentSide(uid, roll, die);

_popup.PopupEntity(Loc.GetString("dice-component-on-roll-land", ("die", uid), ("currentSide", die.CurrentValue)), uid);
_audio.PlayPvs(die.Sound, uid);
}*/
}

67 changes: 67 additions & 0 deletions Content.Shared/E20/E20Component.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;

namespace Content.Shared.E20;
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(true)]
public sealed partial class E20Component : Component
{

/// <summary>
/// Checks activation of dice to prevent double-triple-.. activation in case of double-triple-.. using dice in hands
/// Or rolling value of dice again after activation.
/// </summary>

[AutoNetworkedField]
public bool IsActivated = false;

public bool IsUsed = false;

/// <summary>
/// Person who used E20. Required when 1 is rolled.
/// </summary>

public EntityUid LastUser;

[DataField(required: true)]
public string DiceType { get; set; } = "E20";

/// <summary>
/// Delay for dice action(Gib or Explosion).
/// </summary>
[DataField]
public float Delay = 3;

[DataField]
public SoundSpecifier Sound { get; private set; } = new SoundCollectionSpecifier("Dice");

[DataField]

public SoundSpecifier SoundDie { get; private set; } = new SoundPathSpecifier("/Audio/Items/E20/e20_1.ogg");

[DataField]
public SoundSpecifier Beep = new SoundPathSpecifier("/Audio/Machines/Nuke/general_beep.ogg");

/// <summary>
/// Multiplier for the value of a die. Applied after the <see cref="Offset"/>.
/// </summary>
[DataField]
public int Multiplier { get; private set; } = 1;

/// <summary>
/// Quantity that is subtracted from the value of a die. Can be used to make dice that start at "0". Applied
/// before the <see cref="Multiplier"/>
/// </summary>
[DataField]
public int Offset { get; private set; } = 0;

[DataField]
public int Sides { get; private set; } = 20;

/// <summary>
/// The currently displayed value.
/// </summary>
[DataField]
[AutoNetworkedField]
public int CurrentValue { get; set; } = 20;
}
90 changes: 90 additions & 0 deletions Content.Shared/E20/SharedE20System.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Content.Shared._Lfwb.PredictedRandom;
using Content.Shared.Interaction.Events;
using Content.Shared.Popups;
using Content.Shared.Throwing;
using Robust.Shared.Audio.Systems;

namespace Content.Shared.E20;

public abstract class SharedE20System : EntitySystem
{
[Dependency] private readonly PredictedRandomSystem _predictedRandom = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<E20Component, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<E20Component, LandEvent>(OnLand);
SubscribeLocalEvent<E20Component, AfterAutoHandleStateEvent>(OnDiceAfterHandleState);
}

private void OnDiceAfterHandleState(EntityUid uid, E20Component component, ref AfterAutoHandleStateEvent args)
{
UpdateVisuals(uid, component);
}

private void OnUseInHand(EntityUid uid, E20Component component , UseInHandEvent args)
{
if (component.IsActivated)
{
return;
}

Roll(uid, component);
component.IsActivated = true;
component.LastUser = args.User;
TimerEvent(uid, component);
}

private void OnLand(EntityUid uid, E20Component component, ref LandEvent args)
{
if (component.IsActivated)
{
return;
}

Roll(uid, component);
}

protected void SetCurrentSide(EntityUid uid, int side, E20Component? 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(die);
UpdateVisuals(uid, die);
}

protected virtual void UpdateVisuals(EntityUid uid, E20Component? die = null)
{
// See client system.
}

protected virtual void TimerEvent(EntityUid uid, E20Component? die = null)
{
// See the server system, client cannot count ¯\_(ツ)_/¯.
}

private void Roll(EntityUid uid, E20Component? die = null)
{
if (!Resolve(uid, ref die))
return;

if (die.IsActivated)
return;

var roll = _predictedRandom.Next(1, die.Sides);
SetCurrentSide(uid, roll, die);

_popup.PopupEntity(Loc.GetString("dice-component-on-roll-land", ("die", uid), ("currentSide", die.CurrentValue)), uid);
_audio.PlayPvs(die.Sound, uid);
}
}
Loading