Skip to content

Commit

Permalink
Randomized lollipop and gumball flavors (DeltaV-Station#1074)
Browse files Browse the repository at this point in the history
* Give lollipops and gumballs random flavors

* RandomizedCandy: Fix borg lollipop action

* RandomizedCandy: Play sound when candy is fabricated

* RandomizedCandy: Lollipop can now be put in mouth

* RandomizedCandy: Quieten fab sound

* RandomizedCandy: merge icons and reexport without pHYs chunk

should speed up downloading these textures on 9600 baud modems

* RandomizedCandy: loads more flavors and update description

* RandomizedCandy: Fix duplicate candyFlavor IDs

* RandomizedCandy: Fix attrib and preserve flavor order

* RandomizedCandy: init on MapInit instead of ComponentInit

* RandomizedCandy: Fix minor code style issues, file placement

* RandomizedCandy: put new code into DeltaV namespace

* RandomizedCandy: Removed redundant datafield tags

Signed-off-by: no <165581243+pissdemon@users.noreply.github.com>

---------

Signed-off-by: no <165581243+pissdemon@users.noreply.github.com>
  • Loading branch information
pissdemon authored Apr 14, 2024
1 parent 4b80e48 commit d8b97e8
Show file tree
Hide file tree
Showing 19 changed files with 486 additions and 11 deletions.
26 changes: 26 additions & 0 deletions Content.Client/DeltaV/Abilities/Borgs/RandomizedCandyVisualizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Content.Shared.DeltaV.Abilities.Borgs;
using Robust.Client.GameObjects;

namespace Content.Client.DeltaV.Abilities.Borgs;

/// <summary>
/// Responsible for coloring randomized candy.
/// </summary>
public sealed class RandomizedCandyVisualizer : VisualizerSystem<RandomizedCandyComponent>
{
protected override void OnAppearanceChange(EntityUid uid, RandomizedCandyComponent component, ref AppearanceChangeEvent args)
{
if (!TryComp<SpriteComponent>(uid, out var sprite)
|| !AppearanceSystem.TryGetData<Color>(uid, RandomizedCandyVisuals.Color, out var color, args.Component))
{
return;
}

sprite.LayerSetColor(CandyVisualLayers.Ball, color);
}
}

public enum CandyVisualLayers : byte
{
Ball
}
1 change: 1 addition & 0 deletions Content.Client/Entry/EntryPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public override void Init()
_prototypeManager.RegisterIgnore("wireLayout");
_prototypeManager.RegisterIgnore("alertLevels");
_prototypeManager.RegisterIgnore("nukeopsRole");
_prototypeManager.RegisterIgnore("candyFlavor"); // Delta-V

_componentFactory.GenerateNetIds();
_adminManager.Initialize();
Expand Down
31 changes: 31 additions & 0 deletions Content.Server/DeltaV/Abilities/Borgs/CandyFlavorPrototype.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Content.Shared.Nutrition;
using Robust.Shared.Prototypes;

namespace Content.Server.DeltaV.Abilities.Borgs;

/// <summary>
/// Describes the color and flavor profile of lollipops and gumballs. Yummy!
/// </summary>
[Prototype("candyFlavor")]
public sealed partial class CandyFlavorPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; private set; } = default!;

/// <summary>
/// The display name for this candy. Not localized.
/// </summary>
[DataField] public string Name { get; private set; } = "";

/// <summary>
/// The color of the candy.
/// </summary>
[DataField] public Color Color { get; private set; } = Color.White;

/// <summary>
/// How the candy tastes like.
/// </summary>
[DataField]
public HashSet<ProtoId<FlavorPrototype>> Flavors { get; private set; } = [];
}
83 changes: 83 additions & 0 deletions Content.Server/DeltaV/Abilities/Borgs/RandomizedCandySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Linq;
using Content.Server.Nutrition.Components;
using Content.Shared.DeltaV.Abilities.Borgs;
using Content.Shared.Nutrition;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;

namespace Content.Server.DeltaV.Abilities.Borgs;

/// <summary>
/// Gives things with a <see cref="RandomizedCandyComponent"/> a random flavor, with corresponding appearance and
/// examine text.
/// </summary>
public sealed partial class RandomizedCandySystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;

/// <summary>
/// Flavors that are masked by the candy.
/// </summary>
private static readonly string[] MaskedReagents = { "Sugar", "Iron" }; // sugar is obvious and iron is "metallic" :(

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RandomizedCandyComponent, MapInitEvent>(OnInit);
}

