Flavor profiles (#10991)

* flavor profiles

TODO: every single flavor! yeah!!!

* adds basic localization, and flavors/lastFlavor values for when you get the flavor profile message

* multiple and single flavor messages

* start on flavor localization, multiple flavors in localized flavors

* flavor prototypes

* a few more flavors, descriptions on what each section of the flavor file should be doing

* localization for flavor profiles in drink/food system

* adds an event that allows a flavor profile list to be transformed base on the user entity

* raises it on the food entity too

* changes a field in flavor, adds some more flavors, starts adding flavor prototypes

* adds basic flavors to several entities, and consumable drinks, renames flavor field to 'flavors'

* changes call ordering in flavorprofile, adds flavor to ignored components server-side

flavor is really just a popup message, and those are all processed server-side

* fixes where food tried to get the flavor of the user instead of the food

* single flavors will now get the localized string

* getting the flavor message now ensures that flavors are deduplicated

* makes flavor processing more strictly unique bu making everything hashsets

* yeah, that could just not have distinctby now

* adds flavorprofile directly to food base instead for generic food taste

* FlavorProfileModificationEvent now passes a hashset of strings and not flavorprototypes

* flavorprofilesystem now broadcasts the flavor profile modification event

* adds more flavors to the flavor profile loc file

* skips a flavor, if the flavor string is null/empty

* adds some more flavors, adds generic medicine flavor to medicinal chemicals

* more food flavors, adds flavors to swallowing

* adds some cocktails to the set of flavor profiles

* regenerates flavor prototypes

* adds flavor type to all flavors, adds whitespace between variants

* adds more flavors, adds flavors to several chemicals and food items

this is the part that took the longest

* changes backup flavor message

* spelling mistake

* more flavors, and flavors on food

* readds all the type fields, whoops

* fixes localization strings for forcefeeding food/drink

* fixes multiple flavor profile

* adds flavor limit for flavors

* makes that fetch the cvardef instead
This commit is contained in:
Flipp Syder
2022-09-08 16:14:49 -07:00
committed by GitHub
parent f3510324ea
commit 3cfa00e91c
45 changed files with 2048 additions and 9 deletions

View File

@@ -32,6 +32,7 @@ namespace Content.Server.Nutrition.EntitySystems
public sealed class DrinkSystem : EntitySystem
{
[Dependency] private readonly FoodSystem _foodSystem = default!;
[Dependency] private readonly FlavorProfileSystem _flavorProfileSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
@@ -335,13 +336,15 @@ namespace Content.Server.Nutrition.EntitySystems
return;
}
var flavors = _flavorProfileSystem.GetLocalizedFlavorsMessage(args.User, drained);
if (forceDrink)
{
var targetName = Identity.Entity(uid, EntityManager);
var userName = Identity.Entity(args.User, EntityManager);
_popupSystem.PopupEntity(
Loc.GetString("drink-component-force-feed-success", ("user", userName)), uid, Filter.Entities(uid));
Loc.GetString("drink-component-force-feed-success", ("user", userName), ("flavors", flavors)), uid, Filter.Entities(uid));
_popupSystem.PopupEntity(
Loc.GetString("drink-component-force-feed-success-user", ("target", targetName)),
@@ -350,7 +353,10 @@ namespace Content.Server.Nutrition.EntitySystems
else
{
_popupSystem.PopupEntity(
Loc.GetString("drink-component-try-use-drink-success-slurp"), args.User, Filter.Pvs(args.User));
Loc.GetString("drink-component-try-use-drink-success-slurp-taste", ("flavors", flavors)), args.User,
Filter.Entities(args.User));
_popupSystem.PopupEntity(
Loc.GetString("drink-component-try-use-drink-success-slurp"), args.User, Filter.PvsExcept(args.User));
}
SoundSystem.Play(args.Drink.UseSound.GetSound(), Filter.Pvs(uid), uid, AudioParams.Default.WithVolume(-2f));

View File

@@ -0,0 +1,118 @@
using System.Linq;
using System.Text;
using Content.Server.Nutrition.Components;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Microsoft.VisualBasic;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Server.Nutrition.EntitySystems;
/// <summary>
/// Deals with flavor profiles when you eat something.
/// </summary>
public sealed class FlavorProfileSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
private const string BackupFlavorMessage = "flavor-profile-unknown";
private int FlavorLimit => _configManager.GetCVar(CCVars.FlavorLimit);
public string GetLocalizedFlavorsMessage(EntityUid uid, EntityUid user, Solution solution,
FlavorProfileComponent? flavorProfile = null)
{
var flavors = new HashSet<string>();
if (!Resolve(uid, ref flavorProfile))
{
return Loc.GetString(BackupFlavorMessage);
}
flavors.UnionWith(flavorProfile.Flavors);
flavors.UnionWith(GetFlavorsFromReagents(solution, FlavorLimit - flavors.Count, flavorProfile.IgnoreReagents));
var ev = new FlavorProfileModificationEvent(user, flavors);
RaiseLocalEvent(ev);
RaiseLocalEvent(uid, ev);
RaiseLocalEvent(user, ev);
return FlavorsToFlavorMessage(flavors);
}
public string GetLocalizedFlavorsMessage(EntityUid user, Solution solution)
{
var flavors = GetFlavorsFromReagents(solution, FlavorLimit);
var ev = new FlavorProfileModificationEvent(user, flavors);
RaiseLocalEvent(user, ev, true);
return FlavorsToFlavorMessage(flavors);
}
private string FlavorsToFlavorMessage(HashSet<string> flavorSet)
{
var flavors = new List<FlavorPrototype>();
foreach (var flavor in flavorSet)
{
if (string.IsNullOrEmpty(flavor) || !_prototypeManager.TryIndex<FlavorPrototype>(flavor, out var flavorPrototype))
{
continue;
}
flavors.Add(flavorPrototype);
}
flavors.Sort((a, b) => a.FlavorType.CompareTo(b.FlavorType));
if (flavors.Count == 1 && !string.IsNullOrEmpty(flavors[0].FlavorDescription))
{
return Loc.GetString("flavor-profile", ("flavor", Loc.GetString(flavors[0].FlavorDescription)));
}
if (flavors.Count > 1)
{
var lastFlavor = Loc.GetString(flavors[^1].FlavorDescription);
var allFlavors = string.Join(", ", flavors.GetRange(0, flavors.Count - 1).Select(i => Loc.GetString(i.FlavorDescription)));
return Loc.GetString("flavor-profile-multiple", ("flavors", allFlavors), ("lastFlavor", lastFlavor));
}
return Loc.GetString(BackupFlavorMessage);
}
private HashSet<string> GetFlavorsFromReagents(Solution solution, int desiredAmount, HashSet<string>? toIgnore = null)
{
var flavors = new HashSet<string>();
foreach (var reagent in solution.Contents)
{
if (toIgnore != null && toIgnore.Contains(reagent.ReagentId))
{
continue;
}
if (flavors.Count == desiredAmount)
{
break;
}
var flavor = _prototypeManager.Index<ReagentPrototype>(reagent.ReagentId).Flavor;
flavors.Add(flavor);
}
return flavors;
}
}
public sealed class FlavorProfileModificationEvent : EntityEventArgs
{
public FlavorProfileModificationEvent(EntityUid user, HashSet<string> flavors)
{
User = user;
Flavors = flavors;
}
public EntityUid User { get; }
public HashSet<string> Flavors { get; }
}

