├── .project ├── TwineQuest.mob.twee ├── TwineQuest.twee ├── Wiki └── TiddlyWiki Refrence Here.txt ├── demo ├── TwineQuest_proposal.html ├── TwineQuest_proposal.twee └── TwineQuest_proposal.tws ├── eturnerx.tq.autosynonym.twee ├── eturnerx.tq.helloworld.twee ├── eturnerx.tq.mobnamer.elvish.twee ├── eturnerx.tq.mobnamer.goblin.twee ├── eturnerx.tq.mobnamer.roman.twee ├── eturnerx.tq.mobnamer.twee ├── examples ├── 9999 Macro name.twee └── Item syntax example.twee ├── macros ├── 9999 Macro atend.twee ├── 9999 Macro br.twee └── 9999 Macro while.twee ├── mods └── 9990 Display Console.twee └── styles ├── 9991 Style BlueScreen.twee └── 9991 Style GreenScreen.twee /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | TwineQuest 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /TwineQuest.mob.twee: -------------------------------------------------------------------------------- 1 | ::TwineQuest.mob.twee About [Twine.private] 2 | LICENSE: Public Domain 3 | 4 | PURPOSE: 5 | TwineQuest plugin for mobs (monster objects) 6 | 7 | This plugin implements basic functionality and can be extended by other 8 | TwineQuest plugins to add custom attributes and functionality to the 9 | mobs. 10 | 11 | USAGE: {mob} 12 | 13 | CONTRIBUTORS: 14 | (Add your name as you contribute) 15 | Emmanuel King Turner (eturnerx / @stormrose / Et) http://eturnerx.com 16 | 17 | 18 | //TODO: state.history[0].variables[i] = this._internalstore[i]; should copy not reference the data 19 | 20 | ::TwineQuest.mob [tq.system.plugin] 21 | { 22 | version: '0.1.0', 23 | 24 | tag: 'mob', 25 | 26 | onInit: null, 27 | 28 | onPassage: function(passage) { 29 | if(passage && passage.text) { 30 | var t = TwineQuest.acnToObject(passage.text); 31 | if(t.id == null) { 32 | t.id = passage.title; 33 | } 34 | this.onInitMob(t.id, t); 35 | } 36 | }, 37 | 38 | onStart: function() { 39 | for(var i in this._internalstore) { 40 | state.history[0].variables[i] = this._internalstore[i]; 41 | TwineQuest.registerLabel(i, this.handleLabel, state.history[0].variables[i], this); 42 | } 43 | }, 44 | 45 | onEvent: null, 46 | 47 | handleLabel: function(place, label, params, parser, data, plugin) { 48 | if(plugin.onLabel(place, label, params, parser, data, plugin)) { 49 | if(params.length == 0) { 50 | insertElement(place, 'span', null, 'tq_mob ' + data.name, data.name); 51 | } else if(params.length == 1 && params[0] == 'describe') { 52 | insertElement(place, 'span', null, 'tq_mob describe ' + data.name, plugin.onDescribe(place, label, params, parser, data, plugin)); 53 | } else if(params.length == 1 && data[params[0]] != null) { 54 | insertElement(place, 'span', null, 'tq_mob ' + data.name, data[params[0]]); 55 | } else { 56 | insertElement(place, 'span', null, 'tq_mob ' + data.name, data.name + (params.length > 0 ? ' ' : '') + params.join(' ')); 57 | } 58 | } 59 | }, 60 | 61 | //The onInitMob member is for hooking by extensions when a mob's data structure is created 62 | onInitMob: function(tid, mob) { 63 | if(mob.name == null && mob.id) { 64 | mob.name = mob.id; 65 | } 66 | if(mob.type == null) { 67 | mob.type = 'tq.mob'; 68 | } 69 | if(mob.description == null) { 70 | mob.description = mob.name + ' is indescribable.'; 71 | } 72 | TwineQuest.findPluginById('TwineQuest.mob')._internalstore[tid] = mob; 73 | }, 74 | 75 | //The onLabel member is for hooking by extensions to the mob. Return false to cancel default handling 76 | onLabel: function(place, label, params, parser, data, plugin){ return true; }, 77 | 78 | //The onDescribe member is for hooking by extensions to the mob. Returns a string description 79 | onDescribe: function(place, label, params, parser, data, plugin){ return data.description; }, 80 | 81 | _internalstore: {}, 82 | } 83 | -------------------------------------------------------------------------------- /TwineQuest.twee: -------------------------------------------------------------------------------- 1 | ::TwineQuest.twee About [Twine.private] 2 | LICENSE: Public Domain 3 | PURPOSE: 4 | This is the core TwineQuest file. It contains things that are common to 5 | all TwineQuest plugins. The purpose is to: 6 | 7 | 1) Bootstrap the TwineQuest system 8 | 2) Add TwineQuest support to the wikifier 9 | 3) Provide utility functions useful to TwineQuest plugins 10 | 3) Register TwineQuest plugins from the PassageStore 11 | 4) Send events to TwineQuest plugins: init, start 12 | 5) Built in plugins with near universal appeal tq.vars, tq.object 13 | 14 | 15 | TwineQuest plugins are optional. They should be as optional and rely on 16 | each other as little as practicable. 17 | 18 | 19 | USAGE: 20 | You will need a recent alpha version of v1.3.5 or v1.3.6 of Twine or 21 | later. 22 | Create a passage with the title "StoryIncludes" 23 | List this file (with relative path) on it's own line inside this passage 24 | (You may list file with an http url too) 25 | List the filenames of any TwineQuest plugins that you wish to use inside 26 | the StoryIncludes passage. One per line. 27 | 28 | 29 | CONTRIBUTORS: 30 | (Add your name as you contribute) 31 | Henry Soule 32 | Emmanuel King Turner (eturnerx / stormrose / Et) http://eturnerx.com 33 | 34 | 35 | 36 | 37 | 38 | ::TwineQuest Core Macro [script tq.core] 39 | try { 40 | 41 | // Bootstrap the TwineQuest System 42 | version.extensions['TwineQuestSystem'] = { major:0, minor:1, revision:0 }; 43 | var TwineQuest = { 44 | plugins: [], // TwineQuest plugins 45 | tags: {}, // The passage tags that TwineQuest plugins handle 46 | labels: {}, // The {passagetext} that TwineQuest responds to 47 | }; 48 | 49 | // Add TwineQuest support to the wikifier 50 | Wikifier.formatters.push({ 51 | name: 'TwineQuest', 52 | match: '{', 53 | handler: function(w) { 54 | var s = w.source.substr(w.matchStart); 55 | if(s.length > 2 && s.indexOf('}') > 0) { 56 | s = s.substr(1,s.indexOf('}')-1); 57 | w.nextMatch = w.matchStart + s.length + 2; 58 | if(s.length == 0) { 59 | s = ['_']; 60 | } else { 61 | s = s.split(' '); 62 | } 63 | var label = s.shift(); 64 | if(TwineQuest.labels[label] && typeof TwineQuest.labels[label].handler == 'function') { 65 | TwineQuest.labels[label].handler( 66 | w.output, label, s, w, 67 | (TwineQuest.labels[label].data ? TwineQuest.labels[label].data : null), 68 | (TwineQuest.labels[label].plugin ? TwineQuest.labels[label].plugin : null) 69 | ); 70 | } else { 71 | var label1 = (label.indexOf('$') == 0 ? label.substr(1) : label); 72 | var branches = label1.split('.'); 73 | branches = branches.concat(s); 74 | var node = state.history[0].variables; 75 | var traverse = true; 76 | var newnode; 77 | var i = branches.length; 78 | while(traverse == true && i--) { 79 | newnode = branches.shift(); 80 | if(node[newnode] != null) { 81 | node = node[newnode]; 82 | } else { 83 | traverse = false; 84 | } 85 | } 86 | if(traverse) { 87 | insertElement(w.output,'span',null,'tq_print_var',node); 88 | } else { 89 | insertElement(w.output,'span',null,'marked',label + (s.length > 0 ? ' ' : '') + s.join(' ')); 90 | } 91 | } 92 | } else { 93 | insertElement(w.output,'span',null,'marked','TwineQuest:Opening Curly Brace with no match closing curly brace:'); 94 | } 95 | } 96 | }); 97 | 98 | 99 | // Provide utility functions useful to TwineQuest plugins 100 | 101 | //isNumber() from: http://stackoverflow.com/a/1830844 102 | TwineQuest.isNumber = function(n) { 103 | return !isNaN(parseFloat(n)) && isFinite(n); 104 | }; 105 | TwineQuest.registerPlugin = function(a) { 106 | if(a != null) { 107 | if(a.priority == null) { 108 | a.priority = 1000; 109 | } 110 | this.plugins.push(a); 111 | this.plugins.sort(function(a,b){ return a.priority - b.priority; }); 112 | } 113 | }; 114 | TwineQuest.registerLabel = function(label, xhandler, xdata, xplugin) { 115 | this.labels[label] = { handler: xhandler, data: xdata, plugin: xplugin }; 116 | }; 117 | TwineQuest.findPluginById = function(id) { 118 | var r = null; 119 | var i = this.plugins.length - 1; 120 | do { 121 | if(this.plugins[i].id == id) { 122 | r = this.plugins[i]; 123 | break; 124 | } 125 | } while(i--); 126 | return r; 127 | }; 128 | TwineQuest.acnToObject = function(text) { 129 | var r = {}; 130 | var kv = []; 131 | var t = null; 132 | var state = 0; //0 looking for var, 1 adding to value, 2 lastlineblank 133 | 134 | var _numvar = function(t) { 135 | var r = t; 136 | if(TwineQuest.isNumber(t)) { 137 | t = parseFloat(r); 138 | if(!isNaN(t)) { 139 | r = t; 140 | } else { 141 | t = parseInt(r); 142 | if(!isNaN(t)) { 143 | r = t; 144 | } 145 | } 146 | } 147 | return r; 148 | } 149 | 150 | var lines = text.split(String.fromCharCode(10)); 151 | for(var i in lines) { 152 | var line = lines[i]; 153 | switch(state) { 154 | case 0: 155 | if(line.indexOf(':')>-1) { 156 | kv = line.split(':'); 157 | kv[0] = kv[0].trim(); 158 | kv[1] = kv[1].trim(); 159 | if(kv[1].length > 0) { 160 | r[kv[0]] = _numvar(kv[1]); 161 | } else { 162 | state = 1; 163 | } 164 | } 165 | break; 166 | 167 | case 1: 168 | line = line.trim(); 169 | if(line.length == 0) { 170 | state = 2; 171 | kv[1] = kv[1] + String.fromCharCode(10); 172 | } else { 173 | kv[1] = kv[1] + line + String.fromCharCode(10); 174 | } 175 | break; 176 | 177 | case 2: 178 | line = line.trim(); 179 | var icolon = line.indexOf(':'); 180 | var ispace = line.indexOf(' '); 181 | if(icolon > 0 && (ispace < 0 || ispace >= icolon - 1)) { 182 | r[kv[0]] = _numvar(kv[1].trim()); 183 | kv = line.split(':'); 184 | kv[0] = kv[0].trim(); 185 | kv[1] = kv[1].trim(); 186 | if(kv[1].length > 0) { 187 | r[kv[0]] = kv[1]; 188 | state = 0; 189 | } else { 190 | state = 1; 191 | } 192 | } else { 193 | kv[1] = kv[1] + line + String.fromCharCode(10); 194 | if(line.length > 0) { 195 | state = 1; 196 | } 197 | } 198 | break; 199 | } 200 | } 201 | if(state != 0) { 202 | r[kv[0]] = _numvar(kv[1].trim()); 203 | } 204 | return r; 205 | }; 206 | TwineQuest.initPlugins = function() { 207 | for(var ip = 0; ip < this.plugins.length; ip++) { 208 | var a = this.plugins[ip]; 209 | if(a != null) { 210 | if(typeof a.onInit == 'function') { 211 | a.onInit(); 212 | } 213 | if(typeof a.onEvent == 'function') { 214 | a.onEvent('init',null); 215 | } 216 | } 217 | } 218 | }; 219 | TwineQuest.tagFindPlugins = function() { 220 | var ip = this.plugins.length - 1; 221 | do { 222 | var a = this.plugins[ip]; 223 | if(a && a.tag && (typeof a.onPassage == 'function' || typeof a.onEvent == 'function')) { 224 | var p = tale.lookup('tags', 'tq.' + a.tag); 225 | for(var i = 0; i < p.length; i++) { 226 | if(typeof a.onPassage == 'function') { 227 | a.onPassage(p[i]); 228 | } 229 | if(typeof a.onEvent == 'function') { 230 | a.onEvent('passage', p[i]); 231 | } 232 | } 233 | } 234 | } while(ip--); 235 | }; 236 | 237 | 238 | // Built in plugins with near universal appeal 239 | // Automatically set twine variables from tagged passages at story start 240 | TwineQuest.registerPlugin({ 241 | id: 'TwineQuest.AutoVars', 242 | version: '0.1.0', 243 | tag: 'vars', 244 | onPassage: function(passage) { 245 | if(passage && passage.text) { 246 | var t = TwineQuest.acnToObject(passage.text); 247 | for(var i in t) { 248 | this._internalstore[i] = t[i]; 249 | } 250 | } 251 | }, 252 | onStart: function() { 253 | for(var i in this._internalstore) { 254 | state.history[0].variables[i] = this._internalstore[i]; 255 | } 256 | }, 257 | _internalstore: {}, 258 | }); 259 | 260 | // Automatically set twine objects from tagged passages at story start 261 | TwineQuest.registerPlugin({ 262 | id: 'TwineQuest.AutoObject', 263 | version: '0.1.0', 264 | tag: 'object', 265 | onPassage: function(passage) { 266 | var tid; 267 | if(passage && passage.text) { 268 | var t = TwineQuest.acnToObject(passage.text); 269 | tid = (t.id == null ? passage.title : t.id); 270 | if(t.type == null) { 271 | t.type = 'tq.object'; 272 | } 273 | this._internalstore[tid] = t; 274 | } 275 | }, 276 | onStart: function() { 277 | for(var i in this._internalstore) { 278 | state.history[0].variables[i] = Object.create(this._internalstore[i]); 279 | } 280 | }, 281 | _internalstore: {}, 282 | }); 283 | 284 | 285 | // Register TwineQuest plugins from the PassageStore 286 | var p = tale.lookup('tags','tq.system.plugin'); 287 | for(var tqi=0;tqi>{tpms} 23 | 24 | 25 | Is the TwineQuest.AutoVars built-in plugin working? 26 | 1: <> 27 | 2: <> 28 | 3: <> 29 | 30 | -and with alternative curly bracket syntax? 31 | 4: {$autovar4} 32 | 5: {autovar5} 33 | 34 | 35 | Does the TwineQuest.AutoObjects built-in plugin work? 36 | Object One: <> 37 | <> 38 | 39 | -and with alternative curly bracket syntax? 40 | Object Two: {$bananaman.name} 41 | {bananaman description} 42 | 43 | 44 | What about mobs (monster objects)? 45 | As you enter you see {mob1 describe}. His name is {mob1} and he is <> (yes, {mob1.age}) years old. 46 | {mob2}: {mob2 describe} -- (use the tq.mob plugin) 47 | {$mob3.name}: {$mob3 description} -- (autogen use print macro shortcut by prefixing a $) 48 | {mob4} is a {mob4 culture}. - autogen with culture name 49 | 50 | [[Link 1]] (will set the $test var after the jump) 51 | 52 | 53 | 54 | ::Link 1 55 | <> 56 | More frelling syntax: {test will still fail}, but try going back again. 57 | 58 | [[Start again|RealStart]] 59 | 60 | 61 | 62 | ::Autoset some variables [tq.vars] 63 | autovar1: harro 64 | autovar2: 65 | This is a big longer and includes much more stuff that goes over several 66 | lines like this. We'd use this for things that are more descriptive. 67 | 68 | autovar3: 69 | Since acn (attribute colon newline) format terminates on a blank line 70 | then how does one handle this problem? 71 | 72 | Where a var needs to include it's own newlines. 73 | 74 | Before we can start another variable. 75 | 76 | autovar4: Just detect colon with no preceding spaces 77 | 78 | 79 | ::Autoset some more variables [tq.vars] 80 | autovar5: whee! 81 | 82 | 83 | ::potatoman [tq.object] 84 | name: Mr. PotatoMan 85 | description: 86 | Brown skinned and irregularly shaped. At home in the dirt. 87 | 88 | 89 | ::another auto raw object [tq.object] 90 | id: bananaman 91 | name: Mr. BananaMan 92 | description: Yellow, long and hangs in trees. 93 | 94 | 95 | 96 | ::mob1 [tq.mob] 97 | name: Tom 98 | description: a small, confused boy 99 | age: 7 100 | 101 | ::Another mob monster object [tq.mob] 102 | id: mob2 103 | name: Richard 104 | description: 105 | A small boy about eight years old. Afraid but putting on a brave face. 106 | 107 | ::Empty Mob [tq.mob] 108 | id: mob3 109 | 110 | ::Generated Mob [tq.mob] 111 | id: mob4 112 | culture: Goblin 113 | 114 | 115 | ::Some Stylesheet [stylesheet] 116 | .TwineQuest, .tq_mob { 117 | color: #000; 118 | background-color: #ff9; 119 | } 120 | -------------------------------------------------------------------------------- /demo/TwineQuest_proposal.tws: -------------------------------------------------------------------------------- 1 | (dp0 2 | S'buildDestination' 3 | p1 4 | VC:\u005cDocuments and Settings\u005cAdministrator\u005cgit\u005ctweecode\u005cTwineQuest\u005cdemo\u005cTwineQuest_proposal.html 5 | p2 6 | sS'saveDestination' 7 | p3 8 | VC:\u005cDocuments and Settings\u005cAdministrator\u005cgit\u005ctweecode\u005cTwineQuest\u005cdemo\u005cTwineQuest_proposal.tws 9 | p4 10 | sS'target' 11 | p5 12 | S'Responsive' 13 | p6 14 | sS'storyPanel' 15 | p7 16 | (dp8 17 | S'widgets' 18 | p9 19 | (lp10 20 | (dp11 21 | S'selected' 22 | p12 23 | I00 24 | sS'pos' 25 | p13 26 | (lp14 27 | I10 28 | aI10 29 | asS'passage' 30 | p15 31 | (itiddlywiki 32 | Tiddler 33 | p16 34 | (dp17 35 | S'text' 36 | p18 37 | V<> \u000a 38 | p19 39 | sS'tags' 40 | p20 41 | (lp21 42 | sS'created' 43 | p22 44 | ctime 45 | struct_time 46 | p23 47 | ((I2013 48 | I3 49 | I1 50 | I23 51 | I13 52 | I59 53 | I4 54 | I60 55 | I1 56 | tp24 57 | (dp25 58 | tp26 59 | Rp27 60 | sS'modified' 61 | p28 62 | g27 63 | sS'title' 64 | p29 65 | VStart 66 | p30 67 | sbsa(dp31 68 | g12 69 | I00 70 | sg13 71 | (lp32 72 | I150 73 | aI10 74 | asg15 75 | (itiddlywiki 76 | Tiddler 77 | p33 78 | (dp34 79 | g18 80 | VTwineQuest Demo 81 | p35 82 | sg20 83 | (lp36 84 | sg22 85 | g23 86 | ((I2013 87 | I3 88 | I1 89 | I23 90 | I16 91 | I46 92 | I4 93 | I60 94 | I1 95 | tp37 96 | (dp38 97 | tp39 98 | Rp40 99 | sg28 100 | g40 101 | sg29 102 | VStoryTitle 103 | p41 104 | sbsa(dp42 105 | g12 106 | I00 107 | sg13 108 | (lp43 109 | I290 110 | aI10 111 | asg15 112 | (itiddlywiki 113 | Tiddler 114 | p44 115 | (dp45 116 | g18 117 | VA proposal 118 | p46 119 | sg20 120 | (lp47 121 | sg22 122 | g23 123 | ((I2013 124 | I3 125 | I1 126 | I23 127 | I17 128 | I7 129 | I4 130 | I60 131 | I1 132 | tp48 133 | (dp49 134 | tp50 135 | Rp51 136 | sg28 137 | g51 138 | sg29 139 | VStorySubtitle 140 | p52 141 | sbsa(dp53 142 | g12 143 | I00 144 | sg13 145 | (lp54 146 | I430 147 | aI10 148 | asg15 149 | (itiddlywiki 150 | Tiddler 151 | p55 152 | (dp56 153 | g18 154 | VTwineQuest contributors 155 | p57 156 | sg20 157 | (lp58 158 | sg22 159 | g23 160 | ((I2013 161 | I3 162 | I1 163 | I23 164 | I17 165 | I22 166 | I4 167 | I60 168 | I1 169 | tp59 170 | (dp60 171 | tp61 172 | Rp62 173 | sg28 174 | g62 175 | sg29 176 | VStoryAuthor 177 | p63 178 | sbsa(dp64 179 | g12 180 | I00 181 | sg13 182 | (lp65 183 | I570 184 | aI10 185 | asg15 186 | (itiddlywiki 187 | Tiddler 188 | p66 189 | (dp67 190 | g18 191 | VTwineQuest_proposal.twee \u000a../TwineQuest.twee \u000a../TwineQuest.mob.twee \u000a../TwineQuest.getset.twee \u000a../eturnerx.tq.helloworld.twee \u000a../eturnerx.tq.mobnamer.twee \u000a../eturnerx.tq.mobnamer.elvish.twee \u000a../eturnerx.tq.mobnamer.goblin.twee \u000a../eturnerx.tq.mobnamer.roman.twee \u000a 192 | p68 193 | sg20 194 | (lp69 195 | sg22 196 | g23 197 | ((I2013 198 | I3 199 | I1 200 | I23 201 | I17 202 | I43 203 | I4 204 | I60 205 | I1 206 | tp70 207 | (dp71 208 | tp72 209 | Rp73 210 | sg28 211 | g73 212 | sg29 213 | VStoryIncludes 214 | p74 215 | sbsasS'scale' 216 | p75 217 | I1 218 | ss. -------------------------------------------------------------------------------- /eturnerx.tq.autosynonym.twee: -------------------------------------------------------------------------------- 1 | ::eturnerx.tq.autosynonym.twee About [Twine.private] 2 | VERSION: 20130317 3 | LICENSE: Creative Commons. Attribute. Share. 4 | DESCRIPTION: Automagically replace synonyms to give magical random flavour 5 | HISTORY: made for the "Regen" project began Nov 2012 6 | CONTRIBUTORS: Emmanuel King Turner (Et / eturnerx / @stormrose) 7 | USAGE: 8 | Adds a $$prefix to the wikifier. Just use $$ in normal passage text 9 | 10 | Each line is a synonym set. Items in lines are separated by commas 11 | 12 | The first item in each line is the term in the story to match for 13 | replacement. The first item may not contain spaces. 14 | 15 | The second item is commands. Nothing for now so leave blank. 16 | 17 | The third and subsequent items are the replacements. This may have 18 | spaces if you like. 19 | 20 | e.g. 21 | 22 | celebrate, ,celebrate, praise, mark, observe 23 | 24 | 25 | TODO: 26 | 2nd option modes, like choose once, replace always, choice twice replace one or two, never repeat 27 | Convert to TwineQuest plugin 28 | Make it possible to limit synonym matching to a passage, or global 29 | 30 | 31 | ::eturnerx.tq.autosynonym [tq.system.plugin] 32 | { 33 | version: '0.1.0', 34 | 35 | tag: 'eturnerx.autosynonym', 36 | 37 | onInit: function() { 38 | this._synonyms = [ ]; 39 | Wikifier.formatters.push({ 40 | name: 'eturner.tq.autosynonym', 41 | match: String.fromCharCode(92) + '$' + String.fromCharCode(92) + '$' + String.fromCharCode(92) + 'S', 42 | handler: function(w) { 43 | var s = w.source.substr(w.matchStart); 44 | if(s.length > 2 && s.indexOf(' ') > 0) { 45 | s = s.substr(2,s.indexOf(' ')-2).toLowerCase(); 46 | w.nextMatch = w.matchStart + s.length + 2; 47 | var replacement = s; 48 | var sl = this._autosynonymplugin._synonyms; 49 | var i = sl.length; 50 | while(i > 0) { 51 | i--; 52 | if(sl[i].match == s) { 53 | var candidates = sl[i].candidates; 54 | replacement = candidates[Math.floor(Math.random()*candidates.length)]; 55 | break; 56 | } 57 | } 58 | } 59 | insertText(w.output, replacement); 60 | }, 61 | _autosynonymplugin: TwineQuest.findPluginById('eturnerx.tq.autosynonym'), 62 | }); 63 | }, 64 | 65 | onPassage: function(passage) { 66 | var g = passage.text.split(String.fromCharCode(10)); 67 | for(var gi in g) { 68 | var l = g[gi].split(','); 69 | if(l.length == 0) continue; 70 | if(l.length < 3) throw('Entry for ' + l[0] + ' is malformed. Use: PATTERNWORD, MODE, REPLACE1, REPLACE2, ....'); 71 | var synonymindex = null; 72 | var synonymmode = null; 73 | var synonymcandidates = []; 74 | for(var li in l) { 75 | var t = l[li].trim(); 76 | if(t.substr(0,2) == '$$') t = t.substr(2).toLowerCase(); 77 | if(synonymindex == null) synonymindex = t.toLowerCase(); 78 | else if(synonymmode == null) synonymmode = t; 79 | else synonymcandidates.push(t.toLowerCase()); 80 | } 81 | this._synonyms.push({ 82 | match: synonymindex, 83 | mode: synonymmode, 84 | last: '', 85 | candidates: synonymcandidates, 86 | }); 87 | } 88 | }, 89 | 90 | onStart: null, 91 | 92 | onEvent: null, 93 | 94 | _synonyms: null, 95 | } 96 | -------------------------------------------------------------------------------- /eturnerx.tq.helloworld.twee: -------------------------------------------------------------------------------- 1 | ::eturnerx.tq.helloworld.twee About [Twine.private] 2 | LICENSE: Public Domain 3 | 4 | PURPOSE: 5 | A simple plugin demonstration. 6 | 7 | This is called TwineQuest.eturnerx.X.twee because it is not "official" 8 | TwineQuest core plugin or to denote a set of plugins that play nice 9 | together/by the same authors. 10 | 11 | USAGE: {hello} / {hello and some text} 12 | 13 | CONTRIBUTORS: 14 | (Add your name as you contribute) 15 | Emmanuel King Turner (eturnerx / @stormrose / Et) http://eturnerx.com 16 | 17 | 18 | ::eturnerx.tq.helloworld [tq.system.plugin] 19 | { 20 | version: '0.1.1', 21 | 22 | tag: null, 23 | 24 | onInit: function() { 25 | // Nothing to do on init 26 | }, 27 | 28 | onPassage: function(passage) { 29 | // Nothing to do when TQ has a passage that matches 'tag' 30 | }, 31 | 32 | onStart: function() { 33 | // Register our label and it's handler. It doesn't have any associated data 34 | TwineQuest.registerLabel('hello', this.handleLabel, null, this); 35 | }, 36 | 37 | onEvent: function(evt, params) { 38 | }, 39 | 40 | handleLabel: function(place, label, params, parser, data, plugin) { 41 | insertElement(place, 'span', null, 'TwineQuest HelloWorld', label + (params.length > 0 ? ' ' : '') + params.join(' ')); 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /eturnerx.tq.mobnamer.elvish.twee: -------------------------------------------------------------------------------- 1 | ::eturnerx.tq.mobnamer.elvish About [Twine.private] 2 | LICENSE: Public Domain 3 | 4 | Elvish culture name stems for automatic name generation provided by 5 | the eturnerx.tq.mobnamer.twee plugin. 6 | See: the About for eturnerx.tq.mobnamer.twee 7 | 8 | From the examples provided at: 9 | http://forum.codecall.net/topic/49665-java-random-name-generator/#axzz2B24xMDe8 10 | 11 | 12 | CONTRIBUTORS: 13 | (Add your name as you contribute) 14 | Emmanuel King Turner (eturnerx / @stormrose / Et) http://eturnerx.com 15 | 16 | 17 | 18 | ::eturnerx.tq.mobnamer Elvish [tq.eturnerx.mobnamer.culture] 19 | -ael 20 | -aer 21 | -af 22 | -ah 23 | -am 24 | -ama 25 | -an 26 | -ang +v 27 | -ansr +v 28 | -cael 29 | -dae +c 30 | -dho 31 | -eir 32 | -fi 33 | -fir 34 | -la 35 | -seh 36 | -sel 37 | -ev 38 | -fis 39 | -hu 40 | -ha 41 | -gar 42 | -gil 43 | -ka 44 | -kan 45 | -ya 46 | -za 47 | -zy 48 | -mara 49 | -mai +c 50 | -lue +c 51 | -ny 52 | -she 53 | -sum 54 | -syl 55 | ae +c -c 56 | ael -c 57 | dar 58 | deth +v 59 | dre -v 60 | drim -v 61 | dul 62 | ean -c 63 | el 64 | emar 65 | hal 66 | iat -c 67 | mah 68 | ten 69 | que -v +c 70 | ria 71 | rail 72 | ther 73 | thus 74 | thi 75 | san 76 | +ael -c 77 | +dar 78 | +deth 79 | +dre 80 | +drim 81 | +dul 82 | +ean -c 83 | +el 84 | +emar 85 | +nes 86 | +nin 87 | +oth 88 | +hal 89 | +iat 90 | +mah 91 | +ten 92 | +ther 93 | +thus 94 | +thi 95 | +ran 96 | +ath 97 | +ess 98 | +san 99 | +yth 100 | +las 101 | +lian 102 | +evar 103 | -------------------------------------------------------------------------------- /eturnerx.tq.mobnamer.goblin.twee: -------------------------------------------------------------------------------- 1 | ::eturnerx.tq.mobnamer.goblin About [Twine.private] 2 | LICENSE: Public Domain 3 | 4 | Goblin culture name stems for automatic name generation provided by 5 | the eturnerx.tq.mobnamer.twee plugin. 6 | See: the About for eturnerx.tq.mobnamer.twee 7 | 8 | From the examples provided at: 9 | http://forum.codecall.net/topic/49665-java-random-name-generator/#axzz2B24xMDe8 10 | 11 | 12 | CONTRIBUTORS: 13 | (Add your name as you contribute) 14 | Emmanuel King Turner (eturnerx / @stormrose / Et) http://eturnerx.com 15 | 16 | 17 | 18 | ::eturnerx.tq.mobnamer Goblin [tq.eturnerx.mobnamer.culture] 19 | -waa +c 20 | -boo +c 21 | -gar 22 | -bar 23 | -dar 24 | -jar 25 | -var 26 | -kra 27 | -gra 28 | -dra 29 | -zra 30 | -gob 31 | -dob 32 | -rob 33 | -fob 34 | -zob 35 | -rag 36 | -nag 37 | -dag 38 | bra 39 | ga 40 | da 41 | do 42 | go 43 | ze 44 | sha 45 | naz 46 | zub 47 | zu 48 | na 49 | gor 50 | boo +c 51 | +byr 52 | +gyr 53 | +dyr 54 | +vyr 55 | +zyr 56 | +yr -c 57 | +zog 58 | +rog 59 | +gog 60 | +og -c 61 | +gul 62 | +dul 63 | +bul 64 | +rul 65 | +ul -c 66 | +rgh -v 67 | -------------------------------------------------------------------------------- /eturnerx.tq.mobnamer.roman.twee: -------------------------------------------------------------------------------- 1 | ::eturnerx.tq.mobnamer.roman About [Twine.private] 2 | LICENSE: Public Domain 3 | 4 | Roman culture name stems for automatic name generation provided by 5 | the eturnerx.tq.mobnamer.twee plugin. 6 | See: the About for eturnerx.tq.mobnamer.twee 7 | 8 | From the examples provided at: 9 | http://forum.codecall.net/topic/49665-java-random-name-generator/#axzz2B24xMDe8 10 | 11 | 12 | CONTRIBUTORS: 13 | (Add your name as you contribute) 14 | Emmanuel King Turner (eturnerx / @stormrose / Et) http://eturnerx.com 15 | 16 | 17 | 18 | ::eturnerx.tq.mobnamer Roman [tq.eturnerx.mobnamer.culture] 19 | -a 20 | -al 21 | -au +c 22 | -an 23 | -ba 24 | -be 25 | -bi 26 | -br +v 27 | -da 28 | -di 29 | -do 30 | -du 31 | -e 32 | -eu +c 33 | -fa 34 | bi 35 | be 36 | bo 37 | bu 38 | nul +v 39 | gu 40 | da 41 | au +c -c 42 | fri 43 | gus 44 | +tus 45 | +lus 46 | +lius 47 | +nus 48 | +es 49 | +ius -c 50 | +cus 51 | +tor 52 | +cio 53 | +tin 54 | -------------------------------------------------------------------------------- /eturnerx.tq.mobnamer.twee: -------------------------------------------------------------------------------- 1 | ::eturnerx.tq.mobnamer.twee About [Twine.private] 2 | LICENSE: Public Domain 3 | 4 | PURPOSE: 5 | This plugin extends TwineQuest.mob and adds the ability to automatically 6 | generate names for mobs 7 | 8 | The basic name segment generation is based on: 9 | http://forum.codecall.net/topic/49665-java-random-name-generator/#axzz2B24xMDe8 10 | 11 | 12 | USAGE: 13 | Initialise a mob without a name assigned. 14 | Specify an optional culture attribute in the mob to select different name generation cultures 15 | 16 | 17 | CONTRIBUTORS: 18 | (Add your name as you contribute) 19 | Emmanuel King Turner (eturnerx / @stormrose / Et) http://eturnerx.com 20 | 21 | 22 | 23 | ::eturnerx.tq.mobnamer [tq.system.plugin] 24 | { 25 | version: '0.1.0', 26 | 27 | tag: 'eturnerx.mobnamer.culture', 28 | 29 | priority: 2000, 30 | 31 | onInit: function() { 32 | this._mobplugin = TwineQuest.findPluginById('TwineQuest.mob'); 33 | if(this._mobplugin) { 34 | this._old_onInitMob = this._mobplugin.onInitMob; 35 | this._mobplugin.onInitMob = this.onInitMob; 36 | this._mobplugin['_eturnerx.tq.mobnamer'] = this; 37 | this._cultures = {}; 38 | } 39 | }, 40 | 41 | onPassage: function(passage) { 42 | if(passage && passage.title && passage.text) { 43 | var culture = passage.title.substring(passage.title.lastIndexOf(' ') + 1); 44 | this.addCulture(culture.toLowerCase(), passage.text); 45 | } 46 | }, 47 | 48 | onStart: null, 49 | 50 | onEvent: null, 51 | 52 | onInitMob: function(tid, mob) { 53 | if(mob.name == null) { 54 | mob.name = this['_eturnerx.tq.mobnamer'].generateName(mob.culture ? mob.culture : 'Default'); 55 | } 56 | return this['_eturnerx.tq.mobnamer']._old_onInitMob(tid, mob); 57 | }, 58 | 59 | addCulture: function(culture, text) { 60 | this._cultures[culture] = { prefix:[], middle:[], suffix:[] }; 61 | var g = text.split(String.fromCharCode(10)); 62 | for(var gi = 0; gi < g.length; gi++) { 63 | var l = g[gi].split(' '); 64 | var entry = { syllable:null, nextConsonant:false, nextVowel:false, lastConsonant:false, lastVowel:false }; 65 | for(var li = 0; li < l.length; li++) { 66 | var t = l[li]; 67 | if(entry['syllable'] == null) entry['syllable'] = t; 68 | else if(t == '+c') entry['nextConsonant'] = true; 69 | else if(t == '+v') entry['nextVowel'] = true; 70 | else if(t == '-c') entry['lastConsonant'] = true; 71 | else if(t == '-v') entry['lastVowel'] = true; 72 | } 73 | var c = ''; 74 | if(entry['syllable'][0] == '-') { 75 | entry['syllable'] = entry['syllable'].substring(1); 76 | c = entry['syllable'][0]; 77 | entry['startsWithVowel'] = (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'); 78 | c = entry['syllable'][entry['syllable'].length-1]; 79 | entry['endsWithVowel'] = (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'); 80 | this._cultures[culture].prefix.push(entry); 81 | } else if(entry['syllable'][0] == '+') { 82 | entry['syllable'] = entry['syllable'].substring(1); 83 | c = entry['syllable'][0]; 84 | entry['startsWithVowel'] = (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'); 85 | c = entry['syllable'][entry['syllable'].length-1]; 86 | entry['endsWithVowel'] = (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'); 87 | this._cultures[culture].suffix.push(entry); 88 | } else { 89 | c = entry['syllable'][0]; 90 | entry['startsWithVowel'] = (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'); 91 | c = entry['syllable'][entry['syllable'].length-1]; 92 | entry['endsWithVowel'] = (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'); 93 | this._cultures[culture].middle.push(entry); 94 | } 95 | } 96 | }, 97 | 98 | generateName: function(culture) { 99 | if(culture == null) { 100 | culture = 'default'; 101 | } 102 | var ns = this._cultures[culture.toLowerCase()]; 103 | if(ns == null) ns = this._cultures['default']; 104 | var s1e, s2e, s3e, proceed, ok; 105 | s1e = ns.prefix[Math.floor(Math.random() * ns.prefix.length)]; 106 | proceed = -1000; 107 | while(proceed < 0) { 108 | proceed++; 109 | s2e = ns.middle[Math.floor(Math.random() * ns.middle.length)]; 110 | ok = true; 111 | if(s1e.nextConsonant == true && s2e.startsWithVowel == true) ok = false; 112 | if(s1e.nextVowel == true && s2e.startsWithVowel == false) ok = false; 113 | if(s2e.lastConsonant == true && s1e.endsWithVowel == true) ok = false; 114 | if(s2e.lastVowel == true && s1e.endsWithVowel == false) ok = false; 115 | if(ok) proceed = 1; 116 | } 117 | if(proceed == 0) s2e = { syllable:'_' }; 118 | proceed = -1000; 119 | while(proceed < 0) { 120 | proceed++; 121 | s3e = ns.suffix[Math.floor(Math.random() * ns.suffix.length)]; 122 | ok = true; 123 | if(s2e.nextConsonant == true && s3e.startsWithVowel == true) ok = false; 124 | if(s2e.nextVowel == true && s3e.startsWithVowel == false) ok = false; 125 | if(s3e.lastConsonant == true && s2e.endsWithVowel == true) ok = false; 126 | if(s3e.lastVowel == true && s2e.endsWithVowel == false) ok = false; 127 | if(ok) proceed = 1; 128 | } 129 | if(proceed == 0) s3e = { syllable:'_' }; 130 | var segment = s1e.syllable + s2e.syllable + s3e.syllable; 131 | segment = segment.substr(0,1).toUpperCase() + segment.substr(1); 132 | return segment; 133 | }, 134 | 135 | _mobplugin: null, 136 | _old_onInitMob: null, 137 | _cultures: null, 138 | } 139 | 140 | 141 | ::eturnerx.tq.mobnamer Default [tq.eturnerx.mobnamer.culture] 142 | -a 143 | -al 144 | -au +c 145 | -an 146 | -ba 147 | -be 148 | -bi 149 | -br +v 150 | -da 151 | -di 152 | -do 153 | -du 154 | -e 155 | -eu +c 156 | -fa 157 | bi 158 | be 159 | bo 160 | bu 161 | nul +v 162 | gu 163 | da 164 | au +c -c 165 | fri 166 | gus 167 | +tus 168 | +lus 169 | +lius 170 | +nus 171 | +es 172 | +ius -c 173 | +cus 174 | +tor 175 | +cio 176 | +tin -------------------------------------------------------------------------------- /examples/9999 Macro name.twee: -------------------------------------------------------------------------------- 1 | ::9999 Macro name.twee [Twine.private] 2 | This passage is used to document the macro, acknowledgements etc. 3 | It does not end up in generated html files due to the tag 4 | 5 | credit Stormrose 6 | 7 | ::9999 Macro name [script] 8 | The actual code for the macro/s 9 | -------------------------------------------------------------------------------- /examples/Item syntax example.twee: -------------------------------------------------------------------------------- 1 | ::The Golden Axe [TwineQuest.Item] 2 | LABEL: Golden Axe 3 | DESCRIPTION 4 | The Golden Axe of Sega, sort after by Amazons, Dwarves and Warriors. Forged of purist pixels and engraved into the memories of many. 5 | 6 | WEIGHT:5kg 7 | MATERIAL: 8 | Gold Alloy 9 | Leather 10 | 11 | LENGTH:1.5m 12 | SLOT: 2-handed-weapon 13 | ATTACK MODIFIER: +5 14 | -------------------------------------------------------------------------------- /macros/9999 Macro atend.twee: -------------------------------------------------------------------------------- 1 | ::9999 Macro atend.twee About [Twine.private] 2 | VERSION: 20141206 3 | LICENSE: Public Domain 4 | 5 | USAGE: 6 | <>This text appears at the end of the passage<> 7 | 8 | PURPOSE: 9 | To output certain text at the end of the current passage. 10 | 11 | CONTRIBUTORS: 12 | Emmanuel King Turner (eturnerx / Et / @stormrose) 13 | 14 | ACKNOWLEDGEMENT: 15 | Originally made for use in "Raik" by Harry Giles http://ifdb.tads.org/viewgame?id=j8dfkrype8wk70k 16 | Uses the function decorators from http://me.dt.in.th/page/JavaScript-override/ 17 | 18 | ::9999 Macro atend.twee [script] 19 | (function() { 20 | version.extensions.atendmacro = { 21 | major: 1, 22 | minor: 0, 23 | revision: 0 24 | }; 25 | 26 | //Function decorators from: http://me.dt.in.th/page/JavaScript-override/ 27 | function override(object, methodName, callback) { 28 | object[methodName] = callback(object[methodName]) 29 | } 30 | function override_before(extraBehavior) { 31 | return function(original) { 32 | return function() { 33 | extraBehavior.apply(this, arguments) 34 | return original.apply(this, arguments) 35 | } 36 | } 37 | } 38 | function override_after(extraBehavior) { 39 | return function(original) { 40 | return function() { 41 | var returnValue = original.apply(this, arguments) 42 | extraBehavior.apply(this, arguments) 43 | return returnValue 44 | } 45 | } 46 | } 47 | 48 | //Setup a macro to always print text at end of passage. 49 | macros.atend = {}; 50 | macros.atend.handler = function(place, macroName, params, parser) { 51 | var srcOffset = parser.source.indexOf(">>", parser.matchStart) + 2, 52 | src = parser.source.slice(srcOffset), 53 | i = src.indexOf('<>'); 54 | 55 | if(i > -1) { 56 | if (tale.atend === undefined) { 57 | tale.atend = [ place, '' ]; 58 | } 59 | tale.atend[1] += src.substr(0, i); 60 | parser.nextMatch = srcOffset + i + 10; 61 | } else { 62 | throwError(place, "<> can't find a matching <>", parser.fullMatch()); 63 | } 64 | }; 65 | macros.atendd = { handler: function() {} }; 66 | override(Passage.prototype, 'render', override_after(function() { 67 | if(tale.atend !== undefined) { 68 | new Wikifier(tale.atend[0], tale.atend[1]); 69 | tale.atend = undefined; 70 | } 71 | })); 72 | }()); 73 | -------------------------------------------------------------------------------- /macros/9999 Macro br.twee: -------------------------------------------------------------------------------- 1 | ::9999 Macro br.twee About [Twine.private] 2 | 3 | VERSION: 20130317 4 | 5 | LICENSE: Public Domain 6 | 7 | USAGE: 8 | <
> 9 | 10 | (No parameters) 11 | 12 | 13 | PURPOSE: 14 | Gives author control that deals with Twine's "trim whitespace" around 15 | fragments behaviour. 16 | Useful at the start or end of passages. 17 | Useful at the start or end within <><><> blocks 18 | This macro <
> is a shortcut for
19 | 20 | CONTRIBUTORS: 21 | Emmanuel King Turner (eturnerx / Et / @stormrose) 22 | 23 | ACKNOWLEDGEMENT: 24 | Idea came from user frustration expressed here: 25 | http://groups.google.com/d/topic/tweecode/FBgGTBrH8aM/discussion 26 | 27 | 28 | ::9999 Macro br.twee [script] 29 | try { macros['br'] = { 30 | handler: function(place,macroName,params,parser) { 31 | new Wikifier(place, '
'); 32 | }, 33 | init: function() { } 34 | };} catch(e) { 35 | throwError(place,"Macro br Error: "+e.message); 36 | } 37 | -------------------------------------------------------------------------------- /macros/9999 Macro while.twee: -------------------------------------------------------------------------------- 1 | ::9999 Macro while.twee About [Twine.private] 2 | 3 | VERSION: 20140827 4 | 5 | LICENSE: CC BY-SA 4.0 | Creative Commons Attribute Share-Alike. http://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | USAGE: 8 | <> 9 | Do stuff. 10 | <> 11 | 12 | PURPOSE: 13 | Implementation of a while loop. Avoids using the awful hacks of the past. 14 | 15 | CONTRIBUTORS: 16 | Emmanuel King Turner (eturnerx / Et / @stormrose) 17 | 18 | ACKNOWLEDGEMENT: 19 | Basic idea taken from the <> macro, but works slightly differently. 20 | 21 | 22 | ::9999 Macro while.twee [script] 23 | try { 24 | 25 | version.extensions.whileMacros = { 26 | major: 1, minor: 0, revision: 0 27 | }; 28 | 29 | macros['while'] = { 30 | handler: function(place, macroName, params, parser) { 31 | var srcOffset = parser.source.indexOf(">>", parser.matchStart) + 2, 32 | src = parser.source.slice(srcOffset), 33 | endPos = -1, 34 | condition = parser.fullArgs().trim(), 35 | body = "", 36 | nestlevel = 0, 37 | i = 0; 38 | 39 | for (; i < src.length; i++) { 40 | if (src.substr(i, 8) == "<>") { 44 | nestlevel--; 45 | if (nestlevel < 0) { 46 | endPos = srcOffset + i + 12; 47 | break; 48 | } 49 | } 50 | body += src.charAt(i); 51 | } 52 | body = body.trim(); 53 | 54 | if (endPos != -1) { 55 | parser.nextMatch = endPos; 56 | try { 57 | while (internalEval(condition)) { 58 | new Wikifier(place, body); 59 | } 60 | } catch (e) { 61 | throwError(place, "<> bad condition: " + condition, parser.fullMatch()); 62 | } 63 | } else { 64 | throwError(place, "I can't find a matching <>", parser.fullMatch()); 65 | } 66 | }, 67 | init: function() { } 68 | }; 69 | 70 | macros["endwhile"] = { 71 | handler: function () {} 72 | }; 73 | 74 | } catch(e) { 75 | throwError(place,"Macro while Error: "+e.message); 76 | } 77 | -------------------------------------------------------------------------------- /mods/9990 Display Console.twee: -------------------------------------------------------------------------------- 1 | ::9990 Display Console About [Twine.private] 2 | LICENSE: Public Domain 3 | VERSION: 20130317 4 | DESCRIPTION: 5 | This provides some hacks to the Jonah story format to support a continuous 6 | scrolling story - similar to the text terminal games of yore. 7 | 8 | Useful for many oldschool text game conversions. 9 | Works best when partnered with a friendly style-sheet 10 | e.g. 9991 Style GreenScreen.twee 11 | 9991 Style BlueScreen.twee 12 | 13 | TECHNICAL: 14 | Replaces the Passage.prototype.render 15 | - Always appends text. Adds a timestamp to the passage id 16 | - Suppresses the passage title and toolbar from Jonah 17 | Replaces the <> macro to deactivate all choices once one has 18 | been selected by the user. 19 | 20 | Probably not compatible with anything else that replaces/extends 21 | - Passage.prototype.render 22 | - <> macro 23 | 24 | CONTRIBUTORS: 25 | Emmanuel King Turner (Et / eturnerx / @stormrose) 26 | 27 | 28 | ::9990 Display Console [script] 29 | // Needed to allow loops back through text while keeping output linear 30 | // Suppress title and toolbar while we're at it 31 | Passage.prototype.render = function() { 32 | var passagediv = insertElement(null, 'div', 'passage' + this.title + 'j' + (new Date).getTime(), 'passage'); 33 | passagediv.style.visibility = 'hidden'; 34 | passagediv.setAttribute('data-tags', this.tags.join(' ')); 35 | var body = insertElement(passagediv, 'div', '', 'body'); 36 | new Wikifier(body, this.text); 37 | // event handlers 38 | passagediv.onmouseover = function() { passagediv.className += ' selected' }; 39 | passagediv.onmouseout = function() { passagediv.className = passagediv.className.replace(' selected', ''); }; 40 | return passagediv; 41 | }; 42 | 43 | //And hack the choice macro - no going back! 44 | macros['choice'].activate = function (el, destination) { 45 | var parentDiv = el.parentNode; 46 | while (parentDiv.className.indexOf('body') == -1) 47 | parentDiv = parentDiv.parentNode; 48 | var title = parentDiv.parentNode.id.substr(7); 49 | var links = parentDiv.getElementsByTagName('a'); 50 | var trashed = []; 51 | for (var i = 0; i < links.length; i++) 52 | if (links[i].className.indexOf('choice') != -1) { 53 | var span = document.createElement('span'); 54 | span.innerHTML = links[i].innerHTML; 55 | span.className = 'disabled'; 56 | links[i].parentNode.insertBefore(span, links[i].nextSibling); 57 | trashed.push(links[i]); 58 | }; 59 | tale.get(title).text = '' + parentDiv.childNodes[0].innerHTML + ''; 60 | state.display(destination, el); 61 | for (var i = 0; i < trashed.length; i++) 62 | trashed[i].parentNode.removeChild(trashed[i]); 63 | } 64 | -------------------------------------------------------------------------------- /styles/9991 Style BlueScreen.twee: -------------------------------------------------------------------------------- 1 | ::9991 Style BlueScreen.twee About [Twine.private] 2 | LICENSE: Public Domain 3 | CONTRIBUTORS: Emmanuel King Turner (eturnerx / Et / @stormrose) 4 | VERSION: 20130317 5 | DESCRIPTION: 6 | A blue version of an old console style greenscreen. 7 | Assumes the Jonah storyformat 8 | 9 | USAGE: 10 | Either (A is preferred) 11 | A) Include by listing the file in your StoryIncludes passage 12 | -or- 13 | B) Import the .twee file into your story. 14 | 15 | 16 | ::9991 Style BlueScreen [stylesheet] 17 | .passage .title { display:none; } 18 | body { background-color: #000; color: #36f; font-family: monospace; } 19 | #content2, .passage, #passages, h1, h2, h3 { background-color: #003; color: #69f; font-family: monospace; } 20 | #content2 { padding: 1em 2.5em; } 21 | #passages { padding-bottom: 5em; } 22 | .passage { font-size: 12px; line-height: 17px; } 23 | a.internalLink, a.externalLink, .disabled { color: #06f; } 24 | .disabled { font-style: normal; } 25 | #footer { position: fixed; bottom: 1em; right: 1em; width: 15em; background-color: #000; text-align: left; color: #006; } 26 | h1 { text-align: left; font-size: 28px; line-height: 34px; } 27 | h2 { text-align: left; font-size: 17px; line-height: 17px; font-style: normal; font-weight: bold; } 28 | h3 { text-align: left; font-size: 14px; line-height: 17px; font-weight: bold; margin: 0; padding: 0; } 29 | #storyTitle { display: block; text-align: center; font-size: 34px; line-height: 34px; } 30 | -------------------------------------------------------------------------------- /styles/9991 Style GreenScreen.twee: -------------------------------------------------------------------------------- 1 | ::9991 Style GreenScreen About [Twine.private] 2 | LICENSE: Public Domain 3 | CONTRIBUTORS: Emmanuel King Turner (eturnerx / Et / @stormrose) 4 | VERSION: 20130317 5 | DESCRIPTION: 6 | A green version of an old console style greenscreen. 7 | Assumes the Jonah storyformat 8 | 9 | USAGE: 10 | Either (A is preferred) 11 | A) Include by listing the file in your StoryIncludes passage 12 | -or- 13 | B) Import the .twee file into your story. 14 | 15 | 16 | ::9991 Style GreenScreen.twee [stylesheet] 17 | .passage .title { display:none; } 18 | body { background-color: #000; color: #6f3; font-family: monospace; } 19 | #content2, .passage, #passages, h1, h2, h3 { background-color: #030; color: #6f3; font-family: monospace; } 20 | #content2 { padding: 1em 2.5em; } 21 | #passages { padding-bottom: 5em; } 22 | .passage { font-size: 12px; line-height: 17px; } 23 | a.internalLink, a.externalLink, .disabled { color: #6f0; } 24 | .disabled { font-style: normal; } 25 | #footer { position: fixed; bottom: 1em; right: 1em; width: 15em; background-color: #000; text-align: left; color: #060; } 26 | h1 { text-align: left; font-size: 28px; line-height: 34px; } 27 | h2 { text-align: left; font-size: 17px; line-height: 17px; font-style: normal; font-weight: bold; } 28 | h3 { text-align: left; font-size: 14px; line-height: 17px; font-weight: bold; margin: 0; padding: 0; } 29 | #storyTitle { display: block; text-align: center; font-size: 34px; line-height: 34px; } 30 | --------------------------------------------------------------------------------