private void OnInit(EntityUid uid, RandomizedCandyComponent candyComp, MapInitEvent args)
{
// pick a random flavor
var flavors = _prototypeManager.EnumeratePrototypes<CandyFlavorPrototype>();
var candyFlavor = _random.Pick(flavors.ToList());

// color the candy :3
_appearance.SetData(uid, RandomizedCandyVisuals.Color, candyFlavor.Color);

// flavor the candy! yummy
var flavorProfile = EnsureComp<FlavorProfileComponent>(uid);
flavorProfile.Flavors.Clear(); // it shouldn't be flavored but clear it anyway
foreach (var flavorId in candyFlavor.Flavors)
{
flavorProfile.Flavors.Add(flavorId);
}
flavorProfile.IgnoreReagents.UnionWith(MaskedReagents); // otherwise the nom text gets too long

// update the candy's metadata with fluff
var meta = MetaData(uid);
if (!string.IsNullOrEmpty(candyFlavor.Name))
_metaData.SetEntityName(uid, $"{candyFlavor.Name} {meta.EntityName}", meta);
_metaData.SetEntityDescription(uid, $"{meta.EntityDescription} {GetExamineFluff(candyFlavor.Flavors)}");
Dirty(uid, meta);
}

// this technically duplicates code from FlavorProfileSystem but what we would need to call
// is upstream code in a private method with fixed loc strings and unnecessary sorting, so i don't want to touch it
private string GetExamineFluff(HashSet<ProtoId<FlavorPrototype>> flavorIds)
{
var flavors = new List<string>();
foreach (var flavorId in flavorIds)
{
if (_prototypeManager.TryIndex(flavorId, out var flavor) &&
Loc.TryGetString(flavor.FlavorDescription, out var flavorText))
{
flavors.Add(flavorText);
}
}

return flavors.Count switch
{
> 1 => Loc.GetString("candy-flavor-profile-multiple",
("lastFlavor", flavors.Pop()),
("flavors", string.Join(", ", flavors))
),
1 => Loc.GetString("candy-flavor-profile", ("flavor", flavors.Single())),
_ => Loc.GetString("candy-flavor-profile-unknown")
};
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
using Robust.Shared.Audio;

namespace Content.Server.Abilities.Borgs;

[RegisterComponent]
public sealed partial class FabricateCandyComponent : Component
{
[DataField("lollipopAction")]
[DataField]
public EntityUid? LollipopAction;

[DataField("gumballAction")]
[DataField]
public EntityUid? GumballAction;

/// <summary>
/// The sound played when fabricating candy.
/// </summary>
[DataField]
public SoundSpecifier FabricationSound = new SoundPathSpecifier("/Audio/Machines/machine_vend.ogg")
{
Params = new AudioParams
{
Volume = -2f
}
};
}
18 changes: 14 additions & 4 deletions Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandySystem.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Robust.Server.Audio;
using Robust.Shared.Prototypes;
using Content.Shared.Actions;
using Content.Shared.Actions.Events;

Expand All @@ -6,6 +8,8 @@ namespace Content.Server.Abilities.Borgs;
public sealed partial class FabricateCandySystem : EntitySystem
{
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!;

public override void Initialize()
{
base.Initialize();
Expand All @@ -25,13 +29,19 @@ private void OnInit(EntityUid uid, FabricateCandyComponent component, ComponentI

private void OnLollipop(FabricateLollipopActionEvent args)
{
Spawn("FoodLollipop", Transform(args.Performer).Coordinates);
args.Handled = true;
OnCandy("FoodLollipop", args);
}

private void OnGumball(FabricateGumballActionEvent args)
{
Spawn("FoodGumball", Transform(args.Performer).Coordinates);
args.Handled = true;
OnCandy("FoodGumball", args);
}

private void OnCandy(EntProtoId proto, BaseActionEvent evt)
{
Spawn(proto, Transform(evt.Performer).Coordinates);
if (TryComp(evt.Performer, out FabricateCandyComponent? comp))
_audioSystem.PlayPvs(comp.FabricationSound, evt.Performer);
evt.Handled = true;
}
}
18 changes: 18 additions & 0 deletions Content.Shared/DeltaV/Abilities/Borgs/RandomizedCandyComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;

namespace Content.Shared.DeltaV.Abilities.Borgs;

/// <summary>
/// Marks this entity as being candy with a random flavor and color.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class RandomizedCandyComponent : Component
{
}

[Serializable, NetSerializable]
public enum RandomizedCandyVisuals : byte
{
Color
}
7 changes: 7 additions & 0 deletions Resources/Locale/en-US/deltav/flavors/flavor-profiles.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@ flavor-complex-daiquiri = fashionable
flavor-complex-arsonistsbrew = like ash and flame
flavor-complex-healthcodeviolation = ominous
flavor-complex-pumpkin = like pumpkin
flavor-complex-blellow = like an impossible color
flavor-complex-candy-strawberry = like strawberries
flavor-complex-candy-bubblegum = like bubble gum
candy-flavor-profile = This one is supposed to taste {$flavor}.
candy-flavor-profile-multiple = This one is supposed to taste {$flavors} and {$lastFlavor}.
candy-flavor-profile-unknown = You have no idea what this one is supposed to taste like.
Loading

0 comments on commit d8b97e8

Please sign in to comment.