View File

@@ -30,6 +30,7 @@ namespace Content.Server.Nutrition.EntitySystems
public sealed class FoodSystem : EntitySystem
{
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly FlavorProfileSystem _flavorProfileSystem = default!;
[Dependency] private readonly BodySystem _bodySystem = default!;
[Dependency] private readonly StomachSystem _stomachSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
@@ -157,6 +158,8 @@ namespace Content.Server.Nutrition.EntitySystems
: args.FoodSolution.CurrentVolume;
var split = _solutionContainerSystem.SplitSolution((args.Food).Owner, args.FoodSolution, transferAmount);
var firstStomach = stomachs.FirstOrNull(
stomach => _stomachSystem.CanTransferSolution((stomach.Comp).Owner, split));
@@ -177,11 +180,13 @@ namespace Content.Server.Nutrition.EntitySystems
split.DoEntityReaction(uid, ReactionMethod.Ingestion);
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.Owner, split, firstStomach.Value.Comp);
var flavors = _flavorProfileSystem.GetLocalizedFlavorsMessage(args.Food.Owner, args.User, split);
if (forceFeed)
{
var targetName = Identity.Entity(uid, EntityManager);
var userName = Identity.Entity(args.User, EntityManager);
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName)),
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName), ("flavors", flavors)),
uid, Filter.Entities(uid));
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed-success-user", ("target", targetName)),
@@ -189,7 +194,7 @@ namespace Content.Server.Nutrition.EntitySystems
}
else
{
_popupSystem.PopupEntity(Loc.GetString(args.Food.EatMessage, ("food", args.Food.Owner)), args.User, Filter.Entities(args.User));
_popupSystem.PopupEntity(Loc.GetString(args.Food.EatMessage, ("food", args.Food.Owner), ("flavors", flavors)), args.User, Filter.Entities(args.User));
}
SoundSystem.Play(args.Food.UseSound.GetSound(), Filter.Pvs(uid), uid, AudioParams.Default.WithVolume(-1f));