diff --git a/AndorsTrailEdit/editor.html b/AndorsTrailEdit/editor.html index adf6387fd..4a8c5570d 100644 --- a/AndorsTrailEdit/editor.html +++ b/AndorsTrailEdit/editor.html @@ -120,6 +120,7 @@ + diff --git a/AndorsTrailEdit/js/app.js b/AndorsTrailEdit/js/app.js index 57e218cad..63242c61e 100644 --- a/AndorsTrailEdit/js/app.js +++ b/AndorsTrailEdit/js/app.js @@ -12,6 +12,7 @@ var ATEditor = (function(ATEditor, controllers) { .when('/item/table', {templateUrl: htmldir+'table_item.html', controller: controllers.ItemTableController}) .when('/droplist/edit/:id', {templateUrl: htmldir+'edit_droplist.html', controller: controllers.DropListController}) .when('/dialogue/edit/:id', {templateUrl: htmldir+'edit_dialogue.html', controller: controllers.DialogueController}) + .when('/dialogue/tree/:id', {templateUrl: htmldir+'tree_dialogue.html', controller: controllers.DialogueShowTreeController}) .when('/monster/edit/:id', {templateUrl: htmldir+'edit_monster.html', controller: controllers.MonsterController}) .when('/monster/table', {templateUrl: htmldir+'table_monster.html', controller: controllers.MonsterTableController}) .when('/itemcategory/edit/:id', {templateUrl: htmldir+'edit_itemcategory.html', controller: controllers.ItemCategoryController}) diff --git a/AndorsTrailEdit/js/controllers/dialogue.js b/AndorsTrailEdit/js/controllers/dialogue.js index 1bdb3d017..6c63bd5d0 100644 --- a/AndorsTrailEdit/js/controllers/dialogue.js +++ b/AndorsTrailEdit/js/controllers/dialogue.js @@ -1,4 +1,4 @@ -var ATEditor = (function(ATEditor, model, defaults, importExport, _) { +var ATEditor = (function(ATEditor, model, defaults, importExport) { function DialogueController($scope, $routeParams) { $scope.datasource = model.dialogue; @@ -47,10 +47,13 @@ var ATEditor = (function(ATEditor, model, defaults, importExport, _) { phrase.replies.push(reply); $scope.reply = reply; }; + $scope.showPhraseTree = function(phrase) { + window.location = "#/" + model.dialogue.id + "/tree/" + phrase.id; + }; }; ATEditor.controllers = ATEditor.controllers || {}; ATEditor.controllers.DialogueController = DialogueController; return ATEditor; -})(ATEditor, ATEditor.model, ATEditor.defaults, ATEditor.importExport, _); +})(ATEditor, ATEditor.model, ATEditor.defaults, ATEditor.importExport); diff --git a/AndorsTrailEdit/js/controllers/dialoguetree.js b/AndorsTrailEdit/js/controllers/dialoguetree.js new file mode 100644 index 000000000..4e5c754a4 --- /dev/null +++ b/AndorsTrailEdit/js/controllers/dialoguetree.js @@ -0,0 +1,61 @@ +var ATEditor = (function(ATEditor, model, _) { + + function DialogueShowTreeController($scope, $routeParams) { + $scope.datasource = model.dialogue; + $scope.rootPhrase = $scope.datasource.findById($routeParams.id); + $scope.onclick = function(node) { + ATEditor.navigationFunctions.editObjId(model.dialogue, node.id); + }; + + function buildSingleTreeNode(type, id, text, children) { + return { + id: id || "" + ,text: text || "" + ,type: type + ,children: children || [] + }; + } + + function singleChild(n) { return n ? [n] : []; } + + function buildPhraseTree(phrase, visitedPhrases) { + if (!phrase) { return; } + if (visitedPhrases[phrase.id]) { + return buildSingleTreeNode("loop", phrase.id, phrase.message); + } + visitedPhrases[phrase.id] = true; + + var children; + if (phrase.hasOnlyNextReply) { + var nextNode = model.dialogue.findById(phrase.nextPhraseID); + children = singleChild(buildPhraseTree(nextNode, visitedPhrases)); + } else { + children = _.map(phrase.replies, function(reply) { + var replyChild; + if (reply.nextPhraseID.length == 1) { + replyChild = buildSingleTreeNode("action"); + } else { + var nextNode = model.dialogue.findById(reply.nextPhraseID); + replyChild = buildPhraseTree(nextNode, visitedPhrases); + } + + if (!reply.text) { + return replyChild || buildSingleTreeNode("reply", phrase.id, "(no text)"); + } + + return buildSingleTreeNode("reply", phrase.id, reply.text, singleChild(replyChild)); + }); + } + + var phraseText = phrase.message || "(conditional evaluation)"; + return buildSingleTreeNode("phrase", phrase.id, phraseText, children); + } + + $scope.node = buildPhraseTree($scope.rootPhrase, {}); + }; + + ATEditor.controllers = ATEditor.controllers || {}; + ATEditor.controllers.DialogueShowTreeController = DialogueShowTreeController; + + return ATEditor; +})(ATEditor, ATEditor.model, _); diff --git a/AndorsTrailEdit/js/directives.js b/AndorsTrailEdit/js/directives.js index 9534336a3..2cae818c5 100644 --- a/AndorsTrailEdit/js/directives.js +++ b/AndorsTrailEdit/js/directives.js @@ -84,6 +84,22 @@ var ATEditor = (function(ATEditor, app, tilesets, $) { } }); + + // http://jsfiddle.net/ag5zC/22/ + app.directive('treenode', function ($compile) { + var link; + return { + restrict: 'E', + terminal: true, + scope: { node: '=', onclick: '=' }, + link: function (scope, element, attrs) { + if(!link) { + link = $compile(element.html()); + } + element.replaceWith(link(scope.$new(), function(clone) { })); + } + } + }); return ATEditor; })(ATEditor, ATEditor.app, ATEditor.tilesets, jQuery); diff --git a/AndorsTrailEdit/partials/edit_dialogue.html b/AndorsTrailEdit/partials/edit_dialogue.html index bb466c4f4..5382badf0 100644 --- a/AndorsTrailEdit/partials/edit_dialogue.html +++ b/AndorsTrailEdit/partials/edit_dialogue.html @@ -2,6 +2,12 @@
NPC phrase + + +

+
diff --git a/AndorsTrailEdit/partials/tree_dialogue.html b/AndorsTrailEdit/partials/tree_dialogue.html new file mode 100644 index 000000000..f0e669758 --- /dev/null +++ b/AndorsTrailEdit/partials/tree_dialogue.html @@ -0,0 +1,17 @@ +

Dialogue Tree

+ +
+
  • +
    +
    + (conversation loop) + (action) + {{node.text}} + {{node.text}} +
    +
      +
    • +
    +
    +
+
diff --git a/AndorsTrailEdit/styles.css b/AndorsTrailEdit/styles.css index e7f9f061b..c4ddb5646 100644 --- a/AndorsTrailEdit/styles.css +++ b/AndorsTrailEdit/styles.css @@ -40,10 +40,28 @@ html, body { margin:0; padding:0; } .fieldWithLabel table tbody tr:hover { background-color: #d7d7ff; } table.tableeditor { margin-bottom: 20px; } -#dialogueTree { width: 400px; } -#dialogueTree ul { list-style: none; margin-left: 10px; } -#dialogueTree li { } -#dialogueTree .selected { background-color: #d7d7ff; } +#dialogueTree ul { padding-top: 20px; position: relative; margin-left: 0; } +#dialogueTree li { float: left; text-align: center; list-style-type: none; position: relative; padding: 20px 5px 0 5px; } +#dialogueTree li::before, #dialogueTree li::after + { content: ''; position: absolute; top: 0; right: 50%; border-top: 1px solid #ccc; width: 50%; height: 20px; } +#dialogueTree li::after { right: auto; left: 50%; border-left: 1px solid #ccc; } +#dialogueTree li:only-child::after, #dialogueTree li:only-child::before + { display: none; } +#dialogueTree li:only-child { padding-top: 0; } +#dialogueTree li:first-child::before, #dialogueTree li:last-child::after + { border: 0 none; } +#dialogueTree li:last-child::before { border-right: 1px solid #ccc; border-radius: 0 5px 0 0; -webkit-border-radius: 0 5px 0 0; -moz-border-radius: 0 5px 0 0; } +#dialogueTree li:first-child::after { border-radius: 5px 0 0 0; -webkit-border-radius: 5px 0 0 0; -moz-border-radius: 5px 0 0 0; } +#dialogueTree ul ul::before { content: ''; position: absolute; top: 0; left: 50%; border-left: 1px solid #ccc; width: 0; height: 20px; } +#dialogueTree .dialogue-node { + border: 1px solid #ccc; padding: 5px 10px; text-decoration: none; display: inline-block; max-width: 80px; + box-shadow: 1px 1px 5px #bbb; -moz-box-shadow: 1px 1px 5px #bbb; -webkit-box-shadow: 1px 1px 5px #bbb; + border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; +} +#dialogueTree .dialogue-node-reply { background-color: #ddffdd; } +#dialogueTree .dialogue-node-loop { background-color: #ffdddd; } +#dialogueTree .dialogue-node-action { background-color: #ffffcc; } + .dialogueConditional { color: #855; } .tools-buttons { padding-bottom: 10px; }