├── .gitignore ├── Gruntfile.js ├── LICENSE.md ├── README.md ├── build-authoring-tool.js ├── build-library.js ├── docs └── toolscreenshot.png ├── ensemble ├── ActionLibrary.js ├── RuleLibrary.js ├── Validate.js ├── Volition.js ├── ensemble.js ├── jslib │ ├── underscore-min.js │ ├── underscore-min.map │ ├── underscore.js │ └── util.js └── socialRecord.js ├── ensembletool ├── README.md ├── csslib │ ├── images │ │ ├── animated-overlay.gif │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ ├── ui-bg_flat_10_000000_40x100.png │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_228ef1_256x240.png │ │ ├── ui-icons_2e83ff_256x240.png │ │ ├── ui-icons_454545_256x240.png │ │ ├── ui-icons_888888_256x240.png │ │ ├── ui-icons_cd0a0a_256x240.png │ │ ├── ui-icons_ef8c08_256x240.png │ │ ├── ui-icons_ffd27a_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── jquery-ui.structure.min.css │ └── jquery-ui.theme.min.css ├── defaultdata │ ├── actions.json │ ├── cast.json │ ├── history.json │ ├── schema.json │ ├── triggerRules.json │ └── volitionRules.json ├── ensembleconsole.css ├── index.html ├── js │ ├── actionEditor.js │ ├── consoleViewer.js │ ├── ensembleconsole.js │ ├── fileio.js │ ├── historyViewer.js │ ├── messages.js │ ├── ruleTester.js │ ├── rulesEditor.js │ ├── rulesViewer.js │ └── schemaviewer.js ├── jslib │ ├── ensemble.js │ ├── jquery-2.1.0.js │ ├── jquery-ui.min.js │ ├── underscore-min.js │ ├── underscore-min.map │ ├── underscore.js │ └── util.js ├── main.js └── package.json ├── examples └── loversAndRivals │ ├── data │ ├── actions.json │ ├── cast.json │ ├── history.json │ ├── schema.json │ ├── triggerRules.json │ └── volitionRules.json │ ├── ensemble.js │ ├── index.html │ ├── loversAndRivals.js │ └── styles.css ├── index.html ├── jsdoc-conf.json ├── jsdoc-default.css ├── package-lock.json ├── package.json └── tests ├── data ├── rpgActions.json ├── rpgSchema.json ├── samsVolition.json ├── testActions.json ├── testActionsGrammar.json ├── testActionsGrammar10.json ├── testActionsGrammar11.json ├── testActionsGrammar12.json ├── testActionsGrammar13.json ├── testActionsGrammar14.json ├── testActionsGrammar15.json ├── testActionsGrammar16.json ├── testActionsGrammar17.json ├── testActionsGrammar2.json ├── testActionsGrammar3.json ├── testActionsGrammar4.json ├── testActionsGrammar5.json ├── testActionsGrammar6.json ├── testActionsGrammar7.json ├── testActionsGrammar8.json ├── testActionsGrammar9.json ├── testHistory.json ├── testSocial.json ├── testState.json ├── testTriggerRules.json └── testVolitionRules.json ├── externalApplicationFiles ├── actions.json ├── cast.json ├── dataLoversAndRivals │ ├── actions.json │ ├── cast.json │ ├── history.json │ ├── schema.json │ ├── triggerRules.json │ └── volitionRules.json ├── samsVolition.json ├── schema.json └── testTrigger.json ├── index.html ├── js ├── ActionLibraryUnitTests.js ├── ExternalApplicationTest.js ├── RuleLibraryUnitTests.js ├── SocialRecordUnitTests.js ├── Tests.js ├── ValidateUnitTests.js ├── VolitionUnitTests.js └── ensembleUnitTests.js ├── jslib ├── jquery-2.1.0.js ├── underscore-min.js ├── underscore-min.map └── underscore.js ├── test-styles.css └── tests-main.js /.gitignore: -------------------------------------------------------------------------------- 1 | # generic 2 | .DS_Store 3 | 4 | # used in build process 5 | build 6 | doc 7 | node_modules 8 | release 9 | 10 | # backups of domain JSON files, generated by the authoring tool 11 | examples/loversAndRivals/data/_bak_* 12 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | const config = { 5 | pkg: grunt.file.readJSON("package.json"), 6 | shell: { 7 | options: {stderr: false}, 8 | buildLibrary: {command: "node build-library.js <%=pkg.version%>"}, 9 | buildAuthoringTool: {command: "node build-authoring-tool.js <%=pkg.version%>"} 10 | }, 11 | jsdoc: { 12 | dist: { 13 | src: "ensemble/*.js", 14 | options: { 15 | destination: "doc", 16 | configure: "jsdoc-conf.json", 17 | private: false 18 | } 19 | } 20 | }, 21 | copy: { 22 | buildLibrary: { 23 | files: [ 24 | {src: "build/ensemble.js", dest: "ensembletool/jslib/ensemble.js"}, 25 | {src: "build/ensemble.js", dest: "examples/loversAndRivals/ensemble.js"} 26 | ] 27 | }, 28 | release: { 29 | files: [ 30 | {src: "build/ensemble.js", dest: "release/ensemble.js"} 31 | ] 32 | } 33 | } 34 | }; 35 | 36 | // Set up a compress:PLATFORM subtask for each authoring tool target platform 37 | const authoringToolTargetPlatforms = [ 38 | {releaseName: "linux32", internalName: "linux-ia32"}, 39 | {releaseName: "linux64", internalName: "linux-x64"}, 40 | {releaseName: "macOS", internalName: "darwin-x64"}, 41 | {releaseName: "win32", internalName: "win32-ia32"}, 42 | {releaseName: "win64", internalName: "win32-x64"} 43 | ]; 44 | config.compress = {}; 45 | for (let platform of authoringToolTargetPlatforms) { 46 | config.compress[platform.releaseName] = { 47 | options: {archive: `release/EnsembleTool-v<%=pkg.version%>-${platform.releaseName}.zip`, mode: "zip"}, 48 | files: [{expand: true, cwd: `build/Ensemble Tool-${platform.internalName}`, src: "**", dest: "."}] 49 | }; 50 | } 51 | 52 | // Load config 53 | grunt.initConfig(config); 54 | 55 | // Load plugins 56 | grunt.loadNpmTasks("grunt-contrib-compress"); 57 | grunt.loadNpmTasks("grunt-contrib-copy"); 58 | grunt.loadNpmTasks("grunt-jsdoc"); 59 | grunt.loadNpmTasks("grunt-shell"); 60 | //grunt.loadNpmTasks("grunt-contrib-uglify"); 61 | 62 | // Default task: just build the library 63 | grunt.registerTask("default", ["deploy"]); 64 | 65 | // Build ensemble.js and copy newly built file into place for consumers 66 | grunt.registerTask("deploy", ["shell:buildLibrary", "copy:buildLibrary"]); 67 | 68 | // Generate library documentation 69 | grunt.registerTask("document", ["jsdoc"]); 70 | 71 | // Rebuild the library, then build the authoring tool for all target platforms 72 | grunt.registerTask("build", ["deploy", "shell:buildAuthoringTool"]); 73 | 74 | // Rebuild the library and authoring tool, then zip the authoring tool builds 75 | // and copy all release-ready files to the release directory 76 | grunt.registerTask("release", ["build", "compress", "copy:release"]); 77 | }; 78 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD-4-Clause (University of California-Specific) 2 | 3 | Copyright (c) 2019, The Regents of the University of California. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the University of California, Santa Cruz and its contributors. 10 | 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ensemble 2 | 3 | A framework for creating socially aware characters. An evolution of the Comme il Faut AI system, which powered the game Prom Week. 4 | 5 | ## ensemble.js 6 | 7 | `ensemble.js`, available as part of the [latest release](https://github.com/ensemble-engine/ensemble/releases/latest), is a standalone JavaScript library that you can include in a web project with an HTML script tag: 8 | 9 | `` 10 | 11 | Then, in your JavaScript code, you can use the `ensemble` singleton object to call [Ensemble methods](https://github.com/ensemble-engine/ensemble/wiki/Ensemble-API). 12 | 13 | See the [wiki homepage](https://github.com/ensemble-engine/ensemble/wiki/) for tutorial links and other resources for getting started. 14 | 15 | ## Ensemble Authoring Tool 16 | 17 | It can be difficult and tedious to author Ensemble domains (schema, trigger rules, volition rules, characters, history, and actions) in pure JSON without helper functions. The Ensemble Authoring Tool is a standalone desktop app designed to help authors develop and test their domains. 18 | 19 | ![Screenshot of Ensemble authoring tool](https://raw.githubusercontent.com/ensemble-engine/ensemble/master/docs/toolscreenshot.png) 20 | 21 | The latest builds can be found on the [releases](https://github.com/ensemble-engine/ensemble/releases/latest) page. 22 | 23 | ## Contribute 24 | 25 | See the [Contributing](https://github.com/ensemble-engine/ensemble/wiki/Contributing) wiki page for information about how to contribute to the project, [how to build the library from source](https://github.com/ensemble-engine/ensemble/wiki/Developing-Ensemble-Core), [how to build the tool from source](https://github.com/ensemble-engine/ensemble/wiki/Developing-the-Authoring-Tool), etc. 26 | 27 | ## Get Help 28 | If you are having issues, please let us know by opening an [issue](https://github.com/ensemble-engine/ensemble/issues) (maybe using the “question” tag)! We'd seriously love to hear from you! 29 | 30 | ## License 31 | The project is licensed under the BSD-4-clause license. 32 | -------------------------------------------------------------------------------- /build-authoring-tool.js: -------------------------------------------------------------------------------- 1 | // replace version string in ensembletool/package.json with updated version string 2 | // (passed as first CLI argument) 3 | if (process.argv[2]) { 4 | const version = process.argv[2]; 5 | const packageFilePath = "ensembletool/package.json"; 6 | const fs = require("fs"); 7 | const oldContents = fs.readFileSync(packageFilePath, "utf8"); 8 | const newContents = oldContents.replace(/"version": "[^"]+"/, `"version": "${version}"`); 9 | fs.writeFileSync(packageFilePath, newContents); 10 | } 11 | 12 | const packager = require("electron-packager"); 13 | 14 | async function bundleElectronApp(options) { 15 | const appPaths = await packager(options); 16 | console.log(`Electron app bundles created:\n${appPaths.join("\n")}`); 17 | }; 18 | 19 | bundleElectronApp({ 20 | // options as specified in https://github.com/electron/electron-packager/blob/master/docs/api.md 21 | arch: "ia32,x64", 22 | dir: "ensembletool", 23 | platform: "darwin,win32,linux", 24 | out: "build", 25 | overwrite: true 26 | }); 27 | -------------------------------------------------------------------------------- /build-library.js: -------------------------------------------------------------------------------- 1 | // This script builds the build/ensemble.js standalone Ensemble library file. 2 | 3 | const fs = require("fs"); 4 | 5 | const buildDir = "build"; 6 | const mainBuildPath = buildDir + "/ensemble.js"; 7 | const testBuildPath = buildDir + "/ensemble-test.js"; 8 | const version = process.argv[2]; 9 | 10 | const modules = [ 11 | {name: "underscore", path: "ensemble/jslib/underscore-min.js", wrapper: "none"}, 12 | {name: "util", path: "ensemble/jslib/util.js"}, 13 | {name: "socialRecord", path: "ensemble/socialRecord.js"}, 14 | {name: "ruleLibrary", path: "ensemble/RuleLibrary.js"}, 15 | {name: "actionLibrary", path: "ensemble/ActionLibrary.js"}, 16 | {name: "volition", path: "ensemble/Volition.js"}, 17 | {name: "validate", path: "ensemble/Validate.js"}, 18 | {name: "ensemble", path: "ensemble/ensemble.js"} 19 | ]; 20 | 21 | if (!fs.existsSync(buildDir)) { 22 | console.log(`Creating directory ${buildDir}/`); 23 | fs.mkdirSync(buildDir); 24 | } 25 | 26 | for (let buildPath of [mainBuildPath, testBuildPath]) { 27 | console.log(`Building ${buildPath}...`); 28 | fs.writeFileSync(buildPath, `// *** Ensemble v${version} ***\nensemble = (function(){\n`); 29 | for (let mod of modules) { 30 | console.log(" *", mod.name, mod.path); 31 | fs.appendFile(buildPath, `// MODULE ${mod.name}\n`, () => {}); 32 | const moduleContents = fs.readFileSync(mod.path).toString(); 33 | let moduleOutput = ""; 34 | if (mod.wrapper === "none") { 35 | moduleOutput = moduleContents; 36 | } 37 | else if (mod.wrapper === "IIFE" || mod.wrapper === undefined) { 38 | // keep internal modules private unless building for tests 39 | if (buildPath !== testBuildPath) moduleOutput = "const "; 40 | moduleOutput += `${mod.name} = (function(){\n${moduleContents}\n})();`; 41 | } 42 | else { 43 | console.error(`No such wrapper type: ${mod.wrapper} for module: ${mod.name}`); 44 | moduleOutput = `// OMITTED MODULE ${mod.name} DUE TO ERROR`; 45 | } 46 | fs.appendFile(buildPath, moduleOutput + "\n", () => {}); 47 | } 48 | fs.appendFile(buildPath, "return ensemble;\n})();", () => {}); 49 | } 50 | -------------------------------------------------------------------------------- /docs/toolscreenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/docs/toolscreenshot.png -------------------------------------------------------------------------------- /ensemble/Volition.js: -------------------------------------------------------------------------------- 1 | /*global console, define */ 2 | /*jshint sub:true*/ 3 | /* 4 | * This is the class Volition, for caching and accessing calculated volitions for characters in ensemble, using an Iterator pattern. 5 | * 6 | * Basic usage of this module: store a calculated volition using the saveVolitions function 7 | * 8 | * The internal format for a volitions objects should be structured like this: 9 | * { 10 | "Simon": { 11 | "Monica": [ 12 | { "category": "network", "type": "buddy", "intentType": true, "weight": 20 }, 13 | { "category": "relationship", "type": "involved with", "intentType": true, "weight": 19 } 14 | ] 15 | }, 16 | "Monica": { 17 | "Simon": [ 18 | { "category": "network", "type": "romance", "intentType": false, "weight": 12 } 19 | ] 20 | } 21 | } 22 | * 23 | * Public methods are: 24 | * 25 | * calculateVolition 26 | * runTriggerRules 27 | * 28 | * @class volition 29 | * @private 30 | */ 31 | var volitionCache = {}; 32 | var cachePositions = {}; 33 | 34 | /** 35 | * Get the highest-weighted volition in a given set, for a particular pair of characters, or return undefined if no such volition can be found. 36 | * 37 | * @param {String} key The identifier for a volition set. 38 | * @param {String} from Identifier for the "from" character. 39 | * @param {String} to Identifier for the "to" character. 40 | * 41 | * @return {Object} A volition predicate, with keys "category", "network", "type", "intentType", and "weight". (Or undefined if there are no volotions for this pair of characters.) 42 | */ 43 | var getFirstVolition = function(key, from, to) { 44 | 45 | // Check that we have volitions to return. 46 | var vSet = volitionCache[key]; 47 | if (vSet === undefined) { 48 | console.log("No matching volition set found with key '" + key + "'."); 49 | return undefined; 50 | } 51 | if (vSet[from] === undefined || vSet[from][to] === undefined) { 52 | console.log("No matching volitions found in set '" + key + "' from '" + from + "' to '" + to + "'."); 53 | return undefined; 54 | } 55 | 56 | // Set the cache position for this pair of characters to 0. 57 | var cachePositionsKey = key + from + to; 58 | cachePositions[cachePositionsKey] = 0; 59 | 60 | // Return the volition at the first position (highest weighted). 61 | return vSet[from][to][0]; 62 | 63 | }; 64 | 65 | /** 66 | * Get the next-highest-weighted volition in a given set, for a particular pair of characters, or return undefined if no such volition can be found. If this function on a set for the first time, it acts the same as getFirstVolition. Note that iteration is by a particular pair of characters; calling the function for a different pair of characters will start at getFirst for that pair. 67 | * 68 | * @param {String} key The identifier for a volition set. 69 | * @param {String} from Identifier for the "from" character. 70 | * @param {String} to Identifier for the "to" character. 71 | * 72 | * TODO: It would be nice to have functionality to get a specified intent (e.g. 'what is the volition for Simon to startDating Monica?') 73 | * 74 | * @return {Object} A volition predicate, with keys "category", "network", "type", "intentType", and "weight". (Or undefined if there are no more volitions for this pair of characters.) 75 | */ 76 | var getNextVolition = function(key, from, to) { 77 | 78 | var cachePositionsKey = key + from + to; 79 | var vSet = volitionCache[key]; 80 | var pos = cachePositions[cachePositionsKey]; 81 | 82 | // If we have no cached position, act like getFirstVolition. 83 | if (pos === undefined) { 84 | return getFirstVolition(key, from, to); 85 | } 86 | 87 | // If we are out of volitions, return undefined 88 | if (vSet[from][to][pos+1] === undefined) { 89 | return undefined; 90 | } 91 | 92 | // Advance the cache position and return the next volition. 93 | cachePositions[cachePositionsKey] += 1; 94 | pos = cachePositions[cachePositionsKey]; 95 | return vSet[from][to][pos]; 96 | 97 | }; 98 | 99 | /** Given a set of pre-computed volitions, returns an object with a boolean and an array of reasons why (i.e. b/c their weight is >= 0). 100 | * 101 | * @method isAccepted 102 | * @memberof Volition 103 | * @param {String} key The string that serves as an index to look up volitions in the volitionCache 104 | * @param {String} initiator The first person in the predicate attempted the intent predicate 105 | * @param {String} responder The second person in the predicate 106 | * @param {Object} predicate Predicate intent object to try to match from the predicate intents in the volitionCache 107 | * @return {Object} returnObject an object with the keys: 108 | * {Boolean} accepted - whether the intent is accepted 109 | * {Array} reasonsWhy - the array of volition predicates that are the reason(s) something was accepted 110 | */ 111 | var isAccepted = function(key, initiator, responder, predicate) { 112 | var acceptIfNoMatch = true; // If no matching rules affect the decision, should the character accept or reject the game? 113 | var minimumWeightForAccept = 0; 114 | 115 | var returnObject = {}; 116 | returnObject.accepted = acceptIfNoMatch; 117 | returnObject.reasonsWhy = []; 118 | 119 | var thisV = getFirstVolition(key, responder, initiator); 120 | while (thisV !== undefined) { 121 | if (thisV["category"] === predicate["category"] && 122 | thisV["type"] === predicate["type"] && 123 | thisV["intentType"] === predicate["intentType"]) { 124 | returnObject.weight = thisV.weight; 125 | if (thisV.weight < minimumWeightForAccept) { 126 | returnObject.reasonsWhy.push(thisV); 127 | returnObject.accepted = false; 128 | return returnObject; 129 | } 130 | else { 131 | returnObject.reasonsWhy.push(thisV); 132 | returnObject.accepted = true; 133 | return returnObject; 134 | } 135 | } 136 | thisV = getNextVolition(key, responder, initiator); 137 | } 138 | 139 | return returnObject; 140 | }; 141 | 142 | /** 143 | * Take a set of calculated volitions, sort it, and store it in the internal cache. Return an interface that allows for iterating through its results. 144 | * 145 | * @param {String} key An identifier for this volition set. 146 | * @param {Object} volitions [description] 147 | * 148 | * @return {Object} An interface with functions "getFirst" and "getNext" to iterate through the volitions for particular pair of characters. 149 | */ 150 | var register = function(key, volitions) { 151 | 152 | // Sort the passed-in volitions. 153 | // 154 | // Very simple function used by _.sortBy below to know how to order 155 | // the volition objects for a character set. 156 | var vSort = function(obj) { 157 | return -1 * obj.weight; // -1* since sort works in asending 158 | }; 159 | 160 | // Each character pair in calculatedVolitions now needs to be sorted 161 | // in weight order. Use underscore sortBy on the weight key. 162 | var cast = _.keys(volitions); 163 | var castLength = cast.length; 164 | for (var first = 0; first < castLength; first++) { 165 | for (var second = 0; second < castLength; second++) { 166 | if (second === first) { 167 | //For 'undirected' volitions, we want people to be able to direct volitions towards themselves. 168 | //continue; 169 | } 170 | 171 | volitions[cast[first]][cast[second]] = _.sortBy(volitions[cast[first]][cast[second]], vSort); 172 | } 173 | } 174 | 175 | // Store the sorted volition object in our internal cache. 176 | volitionCache[key] = volitions; 177 | 178 | // Return an interface using currying to pre-fill the value 179 | // of key to the volition set in question. 180 | return { 181 | getFirst: function(first, second) { 182 | return getFirstVolition(key, first, second); 183 | }, 184 | getNext: function(first, second) { 185 | return getNextVolition(key, first, second); 186 | }, 187 | getWeight: function(first, second, predicate) { 188 | var tempPredicates = volitionCache[key][first][second]; 189 | var checkNextPredicate = false; 190 | for (var i = 0 ; i < tempPredicates.length ; i += 1) { 191 | for (var key in predicate) { 192 | if (predicate[key] !== tempPredicates[key]) { 193 | checkNextPredicate = true; 194 | break; 195 | } 196 | } 197 | if(checkNextPredicate !== true) { 198 | return tempPredicates[i].weight; 199 | } 200 | } 201 | return 0; // our default value 202 | }, 203 | dump: function() { // for testing 204 | return volitionCache[key]; 205 | }, 206 | isAccepted: function(initiator, responder, predicate) { 207 | return isAccepted(key, initiator, responder, predicate); 208 | } 209 | }; 210 | }; 211 | 212 | /** 213 | * Return a volitions object prepared to have a blank array for every obj[first][second] pair of cast members. 214 | * 215 | * @param {Array of Strings} cast Cast members to prepare the object with. 216 | * 217 | * @return {Object} Prepared volitions object. 218 | */ 219 | var newSet = function(cast) { 220 | var volitionShell = {}; 221 | if (cast === undefined) return volitionShell; 222 | for (var i = 0; i < cast.length; i++) { 223 | volitionShell[cast[i]] = {}; 224 | for (var j = 0; j < cast.length; j++) { 225 | if (i === j) { 226 | //We want the i === j case to be represented, as a means of characters having undirected volitions (e.g., a character wants to boost their own intelligence). 227 | //continue; 228 | } 229 | volitionShell[cast[i]][cast[j]] = []; 230 | } 231 | } 232 | return volitionShell; 233 | }; 234 | 235 | /** 236 | * @function getVolitionCacheByKey 237 | * @memberof Volition 238 | * @description Given a key, return the contents of the voitionCache at that point 239 | * @private 240 | * @param {[string]} key [The identifier of a volition set.] 241 | * @return {[type]} [The volitions of the specified key.] 242 | */ 243 | var getVolitionCacheByKey = function(key){ 244 | return volitionCache[key]; 245 | }; 246 | 247 | /** 248 | * @functiongetAllVolitionsByKeyFromTo 249 | * @private 250 | * @memberof Volition 251 | * @param {[string]} key [The idenfifier of a volition set] 252 | * @param {[string]} from [The 'initiator' that these volitions pertain to] 253 | * @param {[string]} to [The 'responder' that these volitions pertain to] 254 | * @return {[type]} [The volitions from the volition set specified by key that describe what the 'from' character wants to do with the 'to' character] 255 | */ 256 | var getAllVolitionsByKeyFromTo = function(key, from, to){ 257 | return volitionCache[key][from][to]; 258 | }; 259 | 260 | var volitionInterface = { 261 | newSet: newSet, 262 | register: register, 263 | }; 264 | 265 | /* test-code */ 266 | volitionInterface.getVolitionCacheByKey = getVolitionCacheByKey; 267 | volitionInterface.getAllVolitionsByKeyFromTo = getAllVolitionsByKeyFromTo; 268 | volitionInterface.isAccepted = isAccepted; 269 | /* end-test-code */ 270 | 271 | return volitionInterface; 272 | -------------------------------------------------------------------------------- /ensembletool/README.md: -------------------------------------------------------------------------------- 1 | # Ensemble Authoring Tool 2 | 3 | The Ensemble Authoring Tool can be built as a standalone app for Mac/Windows/Linux (via Node) with: 4 | 5 | grunt build 6 | 7 | It can also be run in a web browser for testing, but to do this you'll need a web server running on your computer for file i/o. On Mac OS, if you navigate to the main ensemble folder (one folder above "ensembletool", you can type this at a command prompt to start a server based in that directory: 8 | 9 | python -m SimpleHTTPServer 10 | 11 | You then need to open a web browser pointing at the right spot: 12 | 13 | http://localhost:8000/ensembletool/ 14 | -------------------------------------------------------------------------------- /ensembletool/csslib/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/animated-overlay.gif -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /ensembletool/csslib/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensemble-engine/ensemble/8b74bdec4ba2ef4e14795b7591df3b5d73f283e3/ensembletool/csslib/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /ensembletool/defaultdata/actions.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileName" : "consoleDefaultActions.json", 3 | "actions" : [ 4 | { 5 | "name" : "STARTDATING", 6 | "intent" : { 7 | "category" : "relationship", 8 | "type" : "involved with", 9 | "intentType" : true, 10 | "first" : "initiator", 11 | "second" : "responder" 12 | }, 13 | "conditions" : [], 14 | "influenceRules" : [], 15 | "leadsTo" : ["ASKOUT", "PICKUPLINE"] 16 | }, 17 | { 18 | "name" : "ASKOUT", 19 | "conditions" : [], 20 | "influenceRules" : [], 21 | "leadsTo" : ["askoutTerminal", "askoutTerminalReject"] 22 | }, 23 | { 24 | "name" : "PICKUPLINE", 25 | "conditions" : [], 26 | "influenceRules" : [ 27 | { 28 | "name": "Happy people are more inclined to do pickuplines.", 29 | "conditions": [ 30 | { 31 | "category" : "status", 32 | "type" : "happy", 33 | "first" : "initiator", 34 | "value" : true 35 | } 36 | ], 37 | "weight" : 542 38 | } 39 | ], 40 | "leadsTo" : ["pickupLineTerminal"] 41 | }, 42 | { 43 | "name" : "askoutTerminal", 44 | "conditions" : [], 45 | "influenceRules" : [], 46 | "effects" : [{ 47 | "category" : "relationship", 48 | "type" : "involved with", 49 | "first" : "initiator", 50 | "second" : "responder", 51 | "value" : true 52 | }], 53 | "isAccept" : true 54 | }, 55 | { 56 | "name" : "askoutTerminalReject", 57 | "conditions" : [], 58 | "influenceRules" : [], 59 | "effects" : [{ 60 | "category" : "relationship", 61 | "type" : "involved with", 62 | "first" : "initiator", 63 | "second" : "responder", 64 | "value" : false 65 | }], 66 | "isAccept" : false 67 | }, 68 | { 69 | "name" : "pickupLineTerminal", 70 | "conditions" : [], 71 | "influenceRules" : [], 72 | "effects" : [{ 73 | "category" : "relationship", 74 | "type" : "involved with", 75 | "first" : "initiator", 76 | "second" : "responder", 77 | "value" : true 78 | }], 79 | "isAccept" : true 80 | }, 81 | { 82 | "name" : "STARTFRIENDS", 83 | "conditions" : [], 84 | "influenceRules" : [], 85 | "intent" : { 86 | "category" : "relationship", 87 | "type" : "friends", 88 | "intentType" : true, 89 | "first" : "initiator", 90 | "second" : "responder" 91 | }, 92 | "leadsTo" : ["BOND", "LAUGH"] 93 | }, 94 | { 95 | "name" : "BOND", 96 | "conditions" : [], 97 | "influenceRules" : [], 98 | "leadsTo" : ["bondTerminal"] 99 | }, 100 | { 101 | "name" : "LAUGH", 102 | "conditions" : [], 103 | "influenceRules" : [], 104 | "leadsTo" : ["laughTerminal1", "laughTerminal2"] 105 | }, 106 | { 107 | "name" : "bondTerminal", 108 | "conditions" : [], 109 | "influenceRules" : [], 110 | "effects" : [{ 111 | "category" : "relationship", 112 | "type" : "friends", 113 | "first" : "initiator", 114 | "second" : "responder", 115 | "value" : true 116 | }], 117 | "isAccept" : true 118 | }, 119 | { 120 | "name" : "laughTerminal1", 121 | "conditions" : [], 122 | "influenceRules" : [], 123 | "effects" : [{ 124 | "category" : "relationship", 125 | "type" : "friends", 126 | "first" : "initiator", 127 | "second" : "responder", 128 | "value" : true 129 | }], 130 | "isAccept" : true 131 | }, 132 | { 133 | "name" : "laughTerminal2", 134 | "conditions" : [], 135 | "influenceRules" : [ 136 | { 137 | "name": "lucky people are a little less inclined to do a laughTerminal2.", 138 | "conditions": [ 139 | { 140 | "category" : "trait", 141 | "type" : "lucky", 142 | "first" : "initiator", 143 | "value" : true 144 | } 145 | ], 146 | "weight" : 2 147 | } 148 | 149 | ], 150 | "effects" : [{ 151 | "category" : "relationship", 152 | "type" : "friends", 153 | "first" : "initiator", 154 | "second" : "responder", 155 | "value" : true 156 | }], 157 | "isAccept" : true 158 | } 159 | ] 160 | } 161 | -------------------------------------------------------------------------------- /ensembletool/defaultdata/cast.json: -------------------------------------------------------------------------------- 1 | { 2 | "cast": { 3 | "al": { 4 | "name": "Al" 5 | }, 6 | "bob": { 7 | "name": "Bob" 8 | }, 9 | "carla": { 10 | "name": "Carla" 11 | }, 12 | "diane": { 13 | "name": "Diane" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ensembletool/defaultdata/history.json: -------------------------------------------------------------------------------- 1 | { 2 | "history": [{ 3 | "pos": 0, 4 | "data": [ 5 | { 6 | "category": "relationship", 7 | "type": "involved with", 8 | "first": "al", 9 | "second": "bob", 10 | "value": true 11 | },{ 12 | "category": "network", 13 | "type": "affinity", 14 | "first": "al", 15 | "second": "bob", 16 | "value": 75 17 | },{ 18 | "category": "network", 19 | "type": "affinity", 20 | "first": "bob", 21 | "second": "al", 22 | "value": 90 23 | },{ 24 | "category": "status", 25 | "type": "happy", 26 | "first": "bob", 27 | "value": true 28 | },{ 29 | "category": "status", 30 | "type": "injured", 31 | "first": "diane", 32 | "value": true 33 | },{ 34 | "category": "directedStatus", 35 | "type": "attracted to", 36 | "first": "al", 37 | "second": "diane", 38 | "value": true 39 | } 40 | ]}, { 41 | "pos": 1, 42 | "data": [ 43 | { 44 | "category": "relationship", 45 | "type": "involved with", 46 | "first": "bob", 47 | "second": "al", 48 | "value": false 49 | },{ 50 | "category": "status", 51 | "type": "happy", 52 | "first": "bob", 53 | "value": false 54 | },{ 55 | "category": "directedStatus", 56 | "type": "upset with", 57 | "first": "bob", 58 | "second": "al", 59 | "value": true 60 | } 61 | ]}, { 62 | "pos": 2, 63 | "data": [ 64 | { 65 | "category": "status", 66 | "type": "lonely", 67 | "first": "al", 68 | "value": true 69 | },{ 70 | "category": "relationship", 71 | "type": "friends", 72 | "first": "bob", 73 | "second": "al", 74 | "value": true 75 | },{ 76 | "category": "relationship", 77 | "type": "friends", 78 | "first": "diane", 79 | "second": "al", 80 | "value": true 81 | },{ 82 | "category": "network", 83 | "type": "affinity", 84 | "first": "diane", 85 | "second": "bob", 86 | "value": 50 87 | },{ 88 | "category": "network", 89 | "type": "affinity", 90 | "first": "bob", 91 | "second": "diane", 92 | "value": 80 93 | },{ 94 | "category": "directedStatus", 95 | "type": "upset with", 96 | "first": "bob", 97 | "second": "al", 98 | "value": false 99 | } 100 | ]} 101 | ] 102 | } 103 | -------------------------------------------------------------------------------- /ensembletool/defaultdata/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": [ 3 | { 4 | "category": "status", 5 | "isBoolean": true, 6 | "directionType": "undirected", 7 | "types": ["grieving", "happy", "lonely", "sad", "injured", "injured", "fatigued", "dead", "exhausted", "recovering", "resting", "expelled"], 8 | "duration": 6, 9 | "defaultValue": false, 10 | "actionable": false 11 | }, 12 | { 13 | "category": "network", 14 | "isBoolean": false, 15 | "directionType": "directed", 16 | "types": ["affinity", "trust"], 17 | "defaultValue": 50, 18 | "minValue": 0, 19 | "maxValue": 100, 20 | "actionable": true 21 | }, 22 | { 23 | "category": "relationship", 24 | "isBoolean": true, 25 | "directionType": "reciprocal", 26 | "types": ["friends", "involved with", "comrades"], 27 | "defaultValue": false, 28 | "actionable": true 29 | }, 30 | { 31 | "category": "directedStatus", 32 | "isBoolean": true, 33 | "directionType": "directed", 34 | "types": ["attracted to", "worried about", "upset with", "hates"], 35 | "duration": 20, 36 | "defaultValue": false, 37 | "actionable": false 38 | }, 39 | { 40 | "category": "trait", 41 | "isBoolean": true, 42 | "directionType": "undirected", 43 | "types": ["liked movies", "liked sports", "liked music", "has a great smile", "jealous", "trusting", "has a kind face"], 44 | "defaultValue": false, 45 | "actionable": false 46 | }, 47 | { 48 | "category": "socialRecordLabel", 49 | "types": ["romanticfailure", "romantic advance", "embarrassing", "newlabel"], 50 | "isBoolean": true, 51 | "directionType": "directed", 52 | "defaultValue": false, 53 | "actionable": false, 54 | "duration": 0 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /ensembletool/defaultdata/triggerRules.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileName" : "testTriggerRules", 3 | "type": "trigger", 4 | "rules": [ 5 | { 6 | "name": "If I'm jealous and someone hits on my sweetie, I hate them A LOT.", 7 | "conditions": [ 8 | { 9 | "category": "relationship", 10 | "type": "involved with", 11 | "first": "x", 12 | "second": "y" 13 | },{ 14 | "category": "trait", 15 | "type": "jealous", 16 | "first": "x" 17 | },{ 18 | "category": "socialRecordLabel", 19 | "type": "romantic advance", 20 | "first": "z", 21 | "second": "y" 22 | } 23 | ], 24 | "effects": [ 25 | { 26 | "category": "directedStatus", 27 | "type": "hates", 28 | "first": "x", 29 | "second": "z", 30 | "value": true 31 | } 32 | ] 33 | }, 34 | { 35 | "name": "If your sweetie is injured, you worry about them.", 36 | "conditions": [ 37 | { 38 | "category": "status", 39 | "type": "injured", 40 | "first": "y" 41 | },{ 42 | "category": "relationship", 43 | "type": "involved with", 44 | "first": "x", 45 | "second": "y" 46 | } 47 | ], 48 | "effects": [ 49 | { 50 | "category": "directedStatus", 51 | "type": "worried about", 52 | "first": "x", 53 | "second": "y", 54 | "value": true 55 | } 56 | ] 57 | }, 58 | { 59 | "name": "Someone with two friends is no longer lonely.", 60 | "conditions": [ 61 | { 62 | "category": "status", 63 | "type": "lonely", 64 | "first": "x" 65 | },{ 66 | "category": "relationship", 67 | "type": "friends", 68 | "first": "x", 69 | "second": "y" 70 | },{ 71 | "category": "relationship", 72 | "type": "friends", 73 | "first": "x", 74 | "second": "z" 75 | } 76 | ], 77 | "effects": [ 78 | { 79 | "category": "status", 80 | "type": "lonely", 81 | "first": "x", 82 | "value": false 83 | } 84 | ] 85 | }, 86 | { 87 | "name": "If worried and no longer dating, remove status.", 88 | "conditions": [ 89 | { 90 | "category": "relationship", 91 | "type": "involved with", 92 | "first": "x", 93 | "second": "y", 94 | "value": true, 95 | "order": 0, 96 | "turnsAgoBetween": ["NOW", 3] 97 | }, 98 | { 99 | "category": "relationship", 100 | "type": "involved with", 101 | "first": "x", 102 | "second": "y", 103 | "value": false, 104 | "order": 1, 105 | "turnsAgoBetween": ["NOW", 3] 106 | 107 | }, 108 | { 109 | "category": "directedStatus", 110 | "type": "worried about", 111 | "first": "x", 112 | "second": "y", 113 | "value": true 114 | } 115 | ], 116 | "effects": [ 117 | { 118 | "category": "directedStatus", 119 | "type": "worried about", 120 | "first": "x", 121 | "second": "y", 122 | "value": false 123 | } 124 | ] 125 | } 126 | ], 127 | "inactiveRules": [ 128 | { 129 | "name": "If someone starts dating my ex, I stop being friends with them.", 130 | "conditions": [ 131 | { 132 | "category": "relationship", 133 | "type": "involved with", 134 | "first": "x", 135 | "second": "y", 136 | "turnsAgoBetween": [1, 100] 137 | }, 138 | { 139 | "category": "relationship", 140 | "type": "involved with", 141 | "first": "x", 142 | "second": "y", 143 | "value": false 144 | }, 145 | { 146 | "category": "relationship", 147 | "type": "involved with", 148 | "first": "y", 149 | "second": "z", 150 | "value": true 151 | }, 152 | { 153 | "category": "relationship", 154 | "type": "friends", 155 | "first": "x", 156 | "second": "z" 157 | } 158 | ], 159 | "effects": [ 160 | { 161 | "category": "relationship", 162 | "type": "friends", 163 | "first": "x", 164 | "second": "z", 165 | "value": false 166 | } 167 | ] 168 | } 169 | ] 170 | 171 | } -------------------------------------------------------------------------------- /ensembletool/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ensemble Tool 6 | 7 | 8 | 9 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 41 | 42 |

