]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Random book story generator refactor (#28082)
authorTayrtahn <tayrtahn@gmail.com>
Sat, 18 May 2024 16:20:00 +0000 (12:20 -0400)
committerGitHub <noreply@github.com>
Sat, 18 May 2024 16:20:00 +0000 (12:20 -0400)
* Randomized book overhaul

* Fix prototype names

* Improved setting paper content

* Praise Ratvar

Content.Server/Paper/PaperRandomStoryComponent.cs
Content.Server/Paper/PaperRandomStorySystem.cs
Content.Shared/StoryGen/EntitySystems/StoryGeneratorSystem.cs [new file with mode: 0644]
Content.Shared/StoryGen/Prototypes/StoryTemplatePrototype.cs [new file with mode: 0644]
Resources/Locale/en-US/paper/story-generation.ftl
Resources/Locale/en-US/storygen/story-template.ftl [new file with mode: 0644]
Resources/Prototypes/Datasets/story_generation.yml
Resources/Prototypes/Entities/Objects/Misc/books.yml
Resources/Prototypes/StoryGen/story-templates.yml [new file with mode: 0644]

index 7c5744f0878ff8f337d3da26a932eb0d2e48ceb6..b8e07f0ee819d6b6fbe55405e9ed19662a7500a7 100644 (file)
@@ -1,14 +1,17 @@
+using Content.Shared.StoryGen;
+using Robust.Shared.Prototypes;
+
 namespace Content.Server.Paper;
 
 /// <summary>
-///    Adds randomly generated stories to Paper component
+///    Adds a randomly generated story to the content of a <see cref="PaperComponent"/>
 /// </summary>
 [RegisterComponent, Access(typeof(PaperRandomStorySystem))]
 public sealed partial class PaperRandomStoryComponent : Component
 {
+    /// <summary>
+    /// The <see cref="StoryTemplatePrototype"/> ID to use for story generation.
+    /// </summary>
     [DataField]
-    public List<string>? StorySegments;
-
-    [DataField]
-    public string StorySeparator = " ";
+    public ProtoId<StoryTemplatePrototype> Template;
 }
index e7712009c2ee7fcbc3358fe8058a0dc27bee971e..156718f54500fefb06fb98f4568a6f47be20c225 100644 (file)
@@ -1,11 +1,11 @@
-using Content.Server.RandomMetadata;
+using Content.Shared.StoryGen;
 
 namespace Content.Server.Paper;
 
 public sealed class PaperRandomStorySystem : EntitySystem
 {
-
-    [Dependency] private readonly RandomMetadataSystem _randomMeta = default!;
+    [Dependency] private readonly StoryGeneratorSystem _storyGen = default!;
+    [Dependency] private readonly PaperSystem _paper = default!;
 
     public override void Initialize()
     {
@@ -19,11 +19,9 @@ public sealed class PaperRandomStorySystem : EntitySystem
         if (!TryComp<PaperComponent>(paperStory, out var paper))
             return;
 
-        if (paperStory.Comp.StorySegments == null)
+        if (!_storyGen.TryGenerateStoryFromTemplate(paperStory.Comp.Template, out var story))
             return;
 
-        var story = _randomMeta.GetRandomFromSegments(paperStory.Comp.StorySegments, paperStory.Comp.StorySeparator);
-
-        paper.Content += $"\n{story}";
+        _paper.SetContent(paperStory.Owner, story, paper);
     }
 }
diff --git a/Content.Shared/StoryGen/EntitySystems/StoryGeneratorSystem.cs b/Content.Shared/StoryGen/EntitySystems/StoryGeneratorSystem.cs
new file mode 100644 (file)
index 0000000..51ad857
--- /dev/null
@@ -0,0 +1,54 @@
+using System.Diagnostics.CodeAnalysis;
+using Robust.Shared.Collections;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Shared.StoryGen;
+
+/// <summary>
+/// Provides functionality to generate a story from a <see cref="StoryTemplatePrototype"/>.
+/// </summary>
+public sealed partial class StoryGeneratorSystem : EntitySystem
+{
+    [Dependency] private readonly IPrototypeManager _protoMan = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+
+    /// <summary>
+    /// Tries to generate a random story using the given template, picking a random word from the referenced
+    /// datasets for each variable and passing them into the localization system with template.
+    /// If <paramref name="seed"/> is specified, the randomizer will be seeded with it for consistent story generation;
+    /// otherwise the variables will be randomized.
+    /// Fails if the template prototype cannot be loaded.
+    /// </summary>
+    /// <returns>true if the template was loaded, otherwise false.</returns>
+    public bool TryGenerateStoryFromTemplate(ProtoId<StoryTemplatePrototype> template, [NotNullWhen(true)] out string? story, int? seed = null)
+    {
+        // Get the story template prototype from the ID
+        if (!_protoMan.TryIndex(template, out var templateProto))
+        {
+            story = null;
+            return false;
+        }
+
+        // If given a seed, use it
+        if (seed != null)
+            _random.SetSeed(seed.Value);
+
+        // Pick values for all of the variables in the template
+        var variables = new ValueList<(string, object)>(templateProto.Variables.Count);
+        foreach (var (name, list) in templateProto.Variables)
+        {
+            // Get the prototype for the world list dataset
+            if (!_protoMan.TryIndex(list, out var listProto))
+                continue; // Missed one, but keep going with the rest of the story
+
+            // Pick a random word from the dataset and localize it
+            var chosenWord = Loc.GetString(_random.Pick(listProto.Values));
+            variables.Add((name, chosenWord));
+        }
+
+        // Pass the variables to the localization system and build the story
+        story = Loc.GetString(templateProto.LocId, variables.ToArray());
+        return true;
+    }
+}
diff --git a/Content.Shared/StoryGen/Prototypes/StoryTemplatePrototype.cs b/Content.Shared/StoryGen/Prototypes/StoryTemplatePrototype.cs
new file mode 100644 (file)
index 0000000..7f6afac
--- /dev/null
@@ -0,0 +1,33 @@
+using Content.Shared.Dataset;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.StoryGen;
+
+/// <summary>
+/// Prototype for a story template that can be filled in with words chosen from <see cref="DatasetPrototype"/>s.
+/// </summary>
+[Serializable, Prototype("storyTemplate")]
+public sealed partial class StoryTemplatePrototype : IPrototype
+{
+    /// <summary>
+    /// Identifier for this prototype instance.
+    /// </summary>
+    [ViewVariables]
+    [IdDataField]
+    public string ID { get; private set; } = default!;
+
+    /// <summary>
+    /// Localization ID of the Fluent string that forms the structure of this story.
+    /// </summary>
+    [DataField(required: true)]
+    public LocId LocId { get; } = default!;
+
+    /// <summary>
+    /// Dictionary containing the name of each variable to pass to the template and the ID of the
+    /// <see cref="DatasetPrototype"/> from which a random entry will be selected as its value.
+    /// For example, <c>name: book_character</c> will pick a random entry from the book_character
+    /// dataset which can then be used in the template by <c>{$name}</c>.
+    /// </summary>
+    [DataField]
+    public Dictionary<string, ProtoId<DatasetPrototype>> Variables { get; } = default!;
+}
index bcd1c8901e0b8eb408184339d7d4d733edddc6a9..94ecbc3caa5787ef82dd17b3d6c6be38f8165f84 100644 (file)
@@ -86,7 +86,7 @@ story-gen-book-character29 = space dragon
 story-gen-book-character30 = revolutionary
 story-gen-book-character31 = nuclear operative
 story-gen-book-character32 = narsie cultist
-story-gen-book-character33 = ratwar cultist
+story-gen-book-character33 = ratvar cultist
 story-gen-book-character34 = greytider
 story-gen-book-character35 = arachnid
 story-gen-book-character36 = vox
@@ -98,7 +98,7 @@ story-gen-book-character40 = slime
 story-gen-book-character-trait1 = stupid
 story-gen-book-character-trait2 = smart
 story-gen-book-character-trait3 = funny
-story-gen-book-character-trait4 = attractive  
+story-gen-book-character-trait4 = attractive
 story-gen-book-character-trait5 = charming
 story-gen-book-character-trait6 = nasty
 story-gen-book-character-trait7 = dying
@@ -113,7 +113,7 @@ story-gen-book-character-trait15 = сharismatic
 story-gen-book-character-trait16 = stoic
 story-gen-book-character-trait17 = cute
 story-gen-book-character-trait18 = dwarven
-story-gen-book-character-trait19 = beer-smelling 
+story-gen-book-character-trait19 = beer-smelling
 story-gen-book-character-trait20 = joyful
 story-gen-book-character-trait21 = painfully beautiful
 story-gen-book-character-trait22 = robotic
@@ -121,20 +121,20 @@ story-gen-book-character-trait23 = holographic
 story-gen-book-character-trait24 = hysterically laughing
 
 story-gen-book-event1 = a zombie outbreak
-story-gen-book-event2 = a nuclear  explosion
+story-gen-book-event2 = a nuclear explosion
 story-gen-book-event3 = a mass murder
 story-gen-book-event4 = a sudden depressurization
 story-gen-book-event5 = a blackout
-story-gen-book-event6 = the starvation of the protagonists
+story-gen-book-event6 = the protagonists nearly starving
 story-gen-book-event7 = a wasting illness
 story-gen-book-event8 = love at first sight
 story-gen-book-event9 = a rush of inspiration
-story-gen-book-event10 = the occurrence of some mystical phenomena
+story-gen-book-event10 = some mystical phenomena
 story-gen-book-event11 = divine intervention
 story-gen-book-event12 = the characters' own selfish motives
 story-gen-book-event13 = an unforeseen deception
-story-gen-book-event14 = the resurrection of one of these characters from the dead
-story-gen-book-event15 = the terrible torture of the protagonist
+story-gen-book-event14 = the resurrection of one of the characters from the dead
+story-gen-book-event15 = the brutal torture of the protagonists
 story-gen-book-event16 = the inadvertent loosing of a gravitational singularity
 story-gen-book-event17 = a psychic prediction of future events
 story-gen-book-event18 = an antimatter explosion
@@ -145,31 +145,31 @@ story-gen-book-event22 = having a quarrel with a close friend
 story-gen-book-event23 = the sudden loss of their home in a fiery blaze
 story-gen-book-event24 = the loss of a PDA
 
-story-gen-book-action1 = share in a kiss with a
-story-gen-book-action2 = strangle to death a
-story-gen-book-action3 = manage to blow apart a
-story-gen-book-action4 = manage to win a game of chess against a
-story-gen-book-action5 = narrowly lose a game of chess against a
-story-gen-book-action6 = reveal the hidden secrets of a
-story-gen-book-action7 = manipulate a
-story-gen-book-action8 = sacrifice upon an altar a
-story-gen-book-action9 = attend the wedding of a
-story-gen-book-action10 = join forces to defeat their common enemy, a
-story-gen-book-action11 = are forced to work together to escape a
+story-gen-book-action1 = share in a kiss with
+story-gen-book-action2 = strangle
+story-gen-book-action3 = blow apart
+story-gen-book-action4 = win a game of chess against
+story-gen-book-action5 = lose a game of chess against
+story-gen-book-action6 = reveal the hidden secrets of
+story-gen-book-action7 = manipulate
+story-gen-book-action8 = sacrifice a hamster to
+story-gen-book-action9 = infiltrate the wedding of
+story-gen-book-action10 = join forces to defeat their common enemy,
+story-gen-book-action11 = are forced to work together to escape
 story-gen-book-action12 = give a valuable gift to
 
-story-gen-book-action-trait1 = terribly 
-story-gen-book-action-trait2 = disgustingly 
+story-gen-book-action-trait1 = clumsily
+story-gen-book-action-trait2 = disgustingly
 story-gen-book-action-trait3 = marvelously
 story-gen-book-action-trait4 = nicely
 story-gen-book-action-trait5 = weirdly
 story-gen-book-action-trait6 = amusingly
 story-gen-book-action-trait7 = fancifully
 story-gen-book-action-trait8 = impressively
-story-gen-book-action-trait9 = irresponsibly 
-story-gen-book-action-trait10 = severely 
-story-gen-book-action-trait11 = ruthlessly 
-story-gen-book-action-trait12 = playfully 
+story-gen-book-action-trait9 = irresponsibly
+story-gen-book-action-trait10 = severely
+story-gen-book-action-trait11 = ruthlessly
+story-gen-book-action-trait12 = playfully
 story-gen-book-action-trait13 = thoughtfully
 
 story-gen-book-location1 = in an underground complex
@@ -178,7 +178,7 @@ story-gen-book-location3 = while trapped in outer space
 story-gen-book-location4 = while in a news office
 story-gen-book-location5 = in a hidden garden
 story-gen-book-location6 = in the kitchen of a local restaurant
-story-gen-book-location7 = under the counter of the local sports bar 
+story-gen-book-location7 = under the counter of the local sports bar
 story-gen-book-location8 = in an ancient library
 story-gen-book-location9 = while deep in bowels of the space station's maintenance corridors
 story-gen-book-location10 = on the bridge of a starship
@@ -192,7 +192,7 @@ story-gen-book-location17 = standing too close to an anomaly
 story-gen-book-location18 = while huddling on the evacuation shuttle
 story-gen-book-location19 = standing in freshly fallen snow
 story-gen-book-location20 = lost in the woods
-story-gen-book-location21 = iin the harsh desert
+story-gen-book-location21 = in the harsh desert
 story-gen-book-location22 = worrying about their social media networks
 story-gen-book-location23 = atop of a mountain
 story-gen-book-location24 = while driving a car
@@ -207,15 +207,15 @@ story-gen-book-location32 = while trapped in a shadow dimension
 story-gen-book-location33 = while trying to escape a destroyed space station
 story-gen-book-location34 = while sandwiched between a Tesla ball and a gravitational singularity
 
-story-gen-book-element1 = The plot
-story-gen-book-element2 = The twist
-story-gen-book-element3 = The climax
-story-gen-book-element4 = The final act
-story-gen-book-element5 = The ending
-story-gen-book-element6 = The moral of the story
-story-gen-book-element7 = The theme of this work
-story-gen-book-element8 = The literary style
-story-gen-book-element9 = The illustrations
+story-gen-book-element1 = plot
+story-gen-book-element2 = twist
+story-gen-book-element3 = climax
+story-gen-book-element4 = final act
+story-gen-book-element5 = ending
+story-gen-book-element6 = moral of the story
+story-gen-book-element7 = theme of this work
+story-gen-book-element8 = literary style
+story-gen-book-element9 = artwork
 
 story-gen-book-element-trait1 = terrifying
 story-gen-book-element-trait2 = disgusting
diff --git a/Resources/Locale/en-US/storygen/story-template.ftl b/Resources/Locale/en-US/storygen/story-template.ftl
new file mode 100644 (file)
index 0000000..b535e2f
--- /dev/null
@@ -0,0 +1,4 @@
+story-template-generic =
+ This is { INDEFINITE($bookGenre) } {$bookGenre} about { INDEFINITE($char1Adj) } {$char1Adj} {$char1Type} and { INDEFINITE($char2Adj) } {$char2Adj} {$char2Type}. Due to {$event}, they {$actionTrait} {$action} { INDEFINITE($char3Type) } {$char3Type} {$location}.
+
+ The {$element} is {$elementTrait}.
index 1083a6acdb661f4a39133d7446c128900eef5851..1a461c7596dd067edf0ce62dbd32541389c60eca 100644 (file)
@@ -1,31 +1,31 @@
 - type: dataset
-  id: book_type
+  id: BookTypes
   values:
-  - story-gen-book-type1 
-  - story-gen-book-type2 
-  - story-gen-book-type3 
-  - story-gen-book-type4 
-  - story-gen-book-type5 
-  - story-gen-book-type6 
-  - story-gen-book-type7 
-  - story-gen-book-type8 
-  - story-gen-book-type9 
+  - story-gen-book-type1
+  - story-gen-book-type2
+  - story-gen-book-type3
+  - story-gen-book-type4
+  - story-gen-book-type5
+  - story-gen-book-type6
+  - story-gen-book-type7
+  - story-gen-book-type8
+  - story-gen-book-type9
   - story-gen-book-type10
   - story-gen-book-type11
   - story-gen-book-type12
 
 - type: dataset
-  id: book_genre
+  id: BookGenres
   values:
-  - story-gen-book-genre1 
-  - story-gen-book-genre2 
-  - story-gen-book-genre3 
-  - story-gen-book-genre4 
-  - story-gen-book-genre5 
-  - story-gen-book-genre6 
-  - story-gen-book-genre7 
-  - story-gen-book-genre8 
-  - story-gen-book-genre9 
+  - story-gen-book-genre1
+  - story-gen-book-genre2
+  - story-gen-book-genre3
+  - story-gen-book-genre4
+  - story-gen-book-genre5
+  - story-gen-book-genre6
+  - story-gen-book-genre7
+  - story-gen-book-genre8
+  - story-gen-book-genre9
   - story-gen-book-genre10
   - story-gen-book-genre11
   - story-gen-book-genre12
   - story-gen-book-genre14
 
 - type: dataset
-  id: book_hint_appearance
+  id: BookHintAppearances
   values:
-  - story-gen-book-appearance1 
-  - story-gen-book-appearance2 
-  - story-gen-book-appearance3 
-  - story-gen-book-appearance4 
-  - story-gen-book-appearance5 
-  - story-gen-book-appearance6 
-  - story-gen-book-appearance7 
-  - story-gen-book-appearance8 
-  - story-gen-book-appearance9 
+  - story-gen-book-appearance1
+  - story-gen-book-appearance2
+  - story-gen-book-appearance3
+  - story-gen-book-appearance4
+  - story-gen-book-appearance5
+  - story-gen-book-appearance6
+  - story-gen-book-appearance7
+  - story-gen-book-appearance8
+  - story-gen-book-appearance9
   - story-gen-book-appearance10
   - story-gen-book-appearance11
   - story-gen-book-appearance12
   - story-gen-book-appearance27
 
 - type: dataset
-  id: book_character
+  id: BookCharacters
   values:
-  - story-gen-book-character1 
-  - story-gen-book-character2 
-  - story-gen-book-character3 
-  - story-gen-book-character4 
-  - story-gen-book-character5 
-  - story-gen-book-character6 
-  - story-gen-book-character7 
-  - story-gen-book-character8 
-  - story-gen-book-character9 
+  - story-gen-book-character1
+  - story-gen-book-character2
+  - story-gen-book-character3
+  - story-gen-book-character4
+  - story-gen-book-character5
+  - story-gen-book-character6
+  - story-gen-book-character7
+  - story-gen-book-character8
+  - story-gen-book-character9
   - story-gen-book-character10
   - story-gen-book-character11
   - story-gen-book-character12
   - story-gen-book-character40
 
 - type: dataset
-  id: book_character_trait
+  id: BookCharacterTraits
   values:
-  - story-gen-book-character-trait1 
-  - story-gen-book-character-trait2 
-  - story-gen-book-character-trait3 
-  - story-gen-book-character-trait4 
-  - story-gen-book-character-trait5 
-  - story-gen-book-character-trait6 
-  - story-gen-book-character-trait7 
-  - story-gen-book-character-trait8 
-  - story-gen-book-character-trait9 
+  - story-gen-book-character-trait1
+  - story-gen-book-character-trait2
+  - story-gen-book-character-trait3
+  - story-gen-book-character-trait4
+  - story-gen-book-character-trait5
+  - story-gen-book-character-trait6
+  - story-gen-book-character-trait7
+  - story-gen-book-character-trait8
+  - story-gen-book-character-trait9
   - story-gen-book-character-trait10
   - story-gen-book-character-trait11
   - story-gen-book-character-trait12
 
 
 - type: dataset
-  id: book_event
+  id: BookEvents
   values:
-  - story-gen-book-event1 
-  - story-gen-book-event2 
-  - story-gen-book-event3 
-  - story-gen-book-event4 
-  - story-gen-book-event5 
-  - story-gen-book-event6 
-  - story-gen-book-event7 
-  - story-gen-book-event8 
-  - story-gen-book-event9 
+  - story-gen-book-event1
+  - story-gen-book-event2
+  - story-gen-book-event3
+  - story-gen-book-event4
+  - story-gen-book-event5
+  - story-gen-book-event6
+  - story-gen-book-event7
+  - story-gen-book-event8
+  - story-gen-book-event9
   - story-gen-book-event10
   - story-gen-book-event11
   - story-gen-book-event12
   - story-gen-book-event24
 
 - type: dataset
-  id: book_action
+  id: BookActions
   values:
-  - story-gen-book-action1 
-  - story-gen-book-action2 
-  - story-gen-book-action3 
-  - story-gen-book-action4 
-  - story-gen-book-action5 
-  - story-gen-book-action6 
-  - story-gen-book-action7 
-  - story-gen-book-action8 
-  - story-gen-book-action9 
+  - story-gen-book-action1
+  - story-gen-book-action2
+  - story-gen-book-action3
+  - story-gen-book-action4
+  - story-gen-book-action5
+  - story-gen-book-action6
+  - story-gen-book-action7
+  - story-gen-book-action8
+  - story-gen-book-action9
   - story-gen-book-action10
   - story-gen-book-action11
   - story-gen-book-action12
 
 - type: dataset
-  id: book_action_trait
+  id: BookActionTraits
   values:
-  - story-gen-book-action-trait1 
-  - story-gen-book-action-trait2 
-  - story-gen-book-action-trait3 
-  - story-gen-book-action-trait4 
-  - story-gen-book-action-trait5 
-  - story-gen-book-action-trait6 
-  - story-gen-book-action-trait7 
-  - story-gen-book-action-trait8 
-  - story-gen-book-action-trait9 
+  - story-gen-book-action-trait1
+  - story-gen-book-action-trait2
+  - story-gen-book-action-trait3
+  - story-gen-book-action-trait4
+  - story-gen-book-action-trait5
+  - story-gen-book-action-trait6
+  - story-gen-book-action-trait7
+  - story-gen-book-action-trait8
+  - story-gen-book-action-trait9
   - story-gen-book-action-trait10
   - story-gen-book-action-trait11
   - story-gen-book-action-trait12
   - story-gen-book-action-trait13
 
 - type: dataset
-  id: book_location
+  id: BookLocations
   values:
-  - story-gen-book-location1 
-  - story-gen-book-location2 
-  - story-gen-book-location3 
-  - story-gen-book-location4 
-  - story-gen-book-location5 
-  - story-gen-book-location6 
-  - story-gen-book-location7 
-  - story-gen-book-location8 
-  - story-gen-book-location9 
+  - story-gen-book-location1
+  - story-gen-book-location2
+  - story-gen-book-location3
+  - story-gen-book-location4
+  - story-gen-book-location5
+  - story-gen-book-location6
+  - story-gen-book-location7
+  - story-gen-book-location8
+  - story-gen-book-location9
   - story-gen-book-location10
   - story-gen-book-location11
   - story-gen-book-location12
   - story-gen-book-location34
 
 - type: dataset
-  id: book_story_element
+  id: BookStoryElements
   values:
   - story-gen-book-element1
   - story-gen-book-element2
   - story-gen-book-element9
 
 - type: dataset
-  id: book_story_element_trait
+  id: BookStoryElementTraits
   values:
-  - story-gen-book-element-trait1 
-  - story-gen-book-element-trait2 
-  - story-gen-book-element-trait3 
-  - story-gen-book-element-trait4 
-  - story-gen-book-element-trait5 
-  - story-gen-book-element-trait6 
-  - story-gen-book-element-trait7 
-  - story-gen-book-element-trait8 
-  - story-gen-book-element-trait9 
+  - story-gen-book-element-trait1
+  - story-gen-book-element-trait2
+  - story-gen-book-element-trait3
+  - story-gen-book-element-trait4
+  - story-gen-book-element-trait5
+  - story-gen-book-element-trait6
+  - story-gen-book-element-trait7
+  - story-gen-book-element-trait8
+  - story-gen-book-element-trait9
   - story-gen-book-element-trait10
   - story-gen-book-element-trait11
   - story-gen-book-element-trait12
-  - story-gen-book-element-trait13
\ No newline at end of file
+  - story-gen-book-element-trait13
index 25e6bb9f943f2f4a2f3d984a46beb440c82313c0..3fc90048dd525e30c78e1d9407d20ee7bbc81962 100644 (file)
   components:
   - type: RandomMetadata
     nameSegments:
-    - book_hint_appearance
-    - book_type
+    - BookHintAppearances
+    - BookTypes
   - type: RandomSprite
     available:
       - cover:
   suffix: random visual, random story
   components:
   - type: PaperRandomStory
-    storySegments:
-    - "This is a "
-    - book_genre
-    - " about a "
-    - book_character_trait
-    - " "
-    - book_character
-    - " and "
-    - book_character_trait
-    - " "
-    - book_character
-    - ". Due to "
-    - book_event
-    - ", they "
-    - book_action_trait
-    - " "
-    - book_action
-    - " "
-    - book_character
-    - " "
-    - book_location
-    - ". \n\n"
-    - book_story_element
-    - " is "
-    - book_story_element_trait
-    - "."
-    storySeparator: ""
+    template: GenericStory
 
 - type: entity
   parent: BookBase
diff --git a/Resources/Prototypes/StoryGen/story-templates.yml b/Resources/Prototypes/StoryGen/story-templates.yml
new file mode 100644 (file)
index 0000000..f05fd5a
--- /dev/null
@@ -0,0 +1,16 @@
+- type: storyTemplate
+  id: GenericStory
+  locId: story-template-generic
+  variables:
+    bookGenre: BookGenres
+    char1Type: BookCharacters
+    char1Adj: BookCharacterTraits
+    char2Type: BookCharacters
+    char2Adj: BookCharacterTraits
+    event: BookEvents
+    action: BookActions
+    actionTrait: BookActionTraits
+    char3Type: BookCharacters
+    location: BookLocations
+    element: BookStoryElements
+    elementTrait: BookStoryElementTraits