From dc8d36b4deeda322a78813a95d1c65c2f54be901 Mon Sep 17 00:00:00 2001 From: David Masad Date: Wed, 27 Jan 2021 15:30:48 -0500 Subject: [PATCH] First commit --- .gitignore | 1 + Readme.md | 16 +++ examples/ball_game.html | 312 ++++++++++++++++++++++++++++++++++++++++ examples/ball_game.js | 82 +++++++++++ examples/ball_game.tw | 115 +++++++++++++++ storymanager.js | 43 ++++++ 6 files changed, 569 insertions(+) create mode 100644 .gitignore create mode 100644 Readme.md create mode 100644 examples/ball_game.html create mode 100644 examples/ball_game.js create mode 100644 examples/ball_game.tw create mode 100644 storymanager.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..600d2d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..008530d --- /dev/null +++ b/Readme.md @@ -0,0 +1,16 @@ +# Story Manager + +A lightweight storylet manager for Twee and Sugarcube. + + +## Feature list + +- [X] Generating potential storylets based on state +- [X] Filtering to N storylets based on priority +- [ ] Allowing some storylets to interrupt and take priority +- [ ] Track storylet history (e.g. to prevent repetition) + - [ ] Storylets bound to specific data + - [ ] Storylet with any binding +- [ ] Storylet tagging and filtering (i.e. pull from only a subset of storylets) +- [ ] Macro / widget for displaying storylet links +- [ ] \ No newline at end of file diff --git a/examples/ball_game.html b/examples/ball_game.html new file mode 100644 index 0000000..a7c3279 --- /dev/null +++ b/examples/ball_game.html @@ -0,0 +1,312 @@ + + + + +Pansexual Space Regency Party (working title) + + + + + + + + + + + + + + + + +
+
+
Your browser lacks required capabilities. Please upgrade it or switch to another to continue.
+
Loading…
+
+ + + + diff --git a/examples/ball_game.js b/examples/ball_game.js new file mode 100644 index 0000000..3078afd --- /dev/null +++ b/examples/ball_game.js @@ -0,0 +1,82 @@ + + + +// Set up narrative model +// ----------------------------------------------------------------------- + + + +// Set up NPCs +// ------------------------------------------ + +var firstNames = { + "m": ["William", "George", "Jose", "Kwame", "Vin", "Alexander", "Martin", "Daniel", + "Nicholas", "Sorin", "Vlad", "Matthew", "Octavius"], + "f": ["Alice", "Bella", "Charlotte", "Doreen", "Francesca", "Willhelmina", "Xenia", + "Juliette", "Rosemary", "Margot"] +}; + +var lastNames = ["Abar", "Bridgewater", "Clarence", "Delmar", "Ellseworth", "Fox", + "Williams", "Rose"]; + +var pronouns = { + "m": {he: "he", his: "his", him: "him"}, + "f": {he: "she", his: "hers", him: "her"} +} + +var nChars = 10; +State.variables.characters = []; +for (let id=0; id= 0) { + let storylet = { + passage: "DancingRoot", + description: "Dance with " + char.firstname + " " + char.lastname, + priority: 0, + payload: {character: char} + } + storylets.push(storylet); + } + } + return storylets; + }, + "Conversation": function() { + let storylets = []; + if (State.variables.location != "Library") return storylets; + for (let id in State.variables.characters) { + let char = State.variables.characters[id]; + if (char.friendship >= 0) { + let storylet = { + passage: "ConversationRoot", + description: "Talk with " + char.firstname + " " + char.lastname, + priority: 0, + payload: {character: char} + } + storylets.push(storylet); + } + } + return storylets; + }, +} diff --git a/examples/ball_game.tw b/examples/ball_game.tw new file mode 100644 index 0000000..eb17618 --- /dev/null +++ b/examples/ball_game.tw @@ -0,0 +1,115 @@ +:: StoryTitle +Pansexual Space Regency Party (working title) + +:: StoryData +{ + "ifid": "E9DEA250-BBFD-4C92-8E8C-53212FBB2083" +} + +:: Story JavaScript [script] +Config.passages.nobr = true; // Deal with linebreaks. + +:: Start +<> +<> +You can go to the [[Ballroom]] or the [[Library]]. + +:: Ballroom +<> +You're in the ballroom.
+<> +<> + <> + [[_story.description|_story.passage][$payload=_story.payload]]
+ <
> +<
> +Or you can go to the [[Library]] + + +:: DancingRoot +<> +You take <>'s hand and step onto the dance floor. As you dance, you can +talk about [[poetry|Conversation-Poetry-Dancing]], [[trade gossip|Conversation-Gossip]], the latest +[[current events|Conversation-Politics-Dancing]] -- or you can [[dance in silence|Dance-Quietly]].
+ + +:: Conversation-Poetry-Dancing +< $partner.poetry>> +(Poetry success) +<> +(Poetry fail) +<> +(Poetry up) +<> +<> +<> +
+[[Return | Ballroom]] + +:: Conversation-Politics-Dancing +(This is inappropriate to do while dancing) +<> +[[Return | Ballroom]] + +:: Dance-Quietly +(Dance quietly, some chance of improving romance goes here) +[[Return | Ballroom]] + +:: Conversation-Gossip +< $partner.gossip>> +"I heard-" you begin archy, and are able to share some juicy gossip you heard earlier, earning a smile. +<> +You bring up a rumor you read earlier, but you can see it's old news already. +<> +Fortunately, they reply with a rumor of their own -- one you haven't heard yet. +<> +<> +<> +
+<> +[[Return | Ballroom]] +<> +[[Return | Library]] +<> + +:: Library +<> +You're in the library.
+<> +<> + <> + [[_story.description|_story.passage][$payload=_story.payload]]
+ <
> +<
> +Or you can go to the [[Ballroom]] + +:: ConversationRoot +<> +You talk to $partner.firstname in the library. You can talk about [[poetry|Conversation-Poetry-Talking]], [[trade gossip|Conversation-Gossip]], or the latest +[[current events|Conversation-Politics-Talking]].
+ + +:: Conversation-Poetry-Talking +< $partner.poetry>> +(Poetry success) +<> +(Poetry fail) +<> +(Poetry up) +<> +<> +<> +
+[[Return | Library]] + + +:: Conversation-Politics-Talking +<> +<> +(Politics conversation success) +<> +<> +(Politics conversation failure) +<> +[[Return | Library]] + diff --git a/storymanager.js b/storymanager.js new file mode 100644 index 0000000..4bd698a --- /dev/null +++ b/storymanager.js @@ -0,0 +1,43 @@ + +// Choose one of an array +var randomChoice = function(vals) { + return vals[Math.floor(Math.random() * vals.length)]; +}; + +// Set up the general narrative manager +// ----------------------------------------------------------------------- +var NarrativeManager = {meta: []}; +NarrativeManager.getAllStorylets = function() { + let allStorylets = []; + for (let key in this.storyletMakers) { + let storylets = this.storyletMakers[key](); + for (let i in storylets) allStorylets.push(storylets[i]); + } + return allStorylets; +} + +NarrativeManager.getNStorylets = function(n) { + /* + Get N storylets, prioritizing the highest-priority ones first. + For now assume that priorities are integers, but it would be nice + to be more flexible. + + */ + let allStorylets = this.getAllStorylets(); + n = Math.min(n, allStorylets.length); + if (n == 0) return []; + let selectedStorylets = []; + // First sort by ascending priority: + allStorylets.sort((a, b) => b.priority - a.priority); + let currentPriority = allStorylets[0].priority; + while (selectedStorylets.length < n) { + let priorityStorylets = allStorylets.filter(s => s.priority==currentPriority); + priorityStorylets.sort((a, b) => (Math.random() - Math.random())); + let nAdd = Math.min(n - selectedStorylets.length, priorityStorylets.length); + for (let i=0; i