Ensemble Tool

43 | 44 |
45 | 52 |
53 |
54 |

Commands: set • 55 | unset • 56 | volitions • 57 | next • 58 | show • 59 | actions • 60 | doAction 61 |

62 | 63 | 64 |

 

65 |
66 |
67 | Command: 68 |
69 |
 
 
 
70 |
71 |
72 |

Social Record History

73 |
74 |

Timestep

75 |

76 | 77 |
78 |

Green indicates new value this timestep.

79 | 80 |
81 |
82 | 83 |
84 |
85 |
86 |
87 | Filter Rules: 88 | 89 |
90 | 94 |
95 |

Trigger Rules

96 |
97 |
98 |
99 |

Volition Rules

100 |
101 |
102 |
103 | 104 |
105 |
106 |
107 |
108 |

No Rule Loaded.

109 |
110 | 111 | 143 | 144 |
145 | 146 | 147 | 148 |
149 | 150 | 151 |
152 | 153 | 154 |
155 | 156 |

Active Schema

157 | 158 |
159 | 160 |
161 | 162 |
163 |

Actions

164 |
165 |
166 | 167 |
168 |

Characters

169 |
170 |
171 | 172 | 173 | 174 |
175 |
176 | 177 |
178 |
179 | 180 | 181 | 182 |
183 |
184 | 185 | 186 |
Changes saved.
187 |
188 |
189 | 190 | Undirected 191 | Directed 192 | Reciprocal 193 |
194 |
195 | 196 | True/False 197 | Numeric 198 |
199 |
200 | 201 | 202 | True 203 | False 204 | 205 | 206 |
207 |
208 | 209 | / 210 | 211 |
212 |
213 | 214 | 215 | 216 |
217 |
218 | 219 | 220 |
221 |
222 | 223 |
224 | 225 | NEW 226 |
227 |
228 |
229 | 230 | These schema entries involve this category: 231 |
237 |
238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | -------------------------------------------------------------------------------- /ensembletool/js/actionEditor.js: -------------------------------------------------------------------------------- 1 | /* 2 | Handles the ability to edit actions. Presents each "actionable" intent twice for each type (for "start dating" / "stop dating") 3 | And for each of those, offers a starter "isAccept" and "isReject" answer. 4 | */ 5 | 6 | actionEditor = (function(){ 7 | 8 | 9 | var intentDisplay = $("#typesTabs"); 10 | var authoringArea = $("#authoringArea"); 11 | var listOfActionsArea = $("#listOfActionsDiv"); 12 | var actionEditorArea = $("#tabsActionEditor"); 13 | 14 | var init = function() { 15 | // Setup interface buttons. 16 | var socialStructure = ensemble.getSocialStructure(); 17 | console.log("Here is the social structure FROM INIT: " , socialStructure); 18 | 19 | //NOTE: WE PROBABLY WANT TO MOVE THE CONTENTS OF REFRESH INTO INIT; 20 | //REFRESH IS AN ARTIFACT OF AN INITIAL ATTEMPT THAT USED TO CALL 21 | //actionEditor.init() IN THE WRONG PLACE. 22 | refresh(); 23 | intentDisplay.tabs( 24 | {activate: function( event, ui ) { 25 | console.log("hi you clicked me!") 26 | }}).addClass( "ui-tabs-vertical ui-helper-clearfix" ); 27 | 28 | 29 | $("button#intentAreaButton").click(intentAreaButtonClick); 30 | $("button#authoringAreaButton").click(authoringareaButtonClick); 31 | 32 | 33 | 34 | 35 | //intentTypeList.append("
  • Start Dating
  • "); 36 | //intentTypeList.append("
  • Stop Dating
  • ") 37 | /* 38 | intentDisplay.append(""); 42 | */ 43 | 44 | } 45 | 46 | var intentAreaButtonClick = function() { 47 | console.log("INTENT AREA CLICK!") 48 | var socialStructure = ensemble.getSocialStructure(); 49 | console.log("Umm.. maybe this has made the socialStructure better? " , socialStructure); 50 | console.log("Um, I think this is what was clicked?" , event.target.parentElement.id); 51 | console.log("Uh, what about event? " , event); 52 | /* 53 | if (interfaceTimestep >= socialRecord.getCurrentTimeStep()) { 54 | return; 55 | } 56 | interfaceTimestep += 1; 57 | refresh(); 58 | */ 59 | }; 60 | 61 | var authoringareaButtonClick = function() { 62 | console.log("AUTHORING AREA CLICK!") 63 | var socialStructure = ensemble.getSocialStructure(); 64 | console.log("Umm.. maybe this has made the socialStructure better? " , socialStructure); 65 | /* 66 | if (interfaceTimestep <= 0) { 67 | return; 68 | } 69 | interfaceTimestep -= 1; 70 | refresh(); 71 | */ 72 | }; 73 | 74 | 75 | var refresh = function() { 76 | 77 | console.log("hello! You just clicked the action editor tab! ") 78 | var socialStructure = ensemble.getSocialStructure(); 79 | console.log("Umm.. maybe this has made the socialStructure better? " , socialStructure); 80 | 81 | for(var categoryKey in socialStructure){ 82 | var category = socialStructure[categoryKey]; 83 | console.log("A CATEGORY: " , categoryKey) 84 | console.log("Here's a category " , category) 85 | for (var typeKey in category){ 86 | console.log("A TYPE: " , typeKey) 87 | var type = category[typeKey] 88 | console.log("Here's a type" , type) 89 | var noWhiteSpaceTypeKey = typeKey.replace(/\s/g,'') 90 | var buttonID = "actionEditorButton-"+noWhiteSpaceTypeKey; 91 | console.log("Here is a button id? " + buttonID) 92 | listOfActionsArea.append("
    " + typeKey + "
    "); 93 | //listOfActionsArea.append("