123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329 |
- var fs = require('fs');
- // Constants
- var con =
- {
- allowable_connections:
- [
- ['dialogue.Text', 'dialogue.Text'],
- ['dialogue.Text', 'dialogue.Node'],
- ['dialogue.Text', 'dialogue.Choice'],
- ['dialogue.Text', 'dialogue.Set'],
- ['dialogue.Text', 'dialogue.Branch'],
- ['dialogue.Text', 'dialogue.Function'],
- ['dialogue.Text', 'dialogue.Tree'],
- ['dialogue.Text', 'dialogue.GoToLabel'],
- ['dialogue.Text', 'dialogue.ConditionalBranch'],
- ['dialogue.Node', 'dialogue.Text'],
- ['dialogue.Node', 'dialogue.Node'],
- ['dialogue.Node', 'dialogue.Choice'],
- ['dialogue.Node', 'dialogue.Set'],
- ['dialogue.Node', 'dialogue.Branch'],
- ['dialogue.Node', 'dialogue.Function'],
- ['dialogue.Node', 'dialogue.Tree'],
- ['dialogue.Node', 'dialogue.GoToLabel'],
- ['dialogue.Node', 'dialogue.ConditionalBranch'],
- ['dialogue.Tree', 'dialogue.Node'],
- ['dialogue.Tree', 'dialogue.Text'],
- ['dialogue.Tree', 'dialogue.Choice'],
- ['dialogue.Tree', 'dialogue.Set'],
- ['dialogue.Tree', 'dialogue.Branch'],
- ['dialogue.Tree', 'dialogue.Function'],
- ['dialogue.Tree', 'dialogue.Tree'],
- ['dialogue.Tree', 'dialogue.GoToLabel'],
- ['dialogue.Tree', 'dialogue.ConditionalBranch'],
- ['dialogue.StartNode', 'dialogue.Text'],
- ['dialogue.StartNode', 'dialogue.Node'],
- ['dialogue.StartNode', 'dialogue.Choice'],
- ['dialogue.StartNode', 'dialogue.Set'],
- ['dialogue.StartNode', 'dialogue.Branch'],
- ['dialogue.StartNode', 'dialogue.Function'],
- ['dialogue.StartNode', 'dialogue.Tree'],
- ['dialogue.StartNode', 'dialogue.GoToLabel'],
- ['dialogue.StartNode', 'dialogue.ConditionalBranch'],
- ['dialogue.Choice', 'dialogue.Text'],
- ['dialogue.Choice', 'dialogue.Node'],
- ['dialogue.Choice', 'dialogue.Set'],
- ['dialogue.Choice', 'dialogue.Branch'],
- ['dialogue.Choice', 'dialogue.Function'],
- ['dialogue.Choice', 'dialogue.Tree'],
- ['dialogue.Choice', 'dialogue.GoToLabel'],
- ['dialogue.Choice', 'dialogue.ConditionalBranch'],
- ['dialogue.Set', 'dialogue.Text'],
- ['dialogue.Set', 'dialogue.Node'],
- ['dialogue.Set', 'dialogue.Set'],
- ['dialogue.Set', 'dialogue.Branch'],
- ['dialogue.Set', 'dialogue.Function'],
- ['dialogue.Set', 'dialogue.Tree'],
- ['dialogue.Set', 'dialogue.GoToLabel'],
- ['dialogue.Set', 'dialogue.ConditionalBranch'],
- ['dialogue.Function', 'dialogue.Text'],
- ['dialogue.Function', 'dialogue.Node'],
- ['dialogue.Function', 'dialogue.Set'],
- ['dialogue.Function', 'dialogue.Branch'],
- ['dialogue.Function', 'dialogue.Function'],
- ['dialogue.Function', 'dialogue.Tree'],
- ['dialogue.Function', 'dialogue.GoToLabel'],
- ['dialogue.Function', 'dialogue.ConditionalBranch'],
- ['dialogue.Branch', 'dialogue.Text'],
- ['dialogue.Branch', 'dialogue.Node'],
- ['dialogue.Branch', 'dialogue.Set'],
- ['dialogue.Branch', 'dialogue.Branch'],
- ['dialogue.Branch', 'dialogue.Function'],
- ['dialogue.Branch', 'dialogue.Tree'],
- ['dialogue.Branch', 'dialogue.GoToLabel'],
- ['dialogue.Branch', 'dialogue.ConditionalBranch'],
- ['dialogue.ConditionalBranch', 'dialogue.Text'],
- ['dialogue.ConditionalBranch', 'dialogue.Node'],
- ['dialogue.ConditionalBranch', 'dialogue.Set'],
- ['dialogue.ConditionalBranch', 'dialogue.ConditionalBranch'],
- ['dialogue.ConditionalBranch', 'dialogue.Branch'],
- ['dialogue.ConditionalBranch', 'dialogue.Function'],
- ['dialogue.ConditionalBranch', 'dialogue.Tree'],
- ['dialogue.ConditionalBranch', 'dialogue.GoToLabel'],
- ],
- default_link: new joint.dia.Link(
- {
- attrs:
- {
- '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z', },
- '.link-tools .tool-remove circle, .marker-vertex': { r: 8 },
- },
- }),
- };
- con.default_link.set('smooth', true);
- // State
- var state =
- {
- graph: new joint.dia.Graph(),
- paper: null,
- filepath: null,
- panning: false,
- mouse_position: { x: 0, y: 0 },
- context_position: { x: 0, y: 0 },
- menu: null,
- };
- // Models
- joint.shapes.dialogue = {};
- joint.shapes.dialogue.Base = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Base',
- size: { width: 100, height: 64 },
- name: '',
- attrs:
- {
- rect: { stroke: 'none', 'fill-opacity': 0 },
- text: { display: 'none' },
- },
- },
- joint.shapes.devs.Model.prototype.defaults
- ),
- });
- joint.shapes.dialogue.BaseView = joint.shapes.devs.ModelView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '<textarea class="name" placeholder="Text"></textarea>',
- '</div>',
- ].join(''),
- initialize: function()
- {
- _.bindAll(this, 'updateBox');
- joint.shapes.devs.ModelView.prototype.initialize.apply(this, arguments);
- this.$box = $(_.template(this.template)());
- // Prevent paper from handling pointerdown.
- this.$box.find('textarea, input').on('mousedown click', function(evt) { evt.stopPropagation(); });
- // This is an example of reacting on the input change and storing the input data in the cell model.
- this.$box.find('textarea.name, input.name').on('change', _.bind(function(evt)
- {
- this.model.set('name', $(evt.target).val());
- }, this));
- this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
- // Update the box position whenever the underlying model changes.
- this.model.on('change', this.updateBox, this);
- // Remove the box when the model gets removed from the graph.
- this.model.on('remove', this.removeBox, this);
- this.updateBox();
- },
- render: function()
- {
- joint.shapes.devs.ModelView.prototype.render.apply(this, arguments);
- this.paper.$el.prepend(this.$box);
- this.updateBox();
- return this;
- },
- updateBox: function()
- {
- // Set the position and dimension of the box so that it covers the JointJS element.
- var bbox = this.model.getBBox();
- // Example of updating the HTML with a data stored in the cell model.
- var nameField = this.$box.find('textarea.name, input.name');
- if (!nameField.is(':focus'))
- nameField.val(this.model.get('name'));
- var label = this.$box.find('.label');
- var type = this.model.get('type').slice('dialogue.'.length);
- label.text(type);
- label.attr('class', 'label ' + type);
- this.$box[0].classList.add(type);
- this.$box.css({ width: bbox.width, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });
- },
- removeBox: function(evt)
- {
- this.$box.remove();
- },
- });
- joint.shapes.dialogue.Node = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Node',
- size: { width: 100, height: 65, },
- inPorts: ['input'],
- outPorts: ['output'],
- attrs:
- {
- '.outPorts circle': { unlimitedConnections: ['dialogue.Choice'], }
- },
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.NodeView = joint.shapes.dialogue.BaseView;
- joint.shapes.dialogue.Tree = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Tree',
- size: { width: 150, height: 65, },
- inPorts: ['input'],
- outPorts: ['output'],
- attrs:
- {
- '.outPorts circle': { unlimitedConnections: ['dialogue.Choice'], }
- },
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.TreeView = joint.shapes.dialogue.BaseView;
- joint.shapes.dialogue.Text = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Text',
- size: { width: 350 },
- inPorts: ['input'],
- outPorts: ['output'],
- attrs:
- {
- '.outPorts circle': { unlimitedConnections: ['dialogue.Choice'], }
- },
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.TextView = joint.shapes.dialogue.BaseView;
- joint.shapes.dialogue.Function = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Function',
- size: { width: 200, height: 65, },
- inPorts: ['input'],
- outPorts: ['output'],
- attrs:
- {
- '.outPorts circle': { unlimitedConnections: ['dialogue.Choice'], }
- },
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.FunctionView = joint.shapes.dialogue.BaseView;
- joint.shapes.dialogue.GoToLabel = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.GoToLabel',
- size: { width: 125, height: 65, },
- inPorts: ['input'],
- outPorts: ['output'],
- attrs:
- {
- '.outPorts circle': { unlimitedConnections: ['dialogue.Choice'], }
- },
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.GoToLabelView = joint.shapes.dialogue.BaseView;
- joint.shapes.dialogue.Branch = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Branch',
- size: { width: 150, height: 95, },
- inPorts: ['input'],
- outPorts: ['output0'],
- values: [],
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.BranchView = joint.shapes.dialogue.BaseView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '<button class="add">+</button>',
- '<button class="remove">-</button>',
- '<input type="text" class="name" placeholder="Variable" />',
- '<input type="text" value="Default" readonly/>',
- '</div>',
- ].join(''),
- initialize: function()
- {
- joint.shapes.dialogue.BaseView.prototype.initialize.apply(this, arguments);
- this.$box.find('.add').on('click', _.bind(this.addPort, this));
- this.$box.find('.remove').on('click', _.bind(this.removePort, this));
- },
- removePort: function()
- {
- if (this.model.get('outPorts').length > 1)
- {
- var outPorts = this.model.get('outPorts').slice(0);
- outPorts.pop();
- this.model.set('outPorts', outPorts);
- var values = this.model.get('values').slice(0);
- values.pop();
- this.model.set('values', values);
- this.updateSize();
- }
- },
- addPort: function()
- {
- var outPorts = this.model.get('outPorts').slice(0);
- outPorts.push('output' + outPorts.length.toString());
- this.model.set('outPorts', outPorts);
- var values = this.model.get('values').slice(0);
- values.push(null);
- this.model.set('values', values);
- this.updateSize();
- },
- updateBox: function()
- {
- joint.shapes.dialogue.BaseView.prototype.updateBox.apply(this, arguments);
- var values = this.model.get('values');
- var valueFields = this.$box.find('input.value');
- // Add value fields if necessary
- for (var i = valueFields.length; i < values.length; i++)
- {
- // Prevent paper from handling pointerdown.
- var $field = $('<input type="text" class="value" />');
- $field.attr('placeholder', 'Value ' + (i + 1).toString());
- $field.attr('index', i);
- this.$box.append($field);
- $field.on('mousedown click', function(evt) { evt.stopPropagation(); });
- // This is an example of reacting on the input change and storing the input data in the cell model.
- $field.on('change', _.bind(function(evt)
- {
- var values = this.model.get('values').slice(0);
- values[$(evt.target).attr('index')] = $(evt.target).val();
- this.model.set('values', values);
- }, this));
- }
- // Remove value fields if necessary
- for (var i = values.length; i < valueFields.length; i++)
- $(valueFields[i]).remove();
- // Update value fields
- valueFields = this.$box.find('input.value');
- for (var i = 0; i < valueFields.length; i++)
- {
- var field = $(valueFields[i]);
- if (!field.is(':focus'))
- field.val(values[i]);
- }
- },
- updateSize: function()
- {
- var textField = this.$box.find('input.name');
- var height = textField.outerHeight(true);
- this.model.set('size', { width: 150, height: 95 + Math.max(0, (this.model.get('outPorts').length - 1) * height) });
- },
- });
- joint.shapes.dialogue.ConditionalBranch = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.ConditionalBranch',
- size: { width: 200, height: 55, },
- inPorts: ['input'],
- outPorts: ['output0'],
- values: [],
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.ConditionalBranchView = joint.shapes.dialogue.BaseView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '<button class="add">+</button>',
- '<button class="remove">-</button>',
- '<input type="text" value="Default" readonly/>',
- '</div>',
- ].join(''),
- initialize: function()
- {
- joint.shapes.dialogue.BaseView.prototype.initialize.apply(this, arguments);
- this.$box.find('.add').on('click', _.bind(this.addPort, this));
- this.$box.find('.remove').on('click', _.bind(this.removePort, this));
- },
- removePort: function()
- {
- if (this.model.get('outPorts').length > 1)
- {
- var outPorts = this.model.get('outPorts').slice(0);
- outPorts.pop();
- this.model.set('outPorts', outPorts);
- var values = this.model.get('values').slice(0);
- values.pop();
- this.model.set('values', values);
- this.updateSize();
- }
- },
- addPort: function()
- {
- var outPorts = this.model.get('outPorts').slice(0);
- outPorts.push('output' + outPorts.length.toString());
- this.model.set('outPorts', outPorts);
- var values = this.model.get('values').slice(0);
- values.push(null);
- this.model.set('values', values);
- this.updateSize();
- },
- updateBox: function()
- {
- joint.shapes.dialogue.BaseView.prototype.updateBox.apply(this, arguments);
- var values = this.model.get('values');
- var valueFields = this.$box.find('input.value');
- // Add value fields if necessary
- for (var i = valueFields.length; i < values.length; i++)
- {
- // Prevent paper from handling pointerdown.
- var $field = $('<input type="text" class="value" />');
- $field.attr('placeholder', 'Condition ' + (i + 1).toString());
- $field.attr('index', i);
- this.$box.append($field);
- $field.on('mousedown click', function(evt) { evt.stopPropagation(); });
- // This is an example of reacting on the input change and storing the input data in the cell model.
- $field.on('change', _.bind(function(evt)
- {
- var values = this.model.get('values').slice(0);
- values[$(evt.target).attr('index')] = $(evt.target).val();
- this.model.set('values', values);
- }, this));
- }
- // Remove value fields if necessary
- for (var i = values.length; i < valueFields.length; i++)
- $(valueFields[i]).remove();
- // Update value fields
- valueFields = this.$box.find('input.value');
- for (var i = 0; i < valueFields.length; i++)
- {
- var field = $(valueFields[i]);
- if (!field.is(':focus'))
- field.val(values[i]);
- }
- },
- updateSize: function()
- {
- var textField = this.$box.find('input');
- var height = textField.outerHeight(true);
- this.model.set('size', { width: 200, height: 95 + Math.max(0, (this.model.get('outPorts').length - 1) * height) });
- },
- });
- joint.shapes.dialogue.StartNode = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.StartNode',
- inPorts: [],
- outPorts: ['output'],
- size: { width: 100, height: 32, },
- value: 'DialogueNode.START',
- attrs:
- {
- '.outPorts circle': { unlimitedConnections: ['dialogue.Choice'], }
- },
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.StartNodeView = joint.shapes.dialogue.BaseView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '</div>',
- ].join(''),
- initialize: function()
- {
- joint.shapes.dialogue.BaseView.prototype.initialize.apply(this, arguments);
- //this.$box.find('input.value').on('change', _.bind(function(evt)
- //{
- // this.model.set('value', $(evt.target).val());
- //}, this));
- },
- updateBox: function()
- {
- joint.shapes.dialogue.BaseView.prototype.updateBox.apply(this, arguments);
- //var field = this.$box.find('input.value');
- //if (!field.is(':focus'))
- // field.val(this.model.get('value'));
- },
- });
- joint.shapes.dialogue.Choice = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Choice',
- inPorts: ['input'],
- outPorts: ['output'],
- size: { width: 175, height: 93, },
- value: '',
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.ChoiceView = joint.shapes.dialogue.BaseView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '<input type="text" class="name" placeholder="Text" />',
- '<input type="text" class="value" placeholder="Conditions" />',
- '</div>',
- ].join(''),
- initialize: function()
- {
- joint.shapes.dialogue.BaseView.prototype.initialize.apply(this, arguments);
- this.$box.find('input.value').on('change', _.bind(function(evt)
- {
- this.model.set('value', $(evt.target).val());
- }, this));
- },
- updateBox: function()
- {
- joint.shapes.dialogue.BaseView.prototype.updateBox.apply(this, arguments);
- var field = this.$box.find('input.value');
- if (!field.is(':focus'))
- field.val(this.model.get('value'));
- },
- });
- joint.shapes.dialogue.Set = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.Set',
- inPorts: ['input'],
- outPorts: ['output'],
- size: { width: 125, height: 90, },
- value: '',
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.SetView = joint.shapes.dialogue.BaseView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '<input type="text" class="name" placeholder="Variable" />',
- '<input type="text" class="value" placeholder="Value" />',
- '</div>',
- ].join(''),
- initialize: function()
- {
- joint.shapes.dialogue.BaseView.prototype.initialize.apply(this, arguments);
- this.$box.find('input.value').on('change', _.bind(function(evt)
- {
- this.model.set('value', $(evt.target).val());
- }, this));
- },
- updateBox: function()
- {
- joint.shapes.dialogue.BaseView.prototype.updateBox.apply(this, arguments);
- var field = this.$box.find('input.value');
- if (!field.is(':focus'))
- field.val(this.model.get('value'));
- },
- });
- /**
- *
- * AI Hook
- *
- */
- joint.shapes.dialogue.AIHook = joint.shapes.devs.Model.extend(
- {
- defaults: joint.util.deepSupplement
- (
- {
- type: 'dialogue.AIHook',
- inPorts: [],
- outPorts: [],
- size: { width: 300, height: 126, },
- value: '',
- },
- joint.shapes.dialogue.Base.prototype.defaults
- ),
- });
- joint.shapes.dialogue.AIHookView = joint.shapes.dialogue.BaseView.extend(
- {
- template:
- [
- '<div class="node">',
- '<span class="label"></span>',
- '<button class="delete">x</button>',
- '<select class="hooktype">',
- '<option value="" selected disabled hidden>Choose Type</option>',
- '<option value="askabout">Investigate Option</option>',
- '<option value="circumstance">Common Dialogue Option</option>',
- '<option value="informative">Pre-Dialogue Dialogue</option>',
- '<option value="critical">Override Dialogue</option>',
- '</select>',
- '<input type="text" class="identifier" placeholder="Selection Text" />',
- '<input type="text" class="conditions" placeholder="Conditions (greeter, answerer)" />',
- '</div>',
- ].join(''),
- initialize: function()
- {
- joint.shapes.dialogue.BaseView.prototype.initialize.apply(this, arguments);
- this.$box.find('input.conditions').on('change', _.bind(function(evt)
- {
- this.model.set('conditions', $(evt.target).val());
- }, this));
- this.$box.find('select.hooktype').on('change', _.bind(function(evt)
- {
- this.model.set('hooktype', $(evt.target).val());
- }, this));
- this.$box.find('input.identifier').on('change', _.bind(function(evt)
- {
- this.model.set('identifier', $(evt.target).val());
- }, this));
- },
- updateBox: function()
- {
- joint.shapes.dialogue.BaseView.prototype.updateBox.apply(this, arguments);
- var field = this.$box.find('select.hooktype');
- if (!field.is(':focus'))
- field.val(this.model.get('hooktype'));
- var field = this.$box.find('input.conditions');
- if (!field.is(':focus'))
- field.val(this.model.get('conditions'));
- var field = this.$box.find('input.identifier');
- if (!field.is(':focus'))
- field.val(this.model.get('identifier'));
- },
- });
- // Functions
- var func = {};
- func.validate_connection = function(cellViewS, magnetS, cellViewT, magnetT, end, linkView)
- {
- // Prevent loop linking
- if (magnetS === magnetT)
- return false;
- if (cellViewS === cellViewT)
- return false;
- if ($(magnetT).parents('.outPorts').length > 0) // Can't connect to an output port
- return false;
- var sourceType = cellViewS.model.attributes.type;
- var targetType = cellViewT.model.attributes.type;
- var valid = false;
- for (var i = 0; i < con.allowable_connections.length; i++)
- {
- var rule = con.allowable_connections[i];
- if (sourceType === rule[0] && targetType === rule[1])
- {
- valid = true;
- break;
- }
- }
- if (!valid)
- return false;
- var links = state.graph.getConnectedLinks(cellViewS.model);
- for (var i = 0; i < links.length; i++)
- {
- var link = links[i];
- if (link.attributes.source.id === cellViewS.model.id && link.attributes.source.port === magnetS.attributes.port.nodeValue && link.attributes.target.id)
- {
- var targetCell = state.graph.getCell(link.attributes.target.id);
- if (targetCell.attributes.type !== targetType)
- return false; // We can only connect to multiple targets of the same type
- if (targetCell === cellViewT.model)
- return false; // Already connected
- }
- }
- return true;
- };
- func.validate_magnet = function(cellView, magnet)
- {
- if ($(magnet).parents('.outPorts').length === 0)
- return false; // we only want output ports
- // If unlimited connections attribute is null, we can only ever connect to one object
- // If it is not null, it is an array of type strings which are allowed to have unlimited connections
- var unlimitedConnections = magnet.getAttribute('unlimitedConnections');
- var links = state.graph.getConnectedLinks(cellView.model);
- for (var i = 0; i < links.length; i++)
- {
- var link = links[i];
- if (link.attributes.source.id === cellView.model.id && link.attributes.source.port === magnet.attributes.port.nodeValue)
- {
- // This port already has a connection
- if (unlimitedConnections && link.attributes.target.id)
- {
- var targetCell = state.graph.getCell(link.attributes.target.id);
- if (unlimitedConnections.indexOf(targetCell.attributes.type) !== -1)
- return true; // It's okay because this target type has unlimited connections
- }
- return false;
- }
- }
- return true;
- };
- func.optimized_data = function()
- {
- var cells = state.graph.toJSON().cells;
- var nodesByID = {};
- var cellsByID = {};
- var nodes = [];
- for (var i = 0; i < cells.length; i++)
- {
- var cell = cells[i];
- if (cell.type != 'link')
- {
- var node =
- {
- type: cell.type.slice('dialogue.'.length),
- id: cell.id,
- };
- if (node.type === 'Branch')
- {
- node.variable = cell.name;
- node.branches = {};
- for (var j = 0; j < cell.values.length; j++)
- {
- var branch = cell.values[j];
- node.branches[branch] = null;
- }
- }
- else if (node.type === 'ConditionalBranch')
- {
- node.branches = {};
- for (var j = 0; j < cell.values.length; j++)
- {
- var branch = cell.values[j];
- node.branches[branch] = null;
- }
- }
- else if (node.type === 'Set')
- {
- node.variable = cell.name;
- node.value = cell.value;
- node.next = null;
- }
- else if (node.type === 'AIHook')
- {
- node.hooktype = cell.hooktype;
- node.identifier = cell.identifier;
- node.conditions = cell.conditions;
- node.next = null;
- }
- else
- {
- node.name = cell.name;
- node.next = null;
- }
- if (node.type === "Choice") {
- node.value = cell.value;
- }
- nodes.push(node);
- nodesByID[cell.id] = node;
- cellsByID[cell.id] = cell;
- }
- }
- for (var i = 0; i < cells.length; i++)
- {
- var cell = cells[i];
- if (cell.type === 'link')
- {
- var source = nodesByID[cell.source.id];
- var target = cell.target ? nodesByID[cell.target.id] : null;
- if (source)
- {
- if (source.type === 'Branch')
- {
- var portNumber = parseInt(cell.source.port.slice('output'.length));
- var value;
- if (portNumber === 0)
- value = '_default';
- else
- {
- var sourceCell = cellsByID[source.id];
- value = sourceCell.values[portNumber - 1];
- }
- source.branches[value] = target ? target.id : null;
- }
- else if ((source.type === 'Text' || source.type === 'Node' || source.type === 'StartNode') && target && target.type === 'Choice')
- {
- if (!source.choices)
- {
- source.choices = [];
- delete source.next;
- }
- source.choices.push(target.id);
- }
- else
- source.next = target ? target.id : null;
- }
- }
- }
- return nodes;
- };
- // Menu actions
- func.flash = function(text)
- {
- var $flash = $('#flash');
- $flash.text(text);
- $flash.stop(true, true);
- $flash.show();
- $flash.css('opacity', 1.0);
- $flash.fadeOut({ duration: 1500 });
- };
- func.apply_fields = function()
- {
- $('input[type=text], select').blur();
- };
- func.save = function()
- {
- func.apply_fields();
- if (!state.filepath)
- func.show_save_dialog();
- else
- func.do_save();
- };
- func.optimized_filename = function(f)
- {
- return f.substring(0, f.length - 2) + 'dlz';
- };
- func.perfect_typescript = function(f)
- {
- return f.substring(0, f.length - 2) + 'dl.ts';
- };
- func.just_name = function (f) {
- return f.substring(0, f.length - 3);
- };
- func.do_save = function()
- {
- if (state.filepath)
- {
- fs.writeFileSync(state.filepath, JSON.stringify(state.graph), 'utf8');
- //fs.writeFileSync(func.optimized_filename(state.filepath), JSON.stringify(func.optimized_data()), 'utf8');
- let name = func.just_name(func.filename_from_filepath(state.filepath));
- let cleants = "// File created automatically by custom Dialogger on " + new Date().toLocaleString() + "\n";
- cleants += "// Do not tamper with this file.\n// It will be replaced automatically by Dialogger and all changes will be lost.\n// Instead change " + name + ".dl.";
- cleants += "\nmodule DialogueTrees {\n export let " + name + " = (function () {\n";
- cleants += func.ts_data(func.optimized_data(), name).replace(/^/gm, ' ') + "\n return tree;\n })();\n}";
-
- fs.writeFileSync(func.perfect_typescript(state.filepath), cleants, 'utf8');
- func.flash('Saved ' + state.filepath);
- }
- };
- func.filename_from_filepath = function(f)
- {
- return f.replace(/^.*[\\\/]/, '');
- };
- func.show_open_dialog = function()
- {
- $('#file_open').click();
- };
- func.show_save_dialog = function()
- {
- $('#file_save').click();
- };
- func.add_node = function(constructor)
- {
- return function()
- {
- var container = $('#container')[0];
- var element = new constructor(
- {
- position: { x: state.context_position.x + container.scrollLeft, y: state.context_position.y + container.scrollTop },
- });
- state.graph.addCells([element]);
- };
- };
- func.clear = function()
- {
- state.graph.clear();
- state.filepath = null;
- document.title = 'Dialogger';
- };
- func.handle_open_files = function(files)
- {
- state.filepath = files[0].path;
- var data = fs.readFileSync(state.filepath);
- document.title = func.filename_from_filepath(state.filepath);
- state.graph.clear();
- state.graph.fromJSON(JSON.parse(data));
- };
- func.handle_save_files = function(files)
- {
- state.filepath = files[0].path;
- func.do_save();
- };
- func.ts_data = function(nodes, name) {
- let declarations = [];
- let addDeclaration = (dec) => {
- if (declarations.indexOf(dec) == -1) {
- declarations.push(dec);
- }
- }
- addDeclaration("let tree : DialogueTree = new DialogueTree(" + JSON.stringify(name) + ");\n");
-
- let finalString = "";
- for (let i = 0; i < nodes.length; i++) {
- finalString += "\n\n";
- let node = nodes[i];
- if (node.type == "Node") {
- finalString += "node = new DialogueNode(" + JSON.stringify(node.id) + ");\n";
- finalString += "node.setName(" + JSON.stringify(node.name) + ");\n";
- if (node.next != null && node.next != undefined) {
- finalString += "node.setNext(" + JSON.stringify(node.next) + ");\n";
- }
- if (node.choices != undefined && node.choices != null) {
- finalString += "node.setChoices(" + JSON.stringify(node.choices) + ");\n";
- }
- finalString += "tree.addNode(node);\n";
- addDeclaration("let node : DialogueNode;\n");
- } else if (node.type == "GoToLabel") {
- finalString += "node = new DialogueNode(" + JSON.stringify(node.id) + ");\n";
- finalString += "node.setNext(" + JSON.stringify(node.name) + ");\n";
- finalString += "tree.addNode(node);\n";
- addDeclaration("let node : DialogueNode;\n");
- } else if (node.type == "Tree") {
- finalString += "nodetree = new DialogueNodeTree(" + JSON.stringify(node.id) + ");\n";
- finalString += "nodetree.setTree(() => { return " + node.name + "; });\n";
- if (node.next != null && node.next != undefined) {
- finalString += "nodetree.setNext(" + JSON.stringify(node.next) + ");\n";
- }
- if (node.choices != undefined && node.choices != null) {
- finalString += "nodetree.setChoices(" + JSON.stringify(node.choices) + ");\n";
- }
- finalString += "tree.addNode(nodetree);\n";
- addDeclaration("let nodetree : DialogueNodeTree;\n");
- } else if (node.type == "StartNode") {
- finalString += "node = new DialogueNode(" + JSON.stringify(node.id) + ");\n";
- if (node.next != null && node.next != undefined) {
- finalString += "node.setNext(" + JSON.stringify(node.next) + ");\n";
- }
- if (node.choices != undefined && node.choices != null) {
- finalString += "node.setChoices(" + JSON.stringify(node.choices) + ");\n";
- }
- finalString += "tree.addStartNode(node);\n";
- addDeclaration("let node : DialogueNode;\n");
- } else if (node.type == "Text") {
- finalString += "text = new DialogueText(" + JSON.stringify(node.id) + ");\n";
- //finalString += "node.setSay(" + node.name + ");\n"; // this way all code we placed will be added right away!
- // SetSay needs to be a function, otherwise data might not be updated when printing!
- finalString += "text.setSay(() => { return new Say(" + node.name + ");});\n";
- if (node.next != null && node.next != undefined) {
- finalString += "text.setNext(" + JSON.stringify(node.next) + ");\n";
- }
- if (node.choices != undefined && node.choices != null) {
- finalString += "text.setChoices(" + JSON.stringify(node.choices) + ");\n";
- }
- finalString += "tree.addNode(text);\n";
- addDeclaration("let text : DialogueText;\n");
- } else if (node.type == "Choice") {
- finalString += "choice = new DialogueChoice(" + JSON.stringify(node.id) + ");\n";
- //finalString += "node.setSay(" + node.name + ");\n"; // this way all code we placed will be added right away!
- // SetSay needs to be a function, otherwise data might not be updated when printing!
- finalString += "choice.setSay(() => { return new Say(" + node.name + ");});\n";
- if (node.value != undefined && node.value != null && node.value != "") {
- finalString += "choice.setConditions(() => { return " + node.value + ";});\n"
- }
- if (node.next != null && node.next != undefined) {
- finalString += "choice.setNext(" + JSON.stringify(node.next) + ");\n";
- }
- if (node.choices != undefined && node.choices != null) {
- finalString += "choice.setChoices(" + JSON.stringify(node.choices) + ");\n";
- }
- finalString += "tree.addNode(choice);\n";
- addDeclaration("let choice : DialogueChoice;\n");
- } else if (node.type == "Branch") {
- finalString += "branch = new DialogueBranch(" + JSON.stringify(node.id) + ");\n";
- finalString += "branch.setVariable(() => { return " + node.variable + ";});\n";
- for (let key in node.branches) {
- let branchCondition = key;
- let branchTarget = node.branches[key];
- if (branchCondition == "_default") {
- finalString += "branch.setNext(" + JSON.stringify(branchTarget) + ");\n";
- } else {
- finalString += "branch.addBranch(" + JSON.stringify(branchTarget) + ", () => { return " + branchCondition + ";});\n";
- }
- }
- finalString += "tree.addNode(branch);\n";
- addDeclaration("let branch : DialogueBranch;\n");
- } else if (node.type == "ConditionalBranch") {
- finalString += "branch = new DialogueBranch(" + JSON.stringify(node.id) + ");\n";
- //finalString += "branch.setVariable(() => { return " + node.variable + ";});\n";
- for (let key in node.branches) {
- let branchCondition = key;
- let branchTarget = node.branches[key];
- if (branchCondition == "_default") {
- finalString += "branch.setNext(" + JSON.stringify(branchTarget) + ");\n";
- } else {
- finalString += "branch.addBranch(" + JSON.stringify(branchTarget) + ", () => { return " + branchCondition + ";});\n";
- }
- }
- finalString += "tree.addNode(branch);\n";
- addDeclaration("let branch : DialogueBranch;\n");
- } else if (node.type == "Set" || node.type == "Function") {
- finalString += "set = new DialogueSet(" + JSON.stringify(node.id) + ");\n";
- if (node.type == "Function") {
- finalString += "set.setFunction(() => {\n" + node.name + "\n});\n";
- } else {
- finalString += "set.setFunction(() => {\n " + node.variable + " = " + node.value + ";\n});\n";
- }
- if (node.next != null && node.next != undefined) {
- finalString += "set.setNext(" + JSON.stringify(node.next) + ");\n";
- }
- if (node.choices != undefined && node.choices != null) {
- finalString += "set.setChoices(" + JSON.stringify(node.choices) + ");\n";
- }
- finalString += "tree.addNode(set);\n";
- addDeclaration("let set : DialogueSet;\n");
- } else if (node.type == "AIHook") {
- // hooktype, identifier, conditions
- // AskAbout/Circumstance/Informative/Critical
- node.hooktype = node.hooktype != undefined ? node.hooktype : "";
- node.identifier = node.identifier != undefined ? node.identifier : "";
- node.conditions = node.conditions != undefined ? node.conditions : "";
- let hookType = node.hooktype.toLowerCase().trim();
- finalString += " AI." + (hookType == "askabout" ? "investigateRules" : "talktoRules") + ".createAndAddRule({\n" +
- " name : " + JSON.stringify("AIHook for " + name) + ",\n";
- finalString += " conditions : (runner : RulebookRunner<TalkingHeads>) => {\n" +
- " // @ts-ignore\n" +
- " let player = WorldState.player, greeter = runner.noun.greeter, answerer = runner.noun.answerer;\n" +
- "\n" +
- " return (" + node.conditions + ");\n" +
- " },\n";
- if (hookType == "critical" || hookType == "informative") {
- finalString += " priority : Rule.PRIORITY_HIGHEST,\n" +
- " firstPriority : Rule.PRIORITY_HIGHEST,\n";
- } else {
- finalString += " priority : Rule.PRIORITY_MEDIUM,\n" +
- " firstPriority : Rule.PRIORITY_MEDIUM,\n"
- }
- if (hookType == "informative") {
- finalString += " code : (runner : RulebookRunner<TalkingHeads>) => {\n" +
- " runner.noun.runFirst.push(tree);\n" +
- " },\n";
- } else if (hookType == "critical") {
- finalString += " code : (runner : RulebookRunner<TalkingHeads>) => {\n" +
- " runner.noun.runAndStop.push(tree);\n" +
- " },\n";
- } else {
- finalString += " code : (runner : RulebookRunner<TalkingHeads>) => {\n" +
- " runner.noun.options.push({\n" +
- " tree: tree,\n" +
- " text : new Say(" + node.identifier + ")\n" +
- " })\n" +
- " },\n";
- }
- finalString += "});\n\n";
- }
- }
- return declarations.join("") + finalString;
- };
- // Initialize
- (function()
- {
- state.paper = new joint.dia.Paper(
- {
- el: $('#paper'),
- width: 32000,
- height: 16000,
- model: state.graph,
- gridSize: 1,
- defaultLink: con.default_link,
- validateConnection: func.validate_connection,
- validateMagnet: func.validate_magnet,
- snapLinks: { radius: 75 }, // enable link snapping within 75px lookup radius
- markAvailable: true,
- });
- state.paper.on('blank:pointerdown', function(e, x, y)
- {
- if (e.button === 0 || e.button === 1)
- {
- state.panning = true;
- state.mouse_position.x = e.pageX;
- state.mouse_position.y = e.pageY;
- $('body').css('cursor', 'move');
- func.apply_fields();
- }
- });
- state.paper.on('cell:pointerdown', function(e, x, y)
- {
- func.apply_fields();
- });
- $('#container').mousemove(function(e)
- {
- if (state.panning)
- {
- var $this = $(this);
- $this.scrollLeft($this.scrollLeft() + state.mouse_position.x - e.pageX);
- $this.scrollTop($this.scrollTop() + state.mouse_position.y - e.pageY);
- state.mouse_position.x = e.pageX;
- state.mouse_position.y = e.pageY;
- }
- });
- $('#container').mouseup(function(e)
- {
- state.panning = false;
- $('body').css('cursor', 'default');
- });
- $('#file_open').on('change', function()
- {
- if (this.files)
- func.handle_open_files(this.files);
- // clear files from this input
- var $this = $(this);
- $this.wrap('<form>').parent('form').trigger('reset');
- $this.unwrap();
- });
- $('#file_save').on('change', function()
- {
- func.handle_save_files(this.files);
- });
- $('body').on('dragenter', function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- });
- $('body').on('dragexit', function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- });
- $('body').on('dragover', function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- });
- $('body').on('drop', function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- func.handle_open_files(e.originalEvent.dataTransfer.files);
- });
- $(window).on('keydown', function(event)
- {
- // Catch Ctrl-S or key code 19 on Mac (Cmd-S)
- if (((event.ctrlKey || event.metaKey) && String.fromCharCode(event.which).toLowerCase() === 's') || event.which === 19)
- {
- event.stopPropagation();
- event.preventDefault();
- func.save();
- return false;
- }
- else if ((event.ctrlKey || event.metaKey) && String.fromCharCode(event.which).toLowerCase() === 'o')
- {
- event.stopPropagation();
- event.preventDefault();
- func.show_open_dialog();
- return false;
- }
- return true;
- });
- $(window).resize(function()
- {
- func.apply_fields();
- var $window = $(window);
- var $container = $('#container');
- $container.height($window.innerHeight());
- $container.width($window.innerWidth());
- return this;
- });
- $(window).trigger('resize');
- // Context menu
- state.menu = new nw.Menu();
- state.menu.append(new nw.MenuItem({ label: 'Text', click: func.add_node(joint.shapes.dialogue.Text) }));
- state.menu.append(new nw.MenuItem({ label: 'Choice', click: func.add_node(joint.shapes.dialogue.Choice) }));
- state.menu.append(new nw.MenuItem({ label: 'Switch', click: func.add_node(joint.shapes.dialogue.Branch) }));
- state.menu.append(new nw.MenuItem({ label: 'Branch', click: func.add_node(joint.shapes.dialogue.ConditionalBranch) }));
- state.menu.append(new nw.MenuItem({ label: 'Set', click: func.add_node(joint.shapes.dialogue.Set) }));
- state.menu.append(new nw.MenuItem({ label: 'Function', click: func.add_node(joint.shapes.dialogue.Function) }));
- state.menu.append(new nw.MenuItem({ label: 'GoToLabel', click: func.add_node(joint.shapes.dialogue.GoToLabel) }));
- state.menu.append(new nw.MenuItem({ label: 'Tree', click: func.add_node(joint.shapes.dialogue.Tree) }));
- state.menu.append(new nw.MenuItem({ label: 'Label', click: func.add_node(joint.shapes.dialogue.Node) }));
- state.menu.append(new nw.MenuItem({ label: 'Start Point', click: func.add_node(joint.shapes.dialogue.StartNode) }));
- state.menu.append(new nw.MenuItem({ label: 'AI Hook', click: func.add_node(joint.shapes.dialogue.AIHook) }));
- state.menu.append(new nw.MenuItem({ type: 'separator' }));
- state.menu.append(new nw.MenuItem({ label: 'Save', click: func.save }));
- state.menu.append(new nw.MenuItem({ label: 'Open', click: func.show_open_dialog }));
- state.menu.append(new nw.MenuItem({ label: 'New', click: func.clear }));
- document.body.addEventListener('contextmenu', function(e)
- {
- e.preventDefault();
- state.context_position.x = e.x;
- state.context_position.y = e.y;
- state.menu.popup(e.x, e.y);
- return false;
- }, false);
- })();
- function updateTextareas () {
- window.requestAnimationFrame(updateTextareas);
- let textareas = new Array(...document.getElementsByTagName("textarea"));
- for (let i = 0; i < textareas.length; i++) {
- let textarea = textareas[i];
- textarea.style.height = "0 px";
- textarea.style.height = textarea.scrollHeight + "px";
- }
- }
- window.requestAnimationFrame(updateTextareas);
|