├── fonts ├── MI.TTF ├── Badaboom.ttf ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff └── glyphicons-halflings-regular.woff2 ├── icons ├── cc.png ├── arrow.png ├── bocca.png ├── cursor.png ├── exit.png ├── mano.png ├── occhi.png ├── arrow-up.png ├── cogwheel.png ├── cursor2.png ├── scissors.png ├── arrow-down.png ├── bocca-hover.png ├── depth-icon.png ├── mano-hover.png ├── occhi-hover.png ├── coord_picker.png ├── cursor-small.png ├── arrow-down-hover.png ├── arrow-up-hover.png ├── cogwheel-hover.png └── shoe-print-large-hi.png ├── css ├── select2.png ├── select2x2.png ├── jstree │ ├── 32px.png │ ├── 40px.png │ └── throbber.gif ├── select2-spinner.gif ├── jquery.inputfile.css ├── context.bootstrap.css ├── uploadfile.min.css ├── select2-bootstrap.css └── codemirror.css ├── bootstrap3-editable └── img │ ├── clear.png │ └── loading.gif ├── LICENSE.md ├── inputs-ext ├── address │ ├── address.css │ └── address.js ├── wysihtml5 │ ├── bootstrap-wysihtml5-0.0.2 │ │ ├── wysiwyg-color.css │ │ ├── bootstrap-wysihtml5-0.0.2.css │ │ └── bootstrap-wysihtml5-0.0.2.min.js │ └── wysihtml5.js └── typeaheadjs │ ├── lib │ └── typeahead.js-bootstrap.css │ └── typeaheadjs.js ├── js ├── variables-manager.js ├── audio-manager.js ├── character-manager.js ├── inventory-manager.js ├── dialog-manager.js ├── anims-manager.js ├── action-manager.js ├── jquery.inputfile.js ├── bootstrap.file-input.js ├── bootstrap-collapse.js ├── context.js ├── pathfinding.js ├── jquery-upload-file.php ├── room-manager.js ├── jquery.uploadfile.min.js ├── deepCopy.js ├── walkbox-manager.js ├── canvas-manager.js ├── utils.js ├── script-manager.js ├── project.js └── sideEffects-manager.js └── README.md /fonts/MI.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/fonts/MI.TTF -------------------------------------------------------------------------------- /icons/cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/cc.png -------------------------------------------------------------------------------- /css/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/css/select2.png -------------------------------------------------------------------------------- /icons/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/arrow.png -------------------------------------------------------------------------------- /icons/bocca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/bocca.png -------------------------------------------------------------------------------- /icons/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/cursor.png -------------------------------------------------------------------------------- /icons/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/exit.png -------------------------------------------------------------------------------- /icons/mano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/mano.png -------------------------------------------------------------------------------- /icons/occhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/occhi.png -------------------------------------------------------------------------------- /css/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/css/select2x2.png -------------------------------------------------------------------------------- /fonts/Badaboom.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/fonts/Badaboom.ttf -------------------------------------------------------------------------------- /icons/arrow-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/arrow-up.png -------------------------------------------------------------------------------- /icons/cogwheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/cogwheel.png -------------------------------------------------------------------------------- /icons/cursor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/cursor2.png -------------------------------------------------------------------------------- /icons/scissors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/scissors.png -------------------------------------------------------------------------------- /css/jstree/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/css/jstree/32px.png -------------------------------------------------------------------------------- /css/jstree/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/css/jstree/40px.png -------------------------------------------------------------------------------- /icons/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/arrow-down.png -------------------------------------------------------------------------------- /icons/bocca-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/bocca-hover.png -------------------------------------------------------------------------------- /icons/depth-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/depth-icon.png -------------------------------------------------------------------------------- /icons/mano-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/mano-hover.png -------------------------------------------------------------------------------- /icons/occhi-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/occhi-hover.png -------------------------------------------------------------------------------- /css/jstree/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/css/jstree/throbber.gif -------------------------------------------------------------------------------- /css/select2-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/css/select2-spinner.gif -------------------------------------------------------------------------------- /icons/coord_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/coord_picker.png -------------------------------------------------------------------------------- /icons/cursor-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/cursor-small.png -------------------------------------------------------------------------------- /icons/arrow-down-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/arrow-down-hover.png -------------------------------------------------------------------------------- /icons/arrow-up-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/arrow-up-hover.png -------------------------------------------------------------------------------- /icons/cogwheel-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/cogwheel-hover.png -------------------------------------------------------------------------------- /icons/shoe-print-large-hi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/icons/shoe-print-large-hi.png -------------------------------------------------------------------------------- /bootstrap3-editable/img/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/bootstrap3-editable/img/clear.png -------------------------------------------------------------------------------- /bootstrap3-editable/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/bootstrap3-editable/img/loading.gif -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RumRogers/GAUSS/HEAD/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This work is licensed under the Creative Commons Attribution 4.0 International License. 2 | To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/. 3 | -------------------------------------------------------------------------------- /inputs-ext/address/address.css: -------------------------------------------------------------------------------- 1 | .editable-address { 2 | display: block; 3 | margin-bottom: 5px; 4 | } 5 | 6 | .editable-address span { 7 | width: 70px; 8 | display: inline-block; 9 | } -------------------------------------------------------------------------------- /js/variables-manager.js: -------------------------------------------------------------------------------- 1 | var editorGameVars = {}; 2 | 3 | var addGameVar = function(varName, varValue) 4 | { 5 | editorGameVars[varName] = varValue; 6 | window[varName] = varValue; 7 | }; 8 | 9 | var deleteGameVar = function(varName) 10 | { 11 | delete editorGameVars[varName]; 12 | delete window[varName]; 13 | }; -------------------------------------------------------------------------------- /js/audio-manager.js: -------------------------------------------------------------------------------- 1 | var editorMapIdAudio = {}; 2 | var editorAudioCount = 0; 3 | 4 | var createNewAudioContent = function(id) 5 | { 6 | var newAudioContent = { id : id, audioData : null }; 7 | editorMapIdAudio[id] = newAudioContent; 8 | }; 9 | 10 | var deleteAudioContent = function(id) 11 | { 12 | delete editorMapIdAudio[id]; 13 | }; -------------------------------------------------------------------------------- /js/character-manager.js: -------------------------------------------------------------------------------- 1 | var editorCharactersList = []; 2 | var editorMapIdCharacter = {}; 3 | var editorCurrentCharacter = null; 4 | var editorPlayerCharacter = null; 5 | 6 | var createNewEditorCharacter = function(id) 7 | { 8 | var newCharacter = new EditorItem(id, 'character'); 9 | editorCharactersList.push(newCharacter); 10 | editorMapIdCharacter[newCharacter.id] = newCharacter; 11 | }; 12 | 13 | var deleteEditorCharacter = function(id) 14 | { 15 | var character = editorMapIdCharacter[id]; 16 | editorCharactersList.splice(editorCharactersList.indexOf(character), 1); 17 | delete editorMapIdCharacter[id]; 18 | }; -------------------------------------------------------------------------------- /js/inventory-manager.js: -------------------------------------------------------------------------------- 1 | var InventoryItem = function(id) 2 | { 3 | this.id = id; 4 | this.anim = null; 5 | this.description = ''; 6 | }; 7 | 8 | var editorInvItemList = []; 9 | var editorMapIdInvItem = {}; 10 | var editorInvItemCount = 0; 11 | 12 | var createNewInvItem = function(id) 13 | { 14 | var newInvItem = new InventoryItem(id); 15 | editorInvItemList.push(newInvItem); 16 | editorMapIdInvItem[newInvItem.id] = newInvItem; 17 | }; 18 | 19 | var deleteInvItem = function(id) 20 | { 21 | var invItem = editorMapIdInvItem[id]; 22 | editorInvItemList.splice(editorInvItemList.indexOf(invItem), 1); 23 | delete editorMapIdInvItem[id]; 24 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GAUSS 2 | ============= 3 | GAUSS stands for "Graphic Adventure Unified Scripting System" and was originally born as thesis for my master degree in computer science: 4 | in short, it's an engine to create graphic adventures in the style of the old LucasArts classics. 5 | GAUSS allows you to import resources, create your own scripts written in JavaScript to define the responses to the player's action and to test the game. 6 | Once you're OK with the result, the editor can export the game as an HTML page, ready to be uploaded and shared. 7 | In order to be playable once exported, the game package must at least include the generated HTML file, the js folder, the fonts folder and the icons folder. 8 | -------------------------------------------------------------------------------- /inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/wysiwyg-color.css: -------------------------------------------------------------------------------- 1 | .wysiwyg-color-black { 2 | color: black; 3 | } 4 | 5 | .wysiwyg-color-silver { 6 | color: silver; 7 | } 8 | 9 | .wysiwyg-color-gray { 10 | color: gray; 11 | } 12 | 13 | .wysiwyg-color-white { 14 | color: white; 15 | } 16 | 17 | .wysiwyg-color-maroon { 18 | color: maroon; 19 | } 20 | 21 | .wysiwyg-color-red { 22 | color: red; 23 | } 24 | 25 | .wysiwyg-color-purple { 26 | color: purple; 27 | } 28 | 29 | .wysiwyg-color-fuchsia { 30 | color: fuchsia; 31 | } 32 | 33 | .wysiwyg-color-green { 34 | color: green; 35 | } 36 | 37 | .wysiwyg-color-lime { 38 | color: lime; 39 | } 40 | 41 | .wysiwyg-color-olive { 42 | color: olive; 43 | } 44 | 45 | .wysiwyg-color-yellow { 46 | color: yellow; 47 | } 48 | 49 | .wysiwyg-color-navy { 50 | color: navy; 51 | } 52 | 53 | .wysiwyg-color-blue { 54 | color: blue; 55 | } 56 | 57 | .wysiwyg-color-teal { 58 | color: teal; 59 | } 60 | 61 | .wysiwyg-color-aqua { 62 | color: aqua; 63 | } 64 | 65 | .wysiwyg-color-orange { 66 | color: orange; 67 | } -------------------------------------------------------------------------------- /js/dialog-manager.js: -------------------------------------------------------------------------------- 1 | var editorMapIdDialog = {}; 2 | var editorDialogsCount = 0; 3 | 4 | var Dialog = function(id) 5 | { 6 | this.id = id; 7 | this.currentSubDialog = 'root'; 8 | this.subdialogs = { 'root' : [] }; 9 | this.hidden = false; 10 | }; 11 | 12 | //TODO: fix dialog lines ordering 13 | Dialog.prototype.addDialogChoice = function(subDialogId, choice, pos) 14 | { 15 | if(subDialogId.length == 0) 16 | subDialogId = 'root'; 17 | else if(this.subdialogs[subDialogId] == undefined) 18 | this.subdialogs[subDialogId] = []; 19 | if(!pos) 20 | { 21 | this.subdialogs[subDialogId].push(choice); 22 | return; 23 | } 24 | this.subdialogs[subDialogId].splice(pos, 0, choice); 25 | }; 26 | 27 | Dialog.prototype.removeDialogChoice = function(subDialogId, pos) 28 | { 29 | if(this.subdialogs[subDialogId] && this.subdialogs[subDialogId].length) 30 | this.subdialogs[subDialogId].splice(pos, 1); 31 | }; 32 | 33 | Dialog.prototype.copy = function(d) 34 | { 35 | this.id = d.id; 36 | this.currentSubDialog = d.currentSubDialog; 37 | this.subdialogs = d.subdialogs; 38 | }; 39 | 40 | var DialogChoice = function(text, script, quit, open, hidden, showOnce, hideOnce) 41 | { 42 | this.sentence = text; 43 | this.script = script; 44 | this.quit = quit; 45 | this.open = open; 46 | this.hidden = hidden; 47 | this.showOnce = showOnce; 48 | this.chooseOnce = hideOnce; 49 | }; 50 | 51 | var deleteDialog = function(id) 52 | { 53 | delete editorMapIdDialog[id]; 54 | }; 55 | 56 | -------------------------------------------------------------------------------- /css/jquery.inputfile.css: -------------------------------------------------------------------------------- 1 | .inputfile { 2 | display: inline-block; 3 | margin-bottom: 2px; 4 | } 5 | 6 | .inputfile .upload-button { 7 | display: inline-block; 8 | position: relative; 9 | } 10 | 11 | .inputfile .upload-button input[type="file"] { 12 | left: 0; 13 | height: 100%; 14 | opacity: 0; 15 | position: absolute; 16 | top: 0; 17 | width: 100%; 18 | } 19 | 20 | .inputfile .previous-file { 21 | display: inline-block; 22 | } 23 | 24 | .inputfile .previous-file .upload-button-link { 25 | margin-right: 4px; 26 | display: inline-block; 27 | direction: rtl; 28 | max-width: 360px; 29 | overflow: visible; 30 | height: 24px; 31 | text-align: right; 32 | white-space: nowrap; 33 | } 34 | 35 | .inputfile .previous-file .upload-button-link[href="#"] { 36 | cursor: default; 37 | text-decoration: none; 38 | } 39 | 40 | .inputfile .previous-file .upload-button-remove { 41 | margin-right: 15px; 42 | } 43 | 44 | 45 | .inputfile .previous-file .upload-button-remove .remove-icon { 46 | display: inline-block; 47 | } 48 | 49 | .inputfile .previous-file .upload-button-remove .restore-icon { 50 | display: none; 51 | } 52 | 53 | .inputfile .previous-file.deleted .upload-button-link { 54 | color: #999; 55 | text-decoration: line-through; 56 | } 57 | 58 | .inputfile .previous-file.deleted .upload-button-remove .remove-icon { 59 | display: none; 60 | } 61 | 62 | .inputfile .previous-file.deleted .upload-button-remove .restore-icon { 63 | display: inline-block; 64 | } -------------------------------------------------------------------------------- /inputs-ext/typeaheadjs/lib/typeahead.js-bootstrap.css: -------------------------------------------------------------------------------- 1 | .twitter-typeahead .tt-query, 2 | .twitter-typeahead .tt-hint { 3 | margin-bottom: 0; 4 | } 5 | 6 | .tt-dropdown-menu { 7 | min-width: 160px; 8 | margin-top: 2px; 9 | padding: 5px 0; 10 | background-color: #fff; 11 | border: 1px solid #ccc; 12 | border: 1px solid rgba(0,0,0,.2); 13 | *border-right-width: 2px; 14 | *border-bottom-width: 2px; 15 | -webkit-border-radius: 6px; 16 | -moz-border-radius: 6px; 17 | border-radius: 6px; 18 | -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 19 | -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 20 | box-shadow: 0 5px 10px rgba(0,0,0,.2); 21 | -webkit-background-clip: padding-box; 22 | -moz-background-clip: padding; 23 | background-clip: padding-box; 24 | } 25 | 26 | .tt-suggestion { 27 | display: block; 28 | padding: 3px 20px; 29 | } 30 | 31 | .tt-suggestion.tt-is-under-cursor { 32 | color: #fff; 33 | background-color: #0081c2; 34 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 35 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 36 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 37 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 38 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 39 | background-repeat: repeat-x; 40 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0) 41 | } 42 | 43 | .tt-suggestion.tt-is-under-cursor a { 44 | color: #fff; 45 | } 46 | 47 | .tt-suggestion p { 48 | margin: 0; 49 | } 50 | -------------------------------------------------------------------------------- /js/anims-manager.js: -------------------------------------------------------------------------------- 1 | var Anim = function(id) 2 | { 3 | this.id = id; 4 | this.frames = new Array(); 5 | this.loop = true; 6 | this.start_idx = 0; 7 | this.animInt = null; 8 | this.current_frame = this.start_idx; 9 | this.frame_rate = 150; 10 | this.addFrame = addAnimFrame; 11 | this.removeFrame = removeAnimFrame; 12 | this.incrCurrIdx = incrCurrFrame; 13 | this.play = startRollingFrames; 14 | this.stop = stopRollingFrames; 15 | }; 16 | 17 | var addAnimFrame = function(idx, image) 18 | { 19 | this.frames[idx] = image; 20 | }; 21 | 22 | var removeAnimFrame = function(idx) 23 | { 24 | this.frames.splice(idx, 1); 25 | }; 26 | 27 | var incrCurrFrame = function() 28 | { 29 | this.current_frame = (this.current_frame + 1) % this.frames.length; 30 | }; 31 | 32 | var createNewAnim = function(id) 33 | { 34 | var newAnim = new Anim(id); 35 | editorAnimsList.push(newAnim); 36 | editorMapIdAnim[id] = newAnim; 37 | }; 38 | 39 | var startRollingFrames = function() 40 | { 41 | if(this.animInt) 42 | return; 43 | var that = this; 44 | this.animInt = setInterval(function() 45 | { 46 | if(that.loop === false && that.current_frame === that.frames.length - 1) 47 | { 48 | clearInterval(that.animInt); 49 | that.animInt = null; 50 | return; 51 | } 52 | that.incrCurrIdx(); 53 | }, that.frame_rate); 54 | }; 55 | 56 | var stopRollingFrames = function() 57 | { 58 | clearInterval(this.animInt); 59 | this.animInt = null; 60 | this.current_frame = this.start_idx; 61 | }; 62 | 63 | var editorAnimsList = []; 64 | var editorMapIdAnim = {}; 65 | var editorAnimsCount = 0; 66 | 67 | var deleteEditorAnim = function(id) 68 | { 69 | var anim = editorMapIdAnim[id]; 70 | editorAnimsList.splice(editorCharactersList.indexOf(anim), 1); 71 | delete editorMapIdAnim[id]; 72 | }; 73 | 74 | 75 | -------------------------------------------------------------------------------- /css/context.bootstrap.css: -------------------------------------------------------------------------------- 1 | /** 2 | * ContextJS Styles 3 | * For use with Twitters Bootstrap CSS 4 | */ 5 | 6 | .dropdown-context .nav-header{ 7 | cursor:default; 8 | } 9 | .dropdown-context:before, .dropdown-context-up:before { 10 | position: absolute; 11 | top: -7px; 12 | left: 9px; 13 | display: inline-block; 14 | border-right: 7px solid transparent; 15 | border-bottom: 7px solid #ccc; 16 | border-left: 7px solid transparent; 17 | border-bottom-color: rgba(0, 0, 0, 0.2); 18 | content: ''; 19 | } 20 | .dropdown-context:after, .dropdown-context-up:after{ 21 | position: absolute; 22 | top: -6px; 23 | left: 10px; 24 | display: inline-block; 25 | border-right: 6px solid transparent; 26 | border-bottom: 6px solid #ffffff; 27 | border-left: 6px solid transparent; 28 | content: ''; 29 | } 30 | .dropdown-context-up:before, .dropdown-context-up:after{ 31 | top:auto; 32 | bottom:-7px; 33 | z-index:9999; 34 | } 35 | .dropdown-context-up:before{ 36 | border-right: 7px solid transparent; 37 | border-top: 7px solid #ccc; 38 | border-bottom:none; 39 | border-left: 7px solid transparent; 40 | } 41 | .dropdown-context-up:after{ 42 | border-right: 6px solid transparent; 43 | border-top: 6px solid #ffffff; 44 | border-left: 6px solid transparent; 45 | border-bottom:none; 46 | } 47 | 48 | .dropdown-context-sub:before, .dropdown-context-sub:after{ 49 | display:none; 50 | } 51 | .dropdown-context .dropdown-submenu:hover .dropdown-menu { 52 | display: none; 53 | } 54 | 55 | .dropdown-context .dropdown-submenu:hover > .dropdown-menu { 56 | display: block; 57 | } 58 | 59 | 60 | .compressed-context a{ 61 | padding-left: 14px; 62 | padding-top: 0; 63 | padding-bottom: 0; 64 | font-size: 13px; 65 | } 66 | .compressed-context .divider{ 67 | margin: 5px 1px; 68 | } 69 | .compressed-context .nav-header{ 70 | padding:1px 13px; 71 | } -------------------------------------------------------------------------------- /css/uploadfile.min.css: -------------------------------------------------------------------------------- 1 | .ajax-file-upload-statusbar{border:1px solid #0ba1b5;margin-top:10px;width:420px;margin-right:10px;margin:5px;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;padding:5px 5px 5px 5px}.ajax-file-upload-filename{width:100%;height:auto;margin:0 5px 5px 10px;color:#807579}.ajax-file-upload-progress{margin:0 10px 5px 10px;position:relative;width:250px;border:1px solid #ddd;padding:1px;border-radius:3px;display:inline-block}.ajax-file-upload-bar{background-color:#0ba1b5;width:0;height:20px;border-radius:3px}.ajax-file-upload-percent{position:absolute;display:inline-block;top:3px;left:48%}.ajax-file-upload-red{-moz-box-shadow:inset 0 39px 0 -24px #e67a73;-webkit-box-shadow:inset 0 39px 0 -24px #e67a73;box-shadow:inset 0 39px 0 -24px #e67a73;background-color:#e4685d;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;display:inline-block;color:#fff;font-family:arial;font-size:13px;font-weight:normal;padding:4px 15px;text-decoration:none;text-shadow:0 1px 0 #b23e35;cursor:pointer;vertical-align:top;margin-right:5px}.ajax-file-upload-green{background-color:#77b55a;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;margin:0;padding:0;display:inline-block;color:#fff;font-family:arial;font-size:13px;font-weight:normal;padding:4px 15px;text-decoration:none;cursor:pointer;text-shadow:0 1px 0 #5b8a3c;vertical-align:top;margin-right:5px}.ajax-file-upload{font-family:Arial,Helvetica,sans-serif;font-size:16px;font-weight:bold;padding:15px 20px;cursor:pointer;line-height:20px;height:25px;margin:0 10px 10px 0;display:inline-block;background:#fff;border:1px solid #e8e8e8;color:#888;text-decoration:none;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;-moz-box-shadow:0 2px 0 0 #e8e8e8;-webkit-box-shadow:0 2px 0 0 #e8e8e8;box-shadow:0 2px 0 0 #e8e8e8;padding:6px 10px 4px 10px;color:#fff;background:#2f8ab9;border:0;-moz-box-shadow:0 2px 0 0 #13648d;-webkit-box-shadow:0 2px 0 0 #13648d;box-shadow:0 2px 0 0 #13648d;vertical-align:middle}.ajax-file-upload:hover{background:#3396c9;-moz-box-shadow:0 2px 0 0 #15719f;-webkit-box-shadow:0 2px 0 0 #15719f;box-shadow:0 2px 0 0 #15719f}.ajax-upload-dragdrop{border:2px dotted #a5a5c7;width:420px;color:#dadce3;text-align:left;vertical-align:middle;padding:10px 10px 0 10px} -------------------------------------------------------------------------------- /js/action-manager.js: -------------------------------------------------------------------------------- 1 | var Action = function(id) 2 | { 3 | this.id = id; 4 | this.description = ''; 5 | }; 6 | 7 | Action.prototype.setDescription = function(desc) 8 | { 9 | this.description = desc; 10 | }; 11 | 12 | var editorActionsList = new Array(); 13 | var editorMapIdAction = {}; 14 | var editorActionsCount = 0; 15 | 16 | var createNewEditorAction = function(id, desc) 17 | { 18 | var newAction = new Action(id); 19 | if(desc) 20 | newAction.setDescription(desc); 21 | editorActionsList.push(newAction); 22 | editorMapIdAction[newAction.id] = newAction; 23 | }; 24 | 25 | var WALK_TO_ID = 'Walk_to'; 26 | var EYES_ID = 'Eyes'; 27 | var HAND_ID = 'Hand'; 28 | var MOUTH_ID = 'Mouth'; 29 | var COMBINE_ID = 'Combine'; 30 | 31 | var DEFAULT_WALK_TO_SENTENCE = 'Walk to'; 32 | var DEFAULT_EYES_SENTENCE = 'Look at'; 33 | var DEFAULT_HAND_SENTENCE = 'Pick up'; 34 | var DEFAULT_MOUTH_SENTENCE = 'Talk to'; 35 | var DEFAULT_COMBINE_SENTENCE = 'Combine'; 36 | 37 | createNewEditorAction(WALK_TO_ID, DEFAULT_WALK_TO_SENTENCE); 38 | createNewEditorAction(EYES_ID, DEFAULT_EYES_SENTENCE); 39 | createNewEditorAction(HAND_ID, DEFAULT_HAND_SENTENCE); 40 | createNewEditorAction(MOUTH_ID, DEFAULT_MOUTH_SENTENCE); 41 | createNewEditorAction(COMBINE_ID, DEFAULT_COMBINE_SENTENCE); 42 | 43 | var defaultSentences = {}; 44 | defaultSentences[HAND_ID] = [ 'I can\'t pick that up.', 'I don\'t need it.', 'That doesn\'t seem to work.', 'I can\'t use that.', 'Nah.']; 45 | defaultSentences[EYES_ID] = [ 'I don\'t see anything special about it.', 'Cool.' ]; 46 | defaultSentences[MOUTH_ID] = [ 'Not a chatterbox.', 'I don\'t think it\'s going to answer.' ]; 47 | defaultSentences[COMBINE_ID] = [ 'That doesn\'t seem to work.' ]; 48 | 49 | var defaultReactions = {}; 50 | defaultReactions[HAND_ID] = 'var set = defaultSentences["' + HAND_ID + '"]; var idx = Math.floor(Math.random() * set.length); egoSayLine(set[idx])'; 51 | defaultReactions[EYES_ID] = 'var set = defaultSentences["' + EYES_ID + '"]; var idx = Math.floor(Math.random() * set.length); egoSayLine(set[idx])'; 52 | defaultReactions[MOUTH_ID] = 'var set = defaultSentences["' + MOUTH_ID + '"]; var idx = Math.floor(Math.random() * set.length); egoSayLine(set[idx])'; 53 | defaultReactions[COMBINE_ID] = 'var set = defaultSentences["' + COMBINE_ID +'"]; var idx = Math.floor(Math.random() * set.length); egoSayLine(set[idx])'; 54 | -------------------------------------------------------------------------------- /inputs-ext/typeaheadjs/typeaheadjs.js: -------------------------------------------------------------------------------- 1 | /** 2 | Typeahead.js input, based on [Twitter Typeahead](http://twitter.github.io/typeahead.js). 3 | It is mainly replacement of typeahead in Bootstrap 3. 4 | 5 | 6 | @class typeaheadjs 7 | @extends text 8 | @since 1.5.0 9 | @final 10 | @example 11 | 12 | 30 | **/ 31 | (function ($) { 32 | "use strict"; 33 | 34 | var Constructor = function (options) { 35 | this.init('typeaheadjs', options, Constructor.defaults); 36 | }; 37 | 38 | $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.text); 39 | 40 | $.extend(Constructor.prototype, { 41 | render: function() { 42 | this.renderClear(); 43 | this.setClass(); 44 | this.setAttr('placeholder'); 45 | this.$input.typeahead(this.options.typeahead); 46 | 47 | // copy `input-sm | input-lg` classes to placeholder input 48 | if($.fn.editableform.engine === 'bs3') { 49 | if(this.$input.hasClass('input-sm')) { 50 | this.$input.siblings('input.tt-hint').addClass('input-sm'); 51 | } 52 | if(this.$input.hasClass('input-lg')) { 53 | this.$input.siblings('input.tt-hint').addClass('input-lg'); 54 | } 55 | } 56 | } 57 | }); 58 | 59 | Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, { 60 | /** 61 | @property tpl 62 | @default 63 | **/ 64 | tpl:'', 65 | /** 66 | Configuration of typeahead itself. 67 | [Full list of options](https://github.com/twitter/typeahead.js#dataset). 68 | 69 | @property typeahead 70 | @type object 71 | @default null 72 | **/ 73 | typeahead: null, 74 | /** 75 | Whether to show `clear` button 76 | 77 | @property clear 78 | @type boolean 79 | @default true 80 | **/ 81 | clear: true 82 | }); 83 | 84 | $.fn.editabletypes.typeaheadjs = Constructor; 85 | 86 | }(window.jQuery)); -------------------------------------------------------------------------------- /inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.css: -------------------------------------------------------------------------------- 1 | ul.wysihtml5-toolbar { 2 | margin: 0; 3 | padding: 0; 4 | display: block; 5 | } 6 | 7 | ul.wysihtml5-toolbar::after { 8 | clear: both; 9 | display: table; 10 | content: ""; 11 | } 12 | 13 | ul.wysihtml5-toolbar > li { 14 | float: left; 15 | display: list-item; 16 | list-style: none; 17 | margin: 0 5px 10px 0; 18 | } 19 | 20 | ul.wysihtml5-toolbar a[data-wysihtml5-command=bold] { 21 | font-weight: bold; 22 | } 23 | 24 | ul.wysihtml5-toolbar a[data-wysihtml5-command=italic] { 25 | font-style: italic; 26 | } 27 | 28 | ul.wysihtml5-toolbar a[data-wysihtml5-command=underline] { 29 | text-decoration: underline; 30 | } 31 | 32 | ul.wysihtml5-toolbar a.btn.wysihtml5-command-active { 33 | background-image: none; 34 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 35 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 36 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 37 | background-color: #E6E6E6; 38 | background-color: #D9D9D9; 39 | outline: 0; 40 | } 41 | 42 | ul.wysihtml5-commands-disabled .dropdown-menu { 43 | display: none !important; 44 | } 45 | 46 | ul.wysihtml5-toolbar div.wysihtml5-colors { 47 | display:block; 48 | width: 50px; 49 | height: 20px; 50 | margin-top: 2px; 51 | margin-left: 5px; 52 | position: absolute; 53 | pointer-events: none; 54 | } 55 | 56 | ul.wysihtml5-toolbar a.wysihtml5-colors-title { 57 | padding-left: 70px; 58 | } 59 | 60 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="black"] { 61 | background: black !important; 62 | } 63 | 64 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="silver"] { 65 | background: silver !important; 66 | } 67 | 68 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="gray"] { 69 | background: gray !important; 70 | } 71 | 72 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="maroon"] { 73 | background: maroon !important; 74 | } 75 | 76 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="red"] { 77 | background: red !important; 78 | } 79 | 80 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="purple"] { 81 | background: purple !important; 82 | } 83 | 84 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="green"] { 85 | background: green !important; 86 | } 87 | 88 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="olive"] { 89 | background: olive !important; 90 | } 91 | 92 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="navy"] { 93 | background: navy !important; 94 | } 95 | 96 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="blue"] { 97 | background: blue !important; 98 | } 99 | 100 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="orange"] { 101 | background: orange !important; 102 | } 103 | -------------------------------------------------------------------------------- /css/select2-bootstrap.css: -------------------------------------------------------------------------------- 1 | .form-control .select2-choice { 2 | border: 0; 3 | border-radius: 2px; 4 | } 5 | 6 | .form-control .select2-choice .select2-arrow { 7 | border-radius: 0 2px 2px 0; 8 | } 9 | 10 | .form-control.select2-container { 11 | height: auto !important; 12 | padding: 0; 13 | } 14 | 15 | .form-control.select2-container.select2-dropdown-open { 16 | border-color: #5897FB; 17 | border-radius: 3px 3px 0 0; 18 | } 19 | 20 | .form-control .select2-container.select2-dropdown-open .select2-choices { 21 | border-radius: 3px 3px 0 0; 22 | } 23 | 24 | .form-control.select2-container .select2-choices { 25 | border: 0 !important; 26 | border-radius: 3px; 27 | } 28 | 29 | .control-group.warning .select2-container .select2-choice, 30 | .control-group.warning .select2-container .select2-choices, 31 | .control-group.warning .select2-container-active .select2-choice, 32 | .control-group.warning .select2-container-active .select2-choices, 33 | .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice, 34 | .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices, 35 | .control-group.warning .select2-container-multi.select2-container-active .select2-choices { 36 | border: 1px solid #C09853 !important; 37 | } 38 | 39 | .control-group.warning .select2-container .select2-choice div { 40 | border-left: 1px solid #C09853 !important; 41 | background: #FCF8E3 !important; 42 | } 43 | 44 | .control-group.error .select2-container .select2-choice, 45 | .control-group.error .select2-container .select2-choices, 46 | .control-group.error .select2-container-active .select2-choice, 47 | .control-group.error .select2-container-active .select2-choices, 48 | .control-group.error .select2-dropdown-open.select2-drop-above .select2-choice, 49 | .control-group.error .select2-dropdown-open.select2-drop-above .select2-choices, 50 | .control-group.error .select2-container-multi.select2-container-active .select2-choices { 51 | border: 1px solid #B94A48 !important; 52 | } 53 | 54 | .control-group.error .select2-container .select2-choice div { 55 | border-left: 1px solid #B94A48 !important; 56 | background: #F2DEDE !important; 57 | } 58 | 59 | .control-group.info .select2-container .select2-choice, 60 | .control-group.info .select2-container .select2-choices, 61 | .control-group.info .select2-container-active .select2-choice, 62 | .control-group.info .select2-container-active .select2-choices, 63 | .control-group.info .select2-dropdown-open.select2-drop-above .select2-choice, 64 | .control-group.info .select2-dropdown-open.select2-drop-above .select2-choices, 65 | .control-group.info .select2-container-multi.select2-container-active .select2-choices { 66 | border: 1px solid #3A87AD !important; 67 | } 68 | 69 | .control-group.info .select2-container .select2-choice div { 70 | border-left: 1px solid #3A87AD !important; 71 | background: #D9EDF7 !important; 72 | } 73 | 74 | .control-group.success .select2-container .select2-choice, 75 | .control-group.success .select2-container .select2-choices, 76 | .control-group.success .select2-container-active .select2-choice, 77 | .control-group.success .select2-container-active .select2-choices, 78 | .control-group.success .select2-dropdown-open.select2-drop-above .select2-choice, 79 | .control-group.success .select2-dropdown-open.select2-drop-above .select2-choices, 80 | .control-group.success .select2-container-multi.select2-container-active .select2-choices { 81 | border: 1px solid #468847 !important; 82 | } 83 | 84 | .control-group.success .select2-container .select2-choice div { 85 | border-left: 1px solid #468847 !important; 86 | background: #DFF0D8 !important; 87 | } 88 | -------------------------------------------------------------------------------- /inputs-ext/wysihtml5/wysihtml5.js: -------------------------------------------------------------------------------- 1 | /** 2 | Bootstrap wysihtml5 editor. Based on [bootstrap-wysihtml5](https://github.com/jhollingworth/bootstrap-wysihtml5). 3 | You should include **manually** distributives of `wysihtml5` and `bootstrap-wysihtml5`: 4 | 5 | 6 | 7 | 8 | 9 | And also include `wysihtml5.js` from `inputs-ext` directory of x-editable: 10 | 11 | 12 | 13 | **Note:** It's better to use fresh bootstrap-wysihtml5 from it's [master branch](https://github.com/jhollingworth/bootstrap-wysihtml5/tree/master/src) as there is update for correct image insertion. 14 | 15 | @class wysihtml5 16 | @extends abstractinput 17 | @final 18 | @since 1.4.0 19 | @example 20 |

awesome

comment!
21 | 29 | **/ 30 | (function ($) { 31 | "use strict"; 32 | 33 | var Wysihtml5 = function (options) { 34 | this.init('wysihtml5', options, Wysihtml5.defaults); 35 | 36 | //extend wysihtml5 manually as $.extend not recursive 37 | this.options.wysihtml5 = $.extend({}, Wysihtml5.defaults.wysihtml5, options.wysihtml5); 38 | }; 39 | 40 | $.fn.editableutils.inherit(Wysihtml5, $.fn.editabletypes.abstractinput); 41 | 42 | $.extend(Wysihtml5.prototype, { 43 | render: function () { 44 | var deferred = $.Deferred(), 45 | msieOld; 46 | 47 | //generate unique id as it required for wysihtml5 48 | this.$input.attr('id', 'textarea_'+(new Date()).getTime()); 49 | 50 | this.setClass(); 51 | this.setAttr('placeholder'); 52 | 53 | //resolve deffered when widget loaded 54 | $.extend(this.options.wysihtml5, { 55 | events: { 56 | load: function() { 57 | deferred.resolve(); 58 | } 59 | } 60 | }); 61 | 62 | this.$input.wysihtml5(this.options.wysihtml5); 63 | 64 | /* 65 | In IE8 wysihtml5 iframe stays on the same line with buttons toolbar (inside popover). 66 | The only solution I found is to add
. If you fine better way, please send PR. 67 | */ 68 | msieOld = /msie\s*(8|7|6)/.test(navigator.userAgent.toLowerCase()); 69 | if(msieOld) { 70 | this.$input.before('

'); 71 | } 72 | 73 | return deferred.promise(); 74 | }, 75 | 76 | value2html: function(value, element) { 77 | $(element).html(value); 78 | }, 79 | 80 | html2value: function(html) { 81 | return html; 82 | }, 83 | 84 | value2input: function(value) { 85 | this.$input.data("wysihtml5").editor.setValue(value, true); 86 | }, 87 | 88 | activate: function() { 89 | this.$input.data("wysihtml5").editor.focus(); 90 | }, 91 | 92 | isEmpty: function($element) { 93 | if($.trim($element.html()) === '') { 94 | return true; 95 | } else if($.trim($element.text()) !== '') { 96 | return false; 97 | } else { 98 | //e.g. '', '
', '

' 99 | return !$element.height() || !$element.width(); 100 | } 101 | } 102 | }); 103 | 104 | Wysihtml5.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 105 | /** 106 | @property tpl 107 | @default 108 | **/ 109 | tpl:'', 110 | /** 111 | @property inputclass 112 | @default editable-wysihtml5 113 | **/ 114 | inputclass: 'editable-wysihtml5', 115 | /** 116 | Placeholder attribute of input. Shown when input is empty. 117 | 118 | @property placeholder 119 | @type string 120 | @default null 121 | **/ 122 | placeholder: null, 123 | /** 124 | Wysihtml5 default options. 125 | See https://github.com/jhollingworth/bootstrap-wysihtml5#options 126 | 127 | @property wysihtml5 128 | @type object 129 | @default {stylesheets: false} 130 | **/ 131 | wysihtml5: { 132 | stylesheets: false //see https://github.com/jhollingworth/bootstrap-wysihtml5/issues/183 133 | } 134 | }); 135 | 136 | $.fn.editabletypes.wysihtml5 = Wysihtml5; 137 | 138 | }(window.jQuery)); 139 | -------------------------------------------------------------------------------- /js/jquery.inputfile.js: -------------------------------------------------------------------------------- 1 | /*jslint browser:true */ 2 | /*global jQuery */ 3 | 4 | (function ($) { 5 | 6 | "use strict"; 7 | 8 | var methods = {}, 9 | BASE_CLASS = 'inputfile', 10 | BUTTON_CLASS = 'upload-button', 11 | PREVIOUS_CLASS = 'previous-file', 12 | DELETED_CLASS = 'deleted', 13 | LINK_CLASS = 'upload-button-link', 14 | REMOVE_CLASS = 'upload-button-remove'; 15 | 16 | function selectFile(evt) { 17 | 18 | var $input = $(evt.currentTarget), 19 | $base = $input.parents('.' + BASE_CLASS), 20 | $div = $base.find('.' + PREVIOUS_CLASS), 21 | $link = $div.find('a'), 22 | $checkbox = $base.find('input[type="checkbox"]'); 23 | 24 | $div.show(); 25 | 26 | $checkbox.attr('disabled', 'disabled'); 27 | $div.removeClass(DELETED_CLASS); 28 | 29 | $link.attr('href', '#'); 30 | //$link.html($input.val()); 31 | $link.html($input.val().split('C:\\fakepath\\')[1]); 32 | $link.on('click', function () { return false; }); 33 | } 34 | 35 | function removeSelectedFile(evt) { 36 | var $button = $(evt.currentTarget), 37 | $base = $button.parents('.' + BASE_CLASS), 38 | $file = $base.find('input[type="file"]'), 39 | $parent = $button.parent(), 40 | $link = $parent.find('a'), 41 | $checkbox = $base.find('input[type="checkbox"]'); 42 | 43 | if ($file.attr('data-value')) { 44 | if ($parent.hasClass(DELETED_CLASS)) { 45 | $checkbox.removeAttr('checked'); 46 | $checkbox.attr('disabled', 'disabled'); 47 | 48 | $parent.removeClass(DELETED_CLASS); 49 | } else { 50 | 51 | if ($link.attr('href') !== $file.attr('data-value')) { 52 | $link.attr('href', $file.attr('data-value')); 53 | $link.html($file.attr('data-text')); 54 | } else { 55 | $checkbox.attr('checked', 'checked'); 56 | $checkbox.removeAttr('disabled'); 57 | 58 | $parent.addClass(DELETED_CLASS); 59 | } 60 | } 61 | 62 | } else { 63 | $parent.hide(); 64 | $parent.addClass(DELETED_CLASS); 65 | 66 | $checkbox.removeAttr('disabled', 'disabled'); 67 | $link.html(''); 68 | $file.replaceWith($file.clone(true)); 69 | } 70 | 71 | return false; 72 | } 73 | 74 | function init(params) { 75 | 76 | this.each(function () { 77 | 78 | var $self = $(this), 79 | fileUrl = $self.data('value'), 80 | fileText = $self.data('text'), 81 | config = $.extend({}, $self.inputfile.config, params), 82 | $button, 83 | $base, 84 | $previous, 85 | $link, 86 | $remove, 87 | removeName, 88 | $checkbox, 89 | $fileButton; 90 | 91 | // Set the html 92 | $self.wrap('
'); 93 | 94 | $button = $self.parent(); 95 | $base = $button.parent(); 96 | 97 | $previous = $('
').prependTo($base); 98 | $link = $('').appendTo($previous); 99 | 100 | if (!params.dontRemove) { 101 | $remove = $('').appendTo($previous); 102 | 103 | $remove.append($(config.removeText).addClass('remove-icon')); 104 | $remove.append($(config.restoreText).addClass('restore-icon')); 105 | 106 | removeName = config.removeName || $self.attr('name'); 107 | $checkbox = $(''); 108 | 109 | $checkbox.hide().appendTo($remove); 110 | } 111 | 112 | if (!fileUrl) { 113 | $previous.hide(); 114 | } else { 115 | $link.attr('href', fileUrl); 116 | $link.html(fileText || fileUrl); 117 | } 118 | 119 | $fileButton = $('').insertBefore($self); 120 | 121 | // Event listeners 122 | $self.on('change', selectFile); 123 | 124 | if ($remove) { 125 | $remove.on('click', removeSelectedFile); 126 | } 127 | }); 128 | } 129 | 130 | $.fn.inputfile = function (method) { 131 | 132 | if (methods[method]) { 133 | return methods[method].apply($(this), Array.prototype.slice.call(arguments, 1)); 134 | } else if (!method || (method && method.constructor === Object)) { 135 | return init.apply(this, arguments); 136 | } 137 | }; 138 | 139 | $.fn.inputfile.config = { 140 | uploadText: ' Upload file', 141 | removeText: '', 142 | restoreText: '', 143 | 144 | uploadButtonClass: 'btn', 145 | removeButtonClass: 'btn', 146 | 147 | removeName: '', 148 | removeValue: 1, 149 | 150 | dontRemove: false 151 | }; 152 | 153 | }(jQuery)); -------------------------------------------------------------------------------- /js/bootstrap.file-input.js: -------------------------------------------------------------------------------- 1 | /* 2 | Bootstrap - File Input 3 | ====================== 4 | 5 | This is meant to convert all file input tags into a set of elements that displays consistently in all browsers. 6 | 7 | Converts all 8 | 9 | into Bootstrap buttons 10 | Browse 11 | 12 | */ 13 | (function($) { 14 | 15 | $.fn.bootstrapFileInput = function() { 16 | 17 | this.each(function(i,elem){ 18 | 19 | var $elem = $(elem); 20 | 21 | // Maybe some fields don't need to be standardized. 22 | if (typeof $elem.attr('data-bfi-disabled') != 'undefined') { 23 | return; 24 | } 25 | 26 | // Set the word to be displayed on the button 27 | var buttonWord = 'Browse'; 28 | 29 | if (typeof $elem.attr('title') != 'undefined') { 30 | buttonWord = $elem.attr('title'); 31 | } 32 | 33 | var className = ''; 34 | 35 | if (!!$elem.attr('class')) { 36 | className = ' ' + $elem.attr('class'); 37 | } 38 | 39 | // Now we're going to wrap that input field with a Bootstrap button. 40 | // The input will actually still be there, it will just be float above and transparent (done with the CSS). 41 | $elem.wrap('').parent().prepend($('').html(buttonWord)); 42 | }) 43 | 44 | // After we have found all of the file inputs let's apply a listener for tracking the mouse movement. 45 | // This is important because the in order to give the illusion that this is a button in FF we actually need to move the button from the file input under the cursor. Ugh. 46 | .promise().done( function(){ 47 | 48 | // As the cursor moves over our new Bootstrap button we need to adjust the position of the invisible file input Browse button to be under the cursor. 49 | // This gives us the pointer cursor that FF denies us 50 | $('.file-input-wrapper').mousemove(function(cursor) { 51 | 52 | var input, wrapper, 53 | wrapperX, wrapperY, 54 | inputWidth, inputHeight, 55 | cursorX, cursorY; 56 | 57 | // This wrapper element (the button surround this file input) 58 | wrapper = $(this); 59 | // The invisible file input element 60 | input = wrapper.find("input"); 61 | // The left-most position of the wrapper 62 | wrapperX = wrapper.offset().left; 63 | // The top-most position of the wrapper 64 | wrapperY = wrapper.offset().top; 65 | // The with of the browsers input field 66 | inputWidth= input.width(); 67 | // The height of the browsers input field 68 | inputHeight= input.height(); 69 | //The position of the cursor in the wrapper 70 | cursorX = cursor.pageX; 71 | cursorY = cursor.pageY; 72 | 73 | //The positions we are to move the invisible file input 74 | // The 20 at the end is an arbitrary number of pixels that we can shift the input such that cursor is not pointing at the end of the Browse button but somewhere nearer the middle 75 | moveInputX = cursorX - wrapperX - inputWidth + 20; 76 | // Slides the invisible input Browse button to be positioned middle under the cursor 77 | moveInputY = cursorY- wrapperY - (inputHeight/2); 78 | 79 | // Apply the positioning styles to actually move the invisible file input 80 | input.css({ 81 | left:moveInputX, 82 | top:moveInputY 83 | }); 84 | }); 85 | 86 | $('body').on('change', '.file-input-wrapper input[type=file]', function(){ 87 | 88 | var fileName; 89 | fileName = $(this).val(); 90 | 91 | // Remove any previous file names 92 | $(this).parent().next('.file-input-name').remove(); 93 | if (!!$(this).prop('files') && $(this).prop('files').length > 1) { 94 | fileName = $(this)[0].files.length+' files'; 95 | } 96 | else { 97 | fileName = fileName.substring(fileName.lastIndexOf('\\') + 1, fileName.length); 98 | } 99 | 100 | // Don't try to show the name if there is none 101 | if (!fileName) { 102 | return; 103 | } 104 | 105 | var selectedFileNamePlacement = $(this).data('filename-placement'); 106 | if (selectedFileNamePlacement === 'inside') { 107 | // Print the fileName inside 108 | $(this).siblings('span').html(fileName); 109 | $(this).attr('title', fileName); 110 | } else { 111 | // Print the fileName aside (right after the the button) 112 | $(this).parent().after(''+fileName+''); 113 | } 114 | }); 115 | 116 | }); 117 | 118 | }; 119 | 120 | // Add the styles before the first stylesheet 121 | // This ensures they can be easily overridden with developer styles 122 | var cssHtml = ''; 127 | $('link[rel=stylesheet]').eq(0).before(cssHtml); 128 | 129 | })(jQuery); 130 | -------------------------------------------------------------------------------- /js/bootstrap-collapse.js: -------------------------------------------------------------------------------- 1 | /* ============================================================= 2 | * bootstrap-collapse.js v2.0.3 3 | * http://twitter.github.com/bootstrap/javascript.html#collapse 4 | * ============================================================= 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | 21 | !function ($) { 22 | 23 | "use strict"; // jshint ;_; 24 | 25 | 26 | /* COLLAPSE PUBLIC CLASS DEFINITION 27 | * ================================ */ 28 | 29 | var Collapse = function (element, options) { 30 | this.$element = $(element) 31 | this.options = $.extend({}, $.fn.collapse.defaults, options) 32 | 33 | if (this.options.parent) { 34 | this.$parent = $(this.options.parent) 35 | } 36 | 37 | this.options.toggle && this.toggle() 38 | } 39 | 40 | Collapse.prototype = { 41 | 42 | constructor: Collapse 43 | 44 | , dimension: function () { 45 | var hasWidth = this.$element.hasClass('width') 46 | return hasWidth ? 'width' : 'height' 47 | } 48 | 49 | , show: function () { 50 | var dimension 51 | , scroll 52 | , actives 53 | , hasData 54 | 55 | if (this.transitioning) return 56 | 57 | dimension = this.dimension() 58 | scroll = $.camelCase(['scroll', dimension].join('-')) 59 | actives = this.$parent && this.$parent.find('> .accordion-group > .in') 60 | 61 | if (actives && actives.length) { 62 | hasData = actives.data('collapse') 63 | if (hasData && hasData.transitioning) return 64 | actives.collapse('hide') 65 | hasData || actives.data('collapse', null) 66 | } 67 | 68 | this.$element[dimension](0) 69 | this.transition('addClass', $.Event('show'), 'shown') 70 | this.$element[dimension](this.$element[0][scroll]) 71 | } 72 | 73 | , hide: function () { 74 | var dimension 75 | if (this.transitioning) return 76 | dimension = this.dimension() 77 | this.reset(this.$element[dimension]()) 78 | this.transition('removeClass', $.Event('hide'), 'hidden') 79 | this.$element[dimension](0) 80 | } 81 | 82 | , reset: function (size) { 83 | var dimension = this.dimension() 84 | 85 | this.$element 86 | .removeClass('collapse') 87 | [dimension](size || 'auto') 88 | [0].offsetWidth 89 | 90 | this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') 91 | 92 | return this 93 | } 94 | 95 | , transition: function (method, startEvent, completeEvent) { 96 | var that = this 97 | , complete = function () { 98 | if (startEvent.type == 'show') that.reset() 99 | that.transitioning = 0 100 | that.$element.trigger(completeEvent) 101 | } 102 | 103 | this.$element.trigger(startEvent) 104 | 105 | if (startEvent.isDefaultPrevented()) return 106 | 107 | this.transitioning = 1 108 | 109 | this.$element[method]('in') 110 | 111 | $.support.transition && this.$element.hasClass('collapse') ? 112 | this.$element.one($.support.transition.end, complete) : 113 | complete() 114 | } 115 | 116 | , toggle: function () { 117 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 118 | } 119 | 120 | } 121 | 122 | 123 | /* COLLAPSIBLE PLUGIN DEFINITION 124 | * ============================== */ 125 | 126 | $.fn.collapse = function (option) { 127 | return this.each(function () { 128 | var $this = $(this) 129 | , data = $this.data('collapse') 130 | , options = typeof option == 'object' && option 131 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) 132 | if (typeof option == 'string') data[option]() 133 | }) 134 | } 135 | 136 | $.fn.collapse.defaults = { 137 | toggle: true 138 | } 139 | 140 | $.fn.collapse.Constructor = Collapse 141 | 142 | 143 | /* COLLAPSIBLE DATA-API 144 | * ==================== */ 145 | 146 | $(function () { 147 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { 148 | var $this = $(this), href 149 | , target = $this.attr('data-target') 150 | || e.preventDefault() 151 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 152 | , option = $(target).data('collapse') ? 'toggle' : $this.data() 153 | $(target).collapse(option) 154 | }) 155 | }) 156 | 157 | }(window.jQuery); -------------------------------------------------------------------------------- /js/context.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Context.js 3 | * Copyright Jacob Kelley 4 | * MIT License 5 | */ 6 | 7 | var context = context || (function () { 8 | 9 | var options = { 10 | fadeSpeed: 100, 11 | filter: function ($obj) { 12 | // Modify $obj, Do not return 13 | }, 14 | above: 'auto', 15 | preventDoubleContext: true, 16 | compress: false 17 | }; 18 | 19 | function initialize(opts) { 20 | 21 | options = $.extend({}, options, opts); 22 | 23 | $(document).on('click', 'html', function () { 24 | $('.dropdown-context').fadeOut(options.fadeSpeed, function(){ 25 | $('.dropdown-context').css({display:''}).find('.drop-left').removeClass('drop-left'); 26 | }); 27 | }); 28 | if(options.preventDoubleContext){ 29 | $(document).on('contextmenu', '.dropdown-context', function (e) { 30 | e.preventDefault(); 31 | }); 32 | } 33 | $(document).on('mouseenter', '.dropdown-submenu', function(){ 34 | var $sub = $(this).find('.dropdown-context-sub:first'), 35 | subWidth = $sub.width(), 36 | subLeft = $sub.offset().left, 37 | collision = (subWidth+subLeft) > window.innerWidth; 38 | if(collision){ 39 | $sub.addClass('drop-left'); 40 | } 41 | }); 42 | 43 | } 44 | 45 | function updateOptions(opts){ 46 | options = $.extend({}, options, opts); 47 | } 48 | 49 | function buildMenu(data, id, subMenu) { 50 | var subClass = (subMenu) ? ' dropdown-context-sub' : '', 51 | compressed = options.compress ? ' compressed-context' : '', 52 | $menu = $(''); 53 | var i = 0, linkTarget = ''; 54 | for(i; i'); 57 | } else if (typeof data[i].header !== 'undefined') { 58 | $menu.append(''); 59 | } else { 60 | if (typeof data[i].href == 'undefined') { 61 | data[i].href = '#'; 62 | } 63 | if (typeof data[i].target !== 'undefined') { 64 | linkTarget = ' target="'+data[i].target+'"'; 65 | } 66 | if (typeof data[i].subMenu !== 'undefined') { 67 | $sub = (''); 68 | } else { 69 | $sub = $('
  • ' + data[i].text + '
  • '); 70 | } 71 | if (typeof data[i].action !== 'undefined') { 72 | var actiond = new Date(), 73 | actionID = 'event-' + actiond.getTime() * Math.floor(Math.random()*100000), 74 | eventAction = data[i].action; 75 | $sub.find('a').attr('id', actionID); 76 | $('#' + actionID).addClass('context-event'); 77 | $(document).on('click', '#' + actionID, eventAction); 78 | } 79 | $menu.append($sub); 80 | if (typeof data[i].subMenu != 'undefined') { 81 | var subMenuData = buildMenu(data[i].subMenu, id, true); 82 | $menu.find('li:last').append(subMenuData); 83 | } 84 | } 85 | if (typeof options.filter == 'function') { 86 | options.filter($menu.find('li:last')); 87 | } 88 | } 89 | return $menu; 90 | } 91 | 92 | function addContext(selector, data) { 93 | 94 | var d = new Date(), 95 | id = d.getTime(), 96 | $menu = buildMenu(data, id); 97 | 98 | $('body').append($menu); 99 | 100 | 101 | $(document).on('contextmenu', selector, function (e) { 102 | e.preventDefault(); 103 | e.stopPropagation(); 104 | 105 | $('.dropdown-context:not(.dropdown-context-sub)').hide(); 106 | 107 | $dd = $('#dropdown-' + id); 108 | if (typeof options.above == 'boolean' && options.above) { 109 | $dd.addClass('dropdown-context-up').css({ 110 | top: e.pageY - 20 - $('#dropdown-' + id).height(), 111 | left: e.pageX - 13 112 | }).fadeIn(options.fadeSpeed); 113 | } else if (typeof options.above == 'string' && options.above == 'auto') { 114 | $dd.removeClass('dropdown-context-up'); 115 | var autoH = $dd.height() + 12; 116 | if ((e.pageY + autoH) > $('html').height()) { 117 | $dd.addClass('dropdown-context-up').css({ 118 | top: e.pageY - 20 - autoH, 119 | left: e.pageX - 13 120 | }).fadeIn(options.fadeSpeed); 121 | } else { 122 | $dd.css({ 123 | top: e.pageY + 10, 124 | left: e.pageX - 13 125 | }).fadeIn(options.fadeSpeed); 126 | } 127 | } 128 | }); 129 | } 130 | 131 | function destroyContext(selector) { 132 | $(document).off('contextmenu', selector).off('click', '.context-event'); 133 | } 134 | 135 | return { 136 | init: initialize, 137 | settings: updateOptions, 138 | attach: addContext, 139 | destroy: destroyContext 140 | }; 141 | })(); -------------------------------------------------------------------------------- /inputs-ext/address/address.js: -------------------------------------------------------------------------------- 1 | /** 2 | Address editable input. 3 | Internally value stored as {city: "Moscow", street: "Lenina", building: "15"} 4 | 5 | @class address 6 | @extends abstractinput 7 | @final 8 | @example 9 | awesome 10 | 23 | **/ 24 | (function ($) { 25 | "use strict"; 26 | 27 | var Address = function (options) { 28 | this.init('address', options, Address.defaults); 29 | }; 30 | 31 | //inherit from Abstract input 32 | $.fn.editableutils.inherit(Address, $.fn.editabletypes.abstractinput); 33 | 34 | $.extend(Address.prototype, { 35 | /** 36 | Renders input from tpl 37 | 38 | @method render() 39 | **/ 40 | render: function() { 41 | this.$input = this.$tpl.find('input'); 42 | }, 43 | 44 | /** 45 | Default method to show value in element. Can be overwritten by display option. 46 | 47 | @method value2html(value, element) 48 | **/ 49 | value2html: function(value, element) { 50 | if(!value) { 51 | $(element).empty(); 52 | return; 53 | } 54 | var html = $('
    ').text(value.city).html() + ', ' + $('
    ').text(value.street).html() + ' st., bld. ' + $('
    ').text(value.building).html(); 55 | $(element).html(html); 56 | }, 57 | 58 | /** 59 | Gets value from element's html 60 | 61 | @method html2value(html) 62 | **/ 63 | html2value: function(html) { 64 | /* 65 | you may write parsing method to get value by element's html 66 | e.g. "Moscow, st. Lenina, bld. 15" => {city: "Moscow", street: "Lenina", building: "15"} 67 | but for complex structures it's not recommended. 68 | Better set value directly via javascript, e.g. 69 | editable({ 70 | value: { 71 | city: "Moscow", 72 | street: "Lenina", 73 | building: "15" 74 | } 75 | }); 76 | */ 77 | return null; 78 | }, 79 | 80 | /** 81 | Converts value to string. 82 | It is used in internal comparing (not for sending to server). 83 | 84 | @method value2str(value) 85 | **/ 86 | value2str: function(value) { 87 | var str = ''; 88 | if(value) { 89 | for(var k in value) { 90 | str = str + k + ':' + value[k] + ';'; 91 | } 92 | } 93 | return str; 94 | }, 95 | 96 | /* 97 | Converts string to value. Used for reading value from 'data-value' attribute. 98 | 99 | @method str2value(str) 100 | */ 101 | str2value: function(str) { 102 | /* 103 | this is mainly for parsing value defined in data-value attribute. 104 | If you will always set value by javascript, no need to overwrite it 105 | */ 106 | return str; 107 | }, 108 | 109 | /** 110 | Sets value of input. 111 | 112 | @method value2input(value) 113 | @param {mixed} value 114 | **/ 115 | value2input: function(value) { 116 | if(!value) { 117 | return; 118 | } 119 | this.$input.filter('[name="city"]').val(value.city); 120 | this.$input.filter('[name="street"]').val(value.street); 121 | this.$input.filter('[name="building"]').val(value.building); 122 | }, 123 | 124 | /** 125 | Returns value of input. 126 | 127 | @method input2value() 128 | **/ 129 | input2value: function() { 130 | return { 131 | city: this.$input.filter('[name="city"]').val(), 132 | street: this.$input.filter('[name="street"]').val(), 133 | building: this.$input.filter('[name="building"]').val() 134 | }; 135 | }, 136 | 137 | /** 138 | Activates input: sets focus on the first field. 139 | 140 | @method activate() 141 | **/ 142 | activate: function() { 143 | this.$input.filter('[name="city"]').focus(); 144 | }, 145 | 146 | /** 147 | Attaches handler to submit form in case of 'showbuttons=false' mode 148 | 149 | @method autosubmit() 150 | **/ 151 | autosubmit: function() { 152 | this.$input.keydown(function (e) { 153 | if (e.which === 13) { 154 | $(this).closest('form').submit(); 155 | } 156 | }); 157 | } 158 | }); 159 | 160 | Address.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 161 | tpl: '
    '+ 162 | '
    '+ 163 | '
    ', 164 | 165 | inputclass: '' 166 | }); 167 | 168 | $.fn.editabletypes.address = Address; 169 | 170 | }(window.jQuery)); -------------------------------------------------------------------------------- /js/pathfinding.js: -------------------------------------------------------------------------------- 1 | var SearchGraphNode = function() 2 | { 3 | this.g = Number.MAX_VALUE; 4 | this.h = null; 5 | this.f = function() { return this.g + this.h; }; 6 | this.walkbox = null; 7 | this.parentIdx = null; 8 | }; 9 | 10 | var PathFinder = function() 11 | { 12 | this.open = []; 13 | this.closed = []; 14 | this.getHighestPriorityNodeIndex = function() 15 | { 16 | var minF = Number.MAX_VALUE; 17 | var idx; 18 | 19 | for(var i = 0; i < this.open.length; i++) 20 | { 21 | var curr = this.open[i]; 22 | if(curr.f() < minF) 23 | { 24 | minF = curr.f(); 25 | idx = i; 26 | } 27 | } 28 | return idx; 29 | }; 30 | this.getClosedNodeNearestToGoal = function() 31 | { 32 | var minH = Number.MAX_VALUE; 33 | var idx; 34 | 35 | for(var i = 0; i < this.closed.length; i++) 36 | { 37 | var curr = this.closed[i]; 38 | if(curr.h < minH) 39 | { 40 | minH = curr.f(); 41 | idx = i; 42 | } 43 | } 44 | return this.closed[idx]; 45 | }; 46 | 47 | this.walkboxIdxInsideList = function(wb, which) 48 | { 49 | var list = which == 'open' ? this.open : this.closed; 50 | for(var i = 0; i < list.length; i++) 51 | if(wb.id === list[i].walkbox.id) 52 | return i; 53 | return -1; 54 | }; 55 | this.aStar = function(nodes, startPoint, destPoint) 56 | { 57 | var getNearestEndpoint = function(edge, p) 58 | { 59 | var dist1 = getDistanceFromPoints(edge[0], p); 60 | var dist2 = getDistanceFromPoints(edge[1], p); 61 | 62 | if(dist1 < dist2) 63 | return edge[0]; 64 | return edge[1]; 65 | }; 66 | var getNearestPointInWalkBox = function(point, skipInvisible) 67 | { 68 | var tmp = new Point(point.x, point.y); 69 | var minDist = Infinity; 70 | var p; 71 | for(var i in nodes) 72 | { 73 | if(skipInvisible === true && nodes[i].visible === false) 74 | continue; 75 | p = nodes[i].polygon.getNearestPoint(point); 76 | var dist = getDistanceBetweenPoints(p, point); 77 | if (dist < minDist) 78 | { 79 | minDist = dist; 80 | tmp = new Point(p.x, p.y); 81 | } 82 | } 83 | return tmp; 84 | }; 85 | var start; 86 | var tmp = new Point(startPoint.x, startPoint.y); 87 | start = getWalkboxFromPoint(nodes, tmp); 88 | if(!start) 89 | { 90 | start = getNearestWalkBox(nodes, tmp); 91 | if (!start) 92 | { 93 | alert("SEVERE PATHFINDING ERROR"); 94 | return []; 95 | } 96 | } 97 | 98 | tmp = new Point(destPoint.x, destPoint.y); 99 | var goal = getWalkboxFromPoint(nodes, tmp); 100 | if(!goal) 101 | { 102 | tmp = getNearestPointInWalkBox(tmp, true); 103 | goal = getNearestWalkBox(nodes, tmp, true); 104 | if(!goal) 105 | { 106 | alert("SEVERE PATHFINDING ERROR"); 107 | return []; 108 | } 109 | 110 | } 111 | destPoint = new Point(tmp.x, tmp.y); 112 | 113 | if(startPoint.x === destPoint.x && startPoint.y === destPoint.y) 114 | return []; 115 | 116 | tmp = start.polygon.centroid; 117 | var startPos = new paper.Point(tmp.x, tmp.y); 118 | tmp = goal.polygon.centroid; 119 | var goalPos = new paper.Point(tmp.x, tmp.y); 120 | 121 | var s = new SearchGraphNode(); 122 | s.walkbox = start; 123 | s.g = 0; 124 | s.h = startPos.getDistance(goalPos); 125 | s.parentIdx = -1; 126 | 127 | this.open.push(s); 128 | var goalFound = false; 129 | while(!goalFound) 130 | { 131 | var highestPriorityIndex = this.getHighestPriorityNodeIndex(); 132 | var currNode = this.open[highestPriorityIndex]; 133 | if(!currNode) // disconnected node 134 | break; 135 | 136 | if(currNode.walkbox.id === goal.id) 137 | { 138 | goalFound = true; 139 | break; 140 | } 141 | this.open.splice(highestPriorityIndex, 1); 142 | this.closed.push(currNode); 143 | 144 | var currNeighborsIds = currNode.walkbox.neighbors; 145 | var currNeighbors = []; 146 | for(var i = 0; i < currNeighborsIds.length; i++) 147 | currNeighbors.push(nodes[currNeighborsIds[i].wbId]); 148 | 149 | for(var i = 0; i < currNeighbors.length; i++) 150 | { 151 | var neighbor = new SearchGraphNode(); 152 | neighbor.walkbox = currNeighbors[i]; 153 | var currNodeCenter = currNode.walkbox.polygon.centroid; 154 | var neighborCenter = neighbor.walkbox.polygon.centroid; 155 | var distance = currNodeCenter.getDistance(neighborCenter); 156 | var cost = currNode.g + distance; 157 | var neighborIdxInOpenList = this.walkboxIdxInsideList(neighbor.walkbox, 'open'); 158 | var neighborIdxInClosedList = this.walkboxIdxInsideList(neighbor.walkbox, 'closed'); 159 | 160 | if(neighborIdxInOpenList != -1 && cost < this.open[neighborIdxInOpenList].g) 161 | { 162 | this.open.splice(neighborIdxInOpenList, 1); 163 | neighborIdxInOpenList = -1; 164 | } 165 | if(neighborIdxInOpenList == -1 && neighborIdxInClosedList == -1) 166 | { 167 | neighbor.g = cost; 168 | neighbor.h = neighborCenter.getDistance(goalPos); 169 | neighbor.parentIdx = this.closed.indexOf(currNode); 170 | this.open.push(neighbor); 171 | } 172 | } 173 | } 174 | var walkBoxesToTraverse = []; 175 | var node = this.open[this.getHighestPriorityNodeIndex()]; 176 | if(!node) // disconnected node, start from the nearest visited node 177 | walkBoxesToTraverse.push(this.getClosedNodeNearestToGoal().walkbox.id); 178 | while(node && node.parentIdx != -1 && this.closed[node.parentIdx].walkbox != start) 179 | { 180 | node = this.closed[node.parentIdx]; 181 | walkBoxesToTraverse.unshift(node.walkbox.id); 182 | } 183 | 184 | walkBoxesToTraverse.push(goal.id); 185 | 186 | this.open = []; 187 | this.closed = []; 188 | 189 | var shortestPath = []; 190 | var currWB = start.id; 191 | 192 | var startGoalEdge = [startPoint, destPoint]; 193 | for(var i = 0; i < walkBoxesToTraverse.length; i++) 194 | { 195 | var nextWb = walkBoxesToTraverse[i]; 196 | var commonEdge = getCommonEdge(nodes[currWB], nodes[nextWb]); 197 | if(!commonEdge) 198 | { 199 | if(currWB !== nextWb) 200 | destPoint = nodes[currWB].polygon.getNearestPoint(destPoint); 201 | break; 202 | } 203 | var nextWayPoint = checkLineIntersection(startGoalEdge, commonEdge); 204 | if(!nextWayPoint.inLines) 205 | nextWayPoint = getNearestEndpoint(getCommonEdge(nodes[currWB], nodes[nextWb]), nextWayPoint); 206 | nextWayPoint = new Point(nextWayPoint.x, nextWayPoint.y); 207 | if(nodes[nextWb].visible === false) 208 | { 209 | destPoint = nextWayPoint; 210 | break; 211 | } 212 | shortestPath.push(nextWayPoint); 213 | currWB = nextWb; 214 | } 215 | 216 | shortestPath.push(destPoint); 217 | return shortestPath; 218 | }; 219 | }; 220 | //TODO: modify the Open and Closed list with a hashmap in order to access an element in O(1) -------------------------------------------------------------------------------- /css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 300px; 7 | border: 1px solid #000000; 8 | cursor: text; 9 | } 10 | 11 | /* PADDING */ 12 | 13 | .CodeMirror-lines { 14 | padding: 4px 0; /* Vertical padding around content */ 15 | } 16 | .CodeMirror pre { 17 | padding: 0 4px; /* Horizontal padding of content */ 18 | } 19 | 20 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 21 | background-color: white; /* The little square between H and V scrollbars */ 22 | } 23 | 24 | /* GUTTER */ 25 | 26 | .CodeMirror-gutters { 27 | border-right: 1px solid #ddd; 28 | background-color: #f7f7f7; 29 | white-space: nowrap; 30 | } 31 | .CodeMirror-linenumbers {} 32 | .CodeMirror-linenumber { 33 | padding: 0 3px 0 5px; 34 | min-width: 20px; 35 | text-align: right; 36 | color: #999; 37 | -moz-box-sizing: content-box; 38 | box-sizing: content-box; 39 | } 40 | 41 | .CodeMirror-guttermarker { color: black; } 42 | .CodeMirror-guttermarker-subtle { color: #999; } 43 | 44 | /* CURSOR */ 45 | 46 | .CodeMirror div.CodeMirror-cursor { 47 | border-left: 1px solid black; 48 | } 49 | /* Shown when moving in bi-directional text */ 50 | .CodeMirror div.CodeMirror-secondarycursor { 51 | border-left: 1px solid silver; 52 | } 53 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursor { 54 | width: auto; 55 | border: 0; 56 | background: #7e7; 57 | } 58 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursors { 59 | z-index: 1; 60 | } 61 | 62 | .cm-animate-fat-cursor { 63 | width: auto; 64 | border: 0; 65 | -webkit-animation: blink 1.06s steps(1) infinite; 66 | -moz-animation: blink 1.06s steps(1) infinite; 67 | animation: blink 1.06s steps(1) infinite; 68 | } 69 | @-moz-keyframes blink { 70 | 0% { background: #7e7; } 71 | 50% { background: none; } 72 | 100% { background: #7e7; } 73 | } 74 | @-webkit-keyframes blink { 75 | 0% { background: #7e7; } 76 | 50% { background: none; } 77 | 100% { background: #7e7; } 78 | } 79 | @keyframes blink { 80 | 0% { background: #7e7; } 81 | 50% { background: none; } 82 | 100% { background: #7e7; } 83 | } 84 | 85 | /* Can style cursor different in overwrite (non-insert) mode */ 86 | div.CodeMirror-overwrite div.CodeMirror-cursor {} 87 | 88 | .cm-tab { display: inline-block; text-decoration: inherit; } 89 | 90 | .CodeMirror-ruler { 91 | border-left: 1px solid #ccc; 92 | position: absolute; 93 | } 94 | 95 | /* DEFAULT THEME */ 96 | 97 | .cm-s-default .cm-keyword {color: #708;} 98 | .cm-s-default .cm-atom {color: #219;} 99 | .cm-s-default .cm-number {color: #164;} 100 | .cm-s-default .cm-def {color: #00f;} 101 | .cm-s-default .cm-variable, 102 | .cm-s-default .cm-punctuation, 103 | .cm-s-default .cm-property, 104 | .cm-s-default .cm-operator {} 105 | .cm-s-default .cm-variable-2 {color: #05a;} 106 | .cm-s-default .cm-variable-3 {color: #085;} 107 | .cm-s-default .cm-comment {color: #a50;} 108 | .cm-s-default .cm-string {color: #a11;} 109 | .cm-s-default .cm-string-2 {color: #f50;} 110 | .cm-s-default .cm-meta {color: #555;} 111 | .cm-s-default .cm-qualifier {color: #555;} 112 | .cm-s-default .cm-builtin {color: #30a;} 113 | .cm-s-default .cm-bracket {color: #997;} 114 | .cm-s-default .cm-tag {color: #170;} 115 | .cm-s-default .cm-attribute {color: #00c;} 116 | .cm-s-default .cm-header {color: blue;} 117 | .cm-s-default .cm-quote {color: #090;} 118 | .cm-s-default .cm-hr {color: #999;} 119 | .cm-s-default .cm-link {color: #00c;} 120 | 121 | .cm-negative {color: #d44;} 122 | .cm-positive {color: #292;} 123 | .cm-header, .cm-strong {font-weight: bold;} 124 | .cm-em {font-style: italic;} 125 | .cm-link {text-decoration: underline;} 126 | .cm-strikethrough {text-decoration: line-through;} 127 | 128 | .cm-s-default .cm-error {color: #f00;} 129 | .cm-invalidchar {color: #f00;} 130 | 131 | /* Default styles for common addons */ 132 | 133 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 134 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 135 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } 136 | .CodeMirror-activeline-background {background: #e8f2ff;} 137 | 138 | /* STOP */ 139 | 140 | /* The rest of this file contains styles related to the mechanics of 141 | the editor. You probably shouldn't touch them. */ 142 | 143 | .CodeMirror { 144 | line-height: 1; 145 | position: relative; 146 | overflow: hidden; 147 | background: white; 148 | color: black; 149 | } 150 | 151 | .CodeMirror-scroll { 152 | overflow: scroll !important; /* Things will break if this is overridden */ 153 | /* 30px is the magic margin used to hide the element's real scrollbars */ 154 | /* See overflow: hidden in .CodeMirror */ 155 | margin-bottom: -30px; margin-right: -30px; 156 | padding-bottom: 30px; 157 | height: 100%; 158 | outline: none; /* Prevent dragging from highlighting the element */ 159 | position: relative; 160 | -moz-box-sizing: content-box; 161 | box-sizing: content-box; 162 | } 163 | .CodeMirror-sizer { 164 | position: relative; 165 | border-right: 30px solid transparent; 166 | -moz-box-sizing: content-box; 167 | box-sizing: content-box; 168 | } 169 | 170 | /* The fake, visible scrollbars. Used to force redraw during scrolling 171 | before actuall scrolling happens, thus preventing shaking and 172 | flickering artifacts. */ 173 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 174 | position: absolute; 175 | z-index: 6; 176 | display: none; 177 | } 178 | .CodeMirror-vscrollbar { 179 | right: 0; top: 0; 180 | overflow-x: hidden; 181 | overflow-y: scroll; 182 | } 183 | .CodeMirror-hscrollbar { 184 | bottom: 0; left: 0; 185 | overflow-y: hidden; 186 | overflow-x: scroll; 187 | } 188 | .CodeMirror-scrollbar-filler { 189 | right: 0; bottom: 0; 190 | } 191 | .CodeMirror-gutter-filler { 192 | left: 0; bottom: 0; 193 | } 194 | 195 | .CodeMirror-gutters { 196 | position: absolute; left: 0; top: 0; 197 | z-index: 3; 198 | } 199 | .CodeMirror-gutter { 200 | white-space: normal; 201 | height: 100%; 202 | -moz-box-sizing: content-box; 203 | box-sizing: content-box; 204 | display: inline-block; 205 | margin-bottom: -30px; 206 | /* Hack to make IE7 behave */ 207 | *zoom:1; 208 | *display:inline; 209 | } 210 | .CodeMirror-gutter-wrapper { 211 | position: absolute; 212 | z-index: 4; 213 | height: 100%; 214 | } 215 | .CodeMirror-gutter-elt { 216 | position: absolute; 217 | cursor: default; 218 | z-index: 4; 219 | } 220 | 221 | .CodeMirror-lines { 222 | cursor: text; 223 | min-height: 1px; /* prevents collapsing before first draw */ 224 | } 225 | .CodeMirror pre { 226 | /* Reset some styles that the rest of the page might have set */ 227 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 228 | border-width: 0; 229 | background: transparent; 230 | font-family: inherit; 231 | font-size: inherit; 232 | margin: 0; 233 | white-space: pre; 234 | word-wrap: normal; 235 | line-height: inherit; 236 | color: inherit; 237 | z-index: 2; 238 | position: relative; 239 | overflow: visible; 240 | } 241 | .CodeMirror-wrap pre { 242 | word-wrap: break-word; 243 | white-space: pre-wrap; 244 | word-break: normal; 245 | } 246 | 247 | .CodeMirror-linebackground { 248 | position: absolute; 249 | left: 0; right: 0; top: 0; bottom: 0; 250 | z-index: 0; 251 | } 252 | 253 | .CodeMirror-linewidget { 254 | position: relative; 255 | z-index: 2; 256 | overflow: auto; 257 | } 258 | 259 | .CodeMirror-widget {} 260 | 261 | .CodeMirror-measure { 262 | position: absolute; 263 | width: 100%; 264 | height: 0; 265 | overflow: hidden; 266 | visibility: hidden; 267 | } 268 | .CodeMirror-measure pre { position: static; } 269 | 270 | .CodeMirror div.CodeMirror-cursor { 271 | position: absolute; 272 | border-right: none; 273 | width: 0; 274 | } 275 | 276 | div.CodeMirror-cursors { 277 | visibility: hidden; 278 | position: relative; 279 | z-index: 3; 280 | } 281 | .CodeMirror-focused div.CodeMirror-cursors { 282 | visibility: visible; 283 | } 284 | 285 | .CodeMirror-selected { background: #d9d9d9; } 286 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 287 | .CodeMirror-crosshair { cursor: crosshair; } 288 | 289 | .cm-searching { 290 | background: #ffa; 291 | background: rgba(255, 255, 0, .4); 292 | } 293 | 294 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 295 | .CodeMirror span { *vertical-align: text-bottom; } 296 | 297 | /* Used to force a border model for a node */ 298 | .cm-force-border { padding-right: .1px; } 299 | 300 | @media print { 301 | /* Hide the cursor when printing */ 302 | .CodeMirror div.CodeMirror-cursors { 303 | visibility: hidden; 304 | } 305 | } 306 | 307 | /* See issue #2901 */ 308 | .cm-tab-wrap-hack:after { content: ''; } 309 | 310 | /* Help users use markselection to safely style text background */ 311 | span.CodeMirror-selectedtext { background: none; } 312 | -------------------------------------------------------------------------------- /js/jquery-upload-file.php: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 573 | 707 | -------------------------------------------------------------------------------- /js/room-manager.js: -------------------------------------------------------------------------------- 1 | var EditorRoom = function(id) 2 | { 3 | this.id = id; 4 | this.items = []; 5 | this.walkBoxes = {}; 6 | this.zOrderMap = {}; 7 | this.setId = setId; 8 | this.walkablePath = null; 9 | this.walkBehinds = []; 10 | this.onEnterScript = null; 11 | this.onExitScript = null; 12 | }; 13 | 14 | var setId = function(newId) 15 | { 16 | for(var i = 0; i < this.items.length; i++) 17 | this.items[i].parentRoomId = newId; 18 | 19 | for(var i = 0; i < editorCharactersList.length; i++) 20 | if(editorCharactersList[i].parentRoomId == this.id) 21 | editorCharactersList[i].parentRoomId = newId; 22 | 23 | this.id = newId; 24 | }; 25 | 26 | var EditorItem = function(id, type, pRoomId) 27 | { 28 | this.id = id; 29 | this.type = type; 30 | this.walkspot = { x : null, y : null}; 31 | this.hotspot = null; 32 | this.visible = true; 33 | this.layer = 2; 34 | this.description = ''; 35 | this.parentRoomId = pRoomId; 36 | this.setLayer = setItemLayer; 37 | this.position = { x : null, y : null }; 38 | this.anim_state = null; 39 | this.dir = null; 40 | this.defaultAnims = {}; 41 | this.customAnims = {}; 42 | this.speechColor = '#ffffff'; 43 | this.faceDir = 'Left'; 44 | this.getCurrentFrame = getItemCurrentFrame; 45 | this.maxScaleFactor = 100; 46 | this.exitTo = { 'room' : null, xPos : null, yPos : null }; 47 | 48 | switch(type) 49 | { 50 | case 'character': 51 | var initAnims = function() { return { 'FL' : null, 'FR' : null, 'FF' : null, 'FB' : null, 'FFL' : null, 'FFR' : null, 'FBL' : null, 'FBR' : null }; }; 52 | this.defaultAnims.stand = initAnims(); 53 | this.defaultAnims.walk = initAnims(); 54 | this.defaultAnims.talk = initAnims(); 55 | this.anim_state = 'stand'; 56 | this.dir = 'FL'; 57 | break; 58 | case 'object': 59 | this.defaultAnims.default = null; 60 | this.anim_state = 'default'; 61 | break; 62 | default: 63 | throw 'Error: invalid object type'; 64 | break; 65 | } 66 | }; 67 | 68 | var getItemPlaceHolder = function(item) 69 | { 70 | var anim; 71 | 72 | switch(item.type) 73 | { 74 | case 'object': 75 | anim = editorMapIdAnim[item.defaultAnims.default]; 76 | break; 77 | case 'character': 78 | anim = editorMapIdAnim[item.defaultAnims.stand.FL]; 79 | break; 80 | } 81 | if(anim) 82 | return anim.frames[anim.start_idx]; 83 | return null; 84 | }; 85 | 86 | var setItemLayer = function(l, which) 87 | { 88 | l = parseInt(l); 89 | 90 | var parentRoom; 91 | 92 | if(!which) 93 | parentRoom = editorMapIdRoom[this.parentRoomId]; 94 | else 95 | parentRoom = testMapIdRoom[this.parentRoomId]; 96 | if(parentRoom.zOrderMap[this.layer]) 97 | { 98 | var index = parentRoom.zOrderMap[this.layer].indexOf(this.id); 99 | if(index !== -1) 100 | { 101 | parentRoom.zOrderMap[this.layer].splice(index, 1); 102 | if (parentRoom.zOrderMap[this.layer].length == 0) 103 | delete parentRoom.zOrderMap[this.layer]; 104 | } 105 | } 106 | if(parentRoom.zOrderMap[l] == undefined) 107 | parentRoom.zOrderMap[l] = []; 108 | parentRoom.zOrderMap[l].push(this.id); 109 | 110 | this.layer = l; 111 | }; 112 | 113 | var getItemCurrentFrame = function() 114 | { 115 | var anim; 116 | 117 | switch(this.type) 118 | { 119 | case 'object': 120 | anim = testMapIdAnim[this.defaultAnims[this.anim_state][this.dir]]; 121 | break; 122 | case 'character': 123 | if(this.anim_state in this.defaultAnims) 124 | try {anim = testMapIdAnim[this.defaultAnims[this.anim_state][this.dir]];} 125 | catch(err) { alert(err); return; } 126 | else if(this.anim_state in this.customAnims) 127 | try {anim = testMapIdAnim[this.customAnims[this.anim_state]];} 128 | catch(err) { alert(err); return; } 129 | 130 | break; 131 | } 132 | if(anim) 133 | return anim.frames[anim.start_idx]; 134 | return null; 135 | }; 136 | 137 | var EditorSprite = function(image) 138 | { 139 | this.img = image; 140 | this.centralPerspectiveWalkBehind = null; 141 | //this.boundingBox = new paper.Rectangle(0, 0, image.width, image.height); 142 | this.boundingBox = new paper.Rectangle(); 143 | this.setPosition = function setPosition(left, top) 144 | { 145 | //this.boundingBox = new paper.Rectangle(left, top, this.boundingBox.width, this.boundingBox.height); 146 | this.boundingBox.setTopLeft(left, top); 147 | }; 148 | this.setSize = function setSize(width, height) 149 | { 150 | this.boundingBox.setSize(width, height); 151 | }; 152 | //this.setPosition(0, 0); 153 | }; 154 | 155 | var editorRoomsList = []; 156 | var editorRoomsCount = 0; 157 | var editorItemsCount = 0; 158 | var editorMapIdRoom = {}; 159 | var editorMapIdItem = {}; 160 | var editorCurrentRoom = null; 161 | var editorCurrentItem = null; 162 | var editorCurrentWalkBox = null; 163 | var editorMapIdWb = {}; 164 | var editorWbCount = 0; 165 | 166 | var createNewEditorRoom = function(id) 167 | { 168 | var newEditorRoom = new EditorRoom(id); 169 | editorRoomsList.push(newEditorRoom); 170 | editorMapIdRoom[id] = newEditorRoom; 171 | }; 172 | 173 | var setEditorRoomBackground = function(event) 174 | { 175 | if(!event.target.files[0].type.match(/image.*/)) 176 | { 177 | alert("Please choose an image file!"); 178 | return; 179 | } 180 | $('.previous-file').hide(); 181 | var newEditorItem; 182 | var fileReader = new FileReader(); 183 | fileReader.onload = function(event){ 184 | var img = new Image(); 185 | img.onload = function(){ 186 | var bg = new EditorSprite(img); 187 | bg.setPosition(0, 0); 188 | bg.setSize(img.width, img.height); 189 | editorCurrentRoom.items[0] = bg; 190 | //editorCurrentRoom.zOrderMap[0] = newEditorItem; 191 | updateCanvas(editorCurrentRoom, 'room'); 192 | $('.item').show(); 193 | }; 194 | img.src = event.target.result; 195 | img.draggable="true"; 196 | }; 197 | fileReader.readAsDataURL(event.target.files[0]); 198 | }; 199 | 200 | var setEditorItemSprite = function(event, dfd) 201 | { 202 | if(!event.target.files[0].type.match(/image.*/)) 203 | { 204 | alert("Please choose an image file!"); 205 | return; 206 | } 207 | $('.previous-file').hide(); 208 | var fileReader = new FileReader(); 209 | fileReader.onload = function(event) 210 | { 211 | var img = new Image(); 212 | img.onload = function() 213 | { 214 | editorMapIdItem[editorCurrentItem.id].sprite = new EditorSprite(img); 215 | editorMapIdItem[editorCurrentItem.id].sprite.setPosition(-img.width, -img.height); 216 | editorMapIdItem[editorCurrentItem.id].sprite.setSize(img.width, img.height); 217 | if(editorCurrentRoom.zOrderMap[editorCurrentItem.layer] == undefined) 218 | editorCurrentRoom.zOrderMap[editorCurrentItem.layer] = []; 219 | editorCurrentRoom.zOrderMap[editorCurrentItem.layer].push(editorCurrentItem.id); 220 | dfd.resolve(); 221 | }; 222 | img.src = event.target.result; 223 | img.draggable="true"; 224 | }; 225 | fileReader.readAsDataURL(event.target.files[0]); 226 | }; 227 | 228 | var createNewEditorItem = function(id, parentRoomId) 229 | { 230 | var newEditorItem = new EditorItem(id, 'object', parentRoomId); 231 | editorCurrentRoom.items.push(newEditorItem); 232 | editorMapIdItem[id] = newEditorItem; 233 | if(editorCurrentRoom.zOrderMap[newEditorItem.layer] == undefined) 234 | editorCurrentRoom.zOrderMap[newEditorItem.layer] = []; 235 | editorCurrentRoom.zOrderMap[newEditorItem.layer].push(newEditorItem.id); 236 | }; 237 | 238 | var deleteEditorRoom = function(roomId) 239 | { 240 | var room = editorMapIdRoom[roomId]; 241 | for(var i = 1; i < room.items.length; i++) 242 | { 243 | delete editorMapIdItem[room.items[i].id]; 244 | } 245 | editorRoomsList.splice(editorRoomsList.indexOf(room), 1); 246 | delete editorMapIdRoom[room.id]; 247 | }; 248 | 249 | var deleteEditorItem = function(itemId) 250 | { 251 | var item = editorMapIdItem[itemId]; 252 | var room = editorMapIdRoom[item.parentRoomId]; 253 | 254 | delete editorMapIdItem[itemId]; 255 | 256 | room.zOrderMap[item.layer].splice(room.zOrderMap[item.layer].indexOf(item.id)); 257 | room.items.splice(room.items.indexOf(item), 1); 258 | }; 259 | 260 | var checkIdUniqueness = function(id, type) 261 | { 262 | switch(type) 263 | { 264 | case 'room': return !(id in editorMapIdRoom); 265 | case 'item': 266 | for(var i = 0; i < editorRoomsList.length; i++) 267 | for(var j = 1; j < editorRoomsList[i].items.length; j++) 268 | if(editorRoomsList[i].items[j].id == id) 269 | return false; 270 | return true; 271 | case 'action': return !(id in editorMapIdAction); 272 | case 'character': return !(id in editorMapIdCharacter); 273 | case 'anim': return !(id in editorMapIdAnim); 274 | case 'inventory-item': return !(id in editorMapIdInvItem); 275 | case 'dialog' : return !(id in editorMapIdDialog); 276 | } 277 | }; 278 | 279 | var createNewEditorWalkBehind = function(id, parentRoomId) 280 | { 281 | editorMapIdRoom[parentRoomId].walkBehinds.push({ id : id, image : null, poly: null, position : null, centralPerspectiveWalkBehind : null }); 282 | editorMapIdWb[id] = editorMapIdRoom[parentRoomId].walkBehinds[editorMapIdRoom[parentRoomId].walkBehinds.length - 1]; 283 | }; 284 | 285 | -------------------------------------------------------------------------------- /js/jquery.uploadfile.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Upload File Plugin 3 | * version: 3.1.4 4 | * @requires jQuery v1.5 or later & form plugin 5 | * Copyright (c) 2013 Ravishanker Kusuma 6 | * http://hayageek.com/ 7 | */ 8 | (function(b){if(b.fn.ajaxForm==undefined){b.getScript("http://malsup.github.io/jquery.form.js")}var a={};a.fileapi=b("").get(0).files!==undefined;a.formdata=window.FormData!==undefined;b.fn.uploadFile=function(t){var r=b.extend({url:"",method:"POST",enctype:"multipart/form-data",formData:null,returnType:null,allowedTypes:"*",fileName:"file",formData:{},dynamicFormData:function(){return{}},maxFileSize:-1,maxFileCount:-1,multiple:true,dragDrop:true,autoSubmit:true,showCancel:true,showAbort:true,showDone:true,showDelete:false,showError:true,showStatusAfterSuccess:true,showStatusAfterError:true,showFileCounter:true,fileCounterStyle:"). ",showProgress:false,nestedForms:true,onSelect:function(s){return true},onSubmit:function(s,u){},onSuccess:function(u,s,v){},onError:function(v,s,u){},deleteCallback:false,afterUploadAll:false,uploadButtonClass:"ajax-file-upload",dragDropStr:"Drag & Drop Files",abortStr:"Abort",cancelStr:"Cancel",deletelStr:"Delete",doneStr:"Done",multiDragErrorStr:"Multiple File Drag & Drop is not allowed.",extErrorStr:"is not allowed. Allowed extensions: ",sizeErrorStr:"is not allowed. Allowed Max size: ",uploadErrorStr:"Upload is not allowed",maxFileCountErrorStr:" is not allowed. Maximum allowed files are:",showQueueDiv:false},t);this.fileCounter=1;this.selectedFiles=0;this.fCounter=0;this.sCounter=0;this.tCounter=0;var d="ajax-file-upload-"+(new Date().getTime());this.formGroup=d;this.hide();this.errorLog=b("
    ");this.after(this.errorLog);this.responses=[];if(!a.formdata){r.dragDrop=false}if(!a.formdata){r.multiple=false}var m=this;var e=b("
    "+b(this).html()+"
    ");b(e).addClass(r.uploadButtonClass);(function k(){if(b.fn.ajaxForm){if(r.dragDrop){var s=b('
    ');b(m).before(s);b(s).append(e);b(s).append(b(r.dragDropStr));f(m,r,s)}else{b(m).before(e)}q(m,d,r,e)}else{window.setTimeout(k,10)}})();this.startUpload=function(){b("."+this.formGroup).each(function(u,s){if(b(this).is("form")){b(this).submit()}})};this.stopUpload=function(){b(".ajax-file-upload-red").each(function(u,s){if(b(this).hasClass(m.formGroup)){b(this).click()}})};this.getResponses=function(){return this.responses};var g=false;function j(){if(r.afterUploadAll&&!g){g=true;(function s(){if(m.sCounter!=0&&(m.sCounter+m.fCounter==m.tCounter)){r.afterUploadAll(m);g=false}else{window.setTimeout(s,100)}})()}}function f(w,u,v){v.on("dragenter",function(s){s.stopPropagation();s.preventDefault();b(this).css("border","2px solid #A5A5C7")});v.on("dragover",function(s){s.stopPropagation();s.preventDefault()});v.on("drop",function(x){b(this).css("border","2px dotted #A5A5C7");x.preventDefault();w.errorLog.html("");var s=x.originalEvent.dataTransfer.files;if(!u.multiple&&s.length>1){if(u.showError){b("
    "+u.multiDragErrorStr+"
    ").appendTo(w.errorLog)}return}if(u.onSelect(s)==false){return}l(u,w,s)});b(document).on("dragenter",function(s){s.stopPropagation();s.preventDefault()});b(document).on("dragover",function(s){s.stopPropagation();s.preventDefault();v.css("border","2px dotted #A5A5C7")});b(document).on("drop",function(s){s.stopPropagation();s.preventDefault();v.css("border","2px dotted #A5A5C7")})}function i(s){var v="";var u=s/1024;if(parseInt(u)>1024){var w=u/1024;v=w.toFixed(2)+" MB"}else{v=u.toFixed(2)+" KB"}return v}function o(x){var y=[];if(jQuery.type(x)=="string"){y=x.split("&")}else{y=b.param(x).split("&")}var u=y.length;var s=[];var w,v;for(w=0;w"+u[C].name+" "+H.extErrorStr+H.allowedTypes+"
    ").appendTo(B.errorLog)}continue}if(H.maxFileSize!=-1&&u[C].size>H.maxFileSize){if(H.showError){b("
    "+u[C].name+" "+H.sizeErrorStr+i(H.maxFileSize)+"
    ").appendTo(B.errorLog)}continue}if(H.maxFileCount!=-1&&B.selectedFiles>=H.maxFileCount){if(H.showError){b("
    "+u[C].name+" "+H.maxFileCountErrorStr+H.maxFileCount+"
    ").appendTo(B.errorLog)}continue}B.selectedFiles++;var D=H;var w=new FormData();var A=H.fileName.replace("[]","");w.append(A,u[C]);var y=H.formData;if(y){var F=o(y);for(var z=0;z");v.appendTo("body");var x=[];x.push(u[C].name);n(v,D,E,x,B);B.fileCounter++}}function c(w,v,y){var x=v.allowedTypes.toLowerCase().split(",");var u=y.split(".").pop().toLowerCase();if(v.allowedTypes!="*"&&jQuery.inArray(u,x)<0){return false}return true}function h(u,w){if(u.showFileCounter){var v=b(".ajax-file-upload-filename").length;w.fileCounter=v+1;b(".ajax-file-upload-filename").each(function(A,y){var s=b(this).html().split(u.fileCounterStyle);var x=parseInt(s[0])-1;var z=v+u.fileCounterStyle+s[1];b(this).html(z);v--})}}function q(y,B,D,u){var A="ajax-upload-id-"+(new Date().getTime());var w=b("
    ");var v="";if(D.multiple){if(D.fileName.indexOf("[]")!=D.fileName.length-2){D.fileName+="[]"}v=""}var z=b(v).appendTo(w);z.change(function(){y.errorLog.html("");var K=D.allowedTypes.toLowerCase().split(",");var G=[];if(this.files){for(H=0;H"+I+" "+D.extErrorStr+D.allowedTypes+"
    ").appendTo(y.errorLog)}return}F.push({name:I,size:"NA"});if(D.onSelect(F)==false){return}}h(D,y);u.unbind("click");w.hide();q(y,B,D,u);w.addClass(B);if(a.fileapi&&a.formdata){w.removeClass(B);var J=this.files;l(D,y,J)}else{var E="";for(var H=0;H"}else{E+=G[H]+"
    "}y.fileCounter++}if(D.maxFileCount!=-1&&(y.selectedFiles+G.length)>D.maxFileCount){if(D.showError){b("
    "+E+" "+D.maxFileCountErrorStr+D.maxFileCount+"
    ").appendTo(y.errorLog)}return}y.selectedFiles+=G.length;var s=new p(y,D);s.filename.html(E);n(w,D,s,G,y)}});if(D.nestedForms){w.css({margin:0,padding:0});var C=b(u).width();if(C<=0){C=120}var x=u.height();if(x<=0){x=25}u.css({position:"relative",overflow:"hidden",cursor:"default"});z.css({position:"absolute",cursor:"pointer",top:"0px",width:C,height:x,left:"0px","z-index":"100",opacity:"0.0",filter:"alpha(opacity=0)","-ms-filter":"alpha(opacity=0)","-khtml-opacity":"0.0","-moz-opacity":"0.0"});w.appendTo(u)}else{w.appendTo(b("body"));w.css({margin:0,padding:0,display:"block",position:"absolute",left:"-250px"});if(navigator.appVersion.indexOf("MSIE ")!=-1){u.attr("for",A)}else{u.click(function(){z.click()})}}}function p(v,u){this.statusbar=b("
    ");this.filename=b("
    ").appendTo(this.statusbar);this.progressDiv=b("
    ").appendTo(this.statusbar).hide();this.progressbar=b("
    ").appendTo(this.progressDiv);this.abort=b("
    "+u.abortStr+"
    ").appendTo(this.statusbar).hide();this.cancel=b("
    "+u.cancelStr+"
    ").appendTo(this.statusbar).hide();this.done=b("
    "+u.doneStr+"
    ").appendTo(this.statusbar).hide();this.del=b("
    "+u.deletelStr+"
    ").appendTo(this.statusbar).hide();if(u.showQueueDiv){b("#"+u.showQueueDiv).append(this.statusbar)}else{v.errorLog.after(this.statusbar)}return this}function n(z,y,u,w,A){var x=null;var v={cache:false,contentType:false,processData:false,forceSync:false,type:y.method,data:y.formData,formData:y.fileData,dataType:y.returnType,beforeSubmit:function(F,C,E){if(y.onSubmit.call(this,w)!=false){var B=y.dynamicFormData();if(B){var s=o(B);if(s){for(var D=0;D"+y.uploadErrorStr+"
    ");u.cancel.show();z.remove();u.cancel.click(function(){u.statusbar.remove()});return false},beforeSend:function(B,s){u.progressDiv.show();u.cancel.hide();u.done.hide();if(y.showAbort){u.abort.show();u.abort.click(function(){B.abort();A.selectedFiles-=w.length})}if(!a.formdata){u.progressbar.width("5%")}else{u.progressbar.width("1%")}},uploadProgress:function(E,s,D,C){if(C>98){C=98}var B=C+"%";if(C>1){u.progressbar.width(B)}if(y.showProgress){u.progressbar.html(B);u.progressbar.css("text-align","center")}},success:function(B,s,C){A.responses.push(B);u.progressbar.width("100%");if(y.showProgress){u.progressbar.html("100%");u.progressbar.css("text-align","center")}u.abort.hide();y.onSuccess.call(this,w,B,C);if(y.showStatusAfterSuccess){if(y.showDone){u.done.show();u.done.click(function(){u.statusbar.hide("slow");u.statusbar.remove()})}else{u.done.hide()}if(y.showDelete){u.del.show();u.del.click(function(){u.statusbar.hide().remove();if(y.deleteCallback){y.deleteCallback.call(this,B,u)}A.selectedFiles-=w.length;h(y,A)})}else{u.del.hide()}}else{u.statusbar.hide("slow");u.statusbar.remove()}z.remove();A.sCounter+=w.length},error:function(C,s,B){u.abort.hide();if(C.statusText=="abort"){u.statusbar.hide("slow").remove();h(y,A)}else{y.onError.call(this,w,s,B);if(y.showStatusAfterError){u.progressDiv.hide();u.statusbar.append("ERROR: "+B+"")}else{u.statusbar.hide();u.statusbar.remove()}A.selectedFiles-=w.length}z.remove();A.fCounter+=w.length}};if(y.autoSubmit){z.ajaxSubmit(v)}else{if(y.showCancel){u.cancel.show();u.cancel.click(function(){z.remove();u.statusbar.remove();A.selectedFiles-=w.length;h(y,A)})}z.ajaxForm(v)}}return this}}(jQuery)); -------------------------------------------------------------------------------- /js/deepCopy.js: -------------------------------------------------------------------------------- 1 | /* This file is part of OWL JavaScript Utilities. 2 | 3 | OWL JavaScript Utilities is free software: you can redistribute it and/or 4 | modify it under the terms of the GNU Lesser General Public License 5 | as published by the Free Software Foundation, either version 3 of 6 | the License, or (at your option) any later version. 7 | 8 | OWL JavaScript Utilities is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with OWL JavaScript Utilities. If not, see 15 | . 16 | */ 17 | 18 | owl = (function() { 19 | 20 | // the re-usable constructor function used by clone(). 21 | function Clone() {} 22 | 23 | // clone objects, skip other types. 24 | function clone(target) { 25 | if ( typeof target == 'object' ) { 26 | Clone.prototype = target; 27 | return new Clone(); 28 | } else { 29 | return target; 30 | } 31 | } 32 | 33 | 34 | // Shallow Copy 35 | function copy(target) { 36 | if (typeof target !== 'object' ) { 37 | return target; // non-object have value sematics, so target is already a copy. 38 | } else { 39 | var value = target.valueOf(); 40 | if (target != value) { 41 | // the object is a standard object wrapper for a native type, say String. 42 | // we can make a copy by instantiating a new object around the value. 43 | return new target.constructor(value); 44 | } else { 45 | // ok, we have a normal object. If possible, we'll clone the original's prototype 46 | // (not the original) to get an empty object with the same prototype chain as 47 | // the original. If just copy the instance properties. Otherwise, we have to 48 | // copy the whole thing, property-by-property. 49 | if ( target instanceof target.constructor && target.constructor !== Object ) { 50 | var c = clone(target.constructor.prototype); 51 | 52 | // give the copy all the instance properties of target. It has the same 53 | // prototype as target, so inherited properties are already there. 54 | for ( var property in target) { 55 | if (target.hasOwnProperty(property)) { 56 | c[property] = target[property]; 57 | } 58 | } 59 | } else { 60 | var c = {}; 61 | for ( var property in target ) c[property] = target[property]; 62 | } 63 | 64 | return c; 65 | } 66 | } 67 | } 68 | 69 | // Deep Copy 70 | var deepCopiers = []; 71 | 72 | function DeepCopier(config) { 73 | for ( var key in config ) this[key] = config[key]; 74 | } 75 | DeepCopier.prototype = { 76 | constructor: DeepCopier, 77 | 78 | // determines if this DeepCopier can handle the given object. 79 | canCopy: function(source) { return false; }, 80 | 81 | // starts the deep copying process by creating the copy object. You 82 | // can initialize any properties you want, but you can't call recursively 83 | // into the DeeopCopyAlgorithm. 84 | create: function(source) { }, 85 | 86 | // Completes the deep copy of the source object by populating any properties 87 | // that need to be recursively deep copied. You can do this by using the 88 | // provided deepCopyAlgorithm instance's deepCopy() method. This will handle 89 | // cyclic references for objects already deepCopied, including the source object 90 | // itself. The "result" passed in is the object returned from create(). 91 | populate: function(deepCopyAlgorithm, source, result) {} 92 | }; 93 | 94 | function DeepCopyAlgorithm() { 95 | // copiedObjects keeps track of objects already copied by this 96 | // deepCopy operation, so we can correctly handle cyclic references. 97 | this.copiedObjects = []; 98 | thisPass = this; 99 | this.recursiveDeepCopy = function(source) { 100 | return thisPass.deepCopy(source); 101 | } 102 | this.depth = 0; 103 | } 104 | DeepCopyAlgorithm.prototype = { 105 | constructor: DeepCopyAlgorithm, 106 | 107 | maxDepth: 256, 108 | 109 | // add an object to the cache. No attempt is made to filter duplicates; 110 | // we always check getCachedResult() before calling it. 111 | cacheResult: function(source, result) { 112 | this.copiedObjects.push([source, result]); 113 | }, 114 | 115 | // Returns the cached copy of a given object, or undefined if it's an 116 | // object we haven't seen before. 117 | getCachedResult: function(source) { 118 | var copiedObjects = this.copiedObjects; 119 | var length = copiedObjects.length; 120 | for ( var i=0; i this.maxDepth ) { 177 | throw new Error("Exceeded max recursion depth in deep copy."); 178 | } 179 | 180 | // It's now safe to let the deepCopier recursively deep copy its properties. 181 | deepCopier.populate(this.recursiveDeepCopy, source, result); 182 | 183 | this.depth--; 184 | 185 | return result; 186 | } 187 | }; 188 | 189 | // entry point for deep copy. 190 | // source is the object to be deep copied. 191 | // maxDepth is an optional recursion limit. Defaults to 256. 192 | function deepCopy(source, maxDepth) { 193 | var deepCopyAlgorithm = new DeepCopyAlgorithm(); 194 | if ( maxDepth ) deepCopyAlgorithm.maxDepth = maxDepth; 195 | return deepCopyAlgorithm.deepCopy(source); 196 | } 197 | 198 | // publicly expose the DeepCopier class. 199 | deepCopy.DeepCopier = DeepCopier; 200 | 201 | // publicly expose the list of deepCopiers. 202 | deepCopy.deepCopiers = deepCopiers; 203 | 204 | // make deepCopy() extensible by allowing others to 205 | // register their own custom DeepCopiers. 206 | deepCopy.register = function(deepCopier) { 207 | if ( !(deepCopier instanceof DeepCopier) ) { 208 | deepCopier = new DeepCopier(deepCopier); 209 | } 210 | deepCopiers.unshift(deepCopier); 211 | } 212 | 213 | // Generic Object copier 214 | // the ultimate fallback DeepCopier, which tries to handle the generic case. This 215 | // should work for base Objects and many user-defined classes. 216 | deepCopy.register({ 217 | canCopy: function(source) { return true; }, 218 | 219 | create: function(source) { 220 | if ( source instanceof source.constructor ) { 221 | return clone(source.constructor.prototype); 222 | } else { 223 | return {}; 224 | } 225 | }, 226 | 227 | populate: function(deepCopy, source, result) { 228 | for ( var key in source ) { 229 | if ( source.hasOwnProperty(key) ) { 230 | result[key] = deepCopy(source[key]); 231 | } 232 | } 233 | return result; 234 | } 235 | }); 236 | 237 | // Array copier 238 | deepCopy.register({ 239 | canCopy: function(source) { 240 | return ( source instanceof Array ); 241 | }, 242 | 243 | create: function(source) { 244 | return new source.constructor(); 245 | }, 246 | 247 | populate: function(deepCopy, source, result) { 248 | for ( var i=0; i 1) return vertex2; 47 | return new paper.Point(vertex1.x + t * (vertex2.x - vertex1.x), vertex1.y + t * (vertex2.y - vertex1.y)); 48 | }; 49 | this.getNearestPoint = function(p) 50 | { 51 | var list = []; 52 | 53 | for(var i = 0; i < this.edges.length; i++) 54 | list.push(this.getNearestPointToEdge(p, this.edges[i][0], this.edges[i][1])); 55 | 56 | var minDist = Number.MAX_VALUE; 57 | var minIdx = -1; 58 | 59 | for(var i = 0; i < list.length; i++) 60 | { 61 | var dist = getDistanceFromPoints(p, list[i]); 62 | if(minDist > dist) 63 | { 64 | minDist = dist; 65 | minIdx = i; 66 | } 67 | } 68 | 69 | return list[minIdx]; 70 | }; 71 | }; 72 | 73 | var Point = function(x, y) 74 | { 75 | this.x = x; 76 | this.y = y; 77 | }; 78 | 79 | var highlightCloseVertex = function(p, wb, precision) 80 | { 81 | var points = wb.polygon.points; 82 | for(var i = 0; i < points.length; i++) 83 | if(p.x >= points[i].x - precision && p.x < points[i].x + precision) 84 | if(p.y >= points[i].y - precision && p.y < points[i].y + precision) 85 | { 86 | wb.polygon.points[i].highlight = true; 87 | return; 88 | } 89 | }; 90 | 91 | var resetVertexHighlighting = function(wb) 92 | { 93 | var points = wb.polygon.points; 94 | for(var i = 0; i < points.length; i++) 95 | wb.polygon.points[i].highlight = false; 96 | }; 97 | 98 | var resetVertexLocking = function(wb) 99 | { 100 | var points = wb.polygon.points; 101 | for(var i = 0; i < points.length; i++) 102 | wb.polygon.points[i].locked = false; 103 | }; 104 | 105 | var getHighlightedWalkboxVertex = function(wboxes) 106 | { 107 | for(var i in wboxes) 108 | { 109 | var points = wboxes[i].polygon.points; 110 | for(var j = 0; j < points.length; j++) 111 | if(points[j].highlight) 112 | return { wboxId : i, point : points[j] }; 113 | } 114 | return null; 115 | }; 116 | 117 | var getLockedWalkboxVertex = function(wboxes) 118 | { 119 | for(var i in wboxes) 120 | { 121 | var points = wboxes[i].polygon.points; 122 | for(var j = 0; j < points.length; j++) 123 | if(points[j].locked) 124 | return { wboxId : i, point : points[j] }; 125 | } 126 | return null; 127 | }; 128 | 129 | var changeLockedWalkboxVertexPosition = function(wboxes, wboxId, x, y) 130 | { 131 | var poly = wboxes[wboxId].polygon; 132 | var points = poly.points; 133 | for(var j = 0; j < points.length; j++) 134 | if(points[j].locked) 135 | { 136 | points[j].x = x; 137 | points[j].y = y; 138 | } 139 | if(poly.closed === true) 140 | poly.close(); 141 | }; 142 | 143 | var isPointOnLine = function(edge, p, precision) 144 | { 145 | var edgePointA = edge[0]; 146 | var edgePointB = edge[1]; 147 | 148 | var dist = Math.abs((edgePointB.y - edgePointA.y) * p.x - (edgePointB.x - edgePointA.x) * p.y + edgePointB.x * edgePointA.y 149 | - edgePointB.y * edgePointA.x) / Math.sqrt(Math.pow(edgePointB.y - edgePointA.y, 2) 150 | + Math.pow(edgePointB.x - edgePointA.x, 2)); 151 | 152 | var maxX = Math.max(edgePointA.x, edgePointB.x); 153 | var minX = Math.min(edgePointA.x, edgePointB.x); 154 | var maxY = Math.max(edgePointA.y, edgePointB.y); 155 | var minY = Math.min(edgePointA.y, edgePointB.y); 156 | 157 | if(dist <= precision && (p.x >= minX - 5 && p.x < maxX + 5 && p.y >= minY -5 && p.y < maxY + 5)) 158 | return true; 159 | }; 160 | 161 | 162 | var highlightCloseEdge = function(p, wb, precision) 163 | { 164 | var edges = wb.polygon.edges; 165 | for(var i = 0; i < edges.length; i++) 166 | if(isPointOnLine(edges[i], p, precision)) 167 | { 168 | wb.polygon.edges[i].highlight = true; 169 | return; 170 | } 171 | }; 172 | 173 | var getHighlightedWalkboxEdge = function(wboxes) 174 | { 175 | for(var i in wboxes) 176 | { 177 | var edges = wboxes[i].polygon.edges; 178 | for(var j = 0; j < edges.length; j++) 179 | if(edges[j].highlight) 180 | return { wboxId : i, edge : edges[j] }; 181 | } 182 | return null; 183 | }; 184 | 185 | var lockVertex = function(wb, p) 186 | { 187 | var points = wb.polygon.points; 188 | for(var i = 0; i < points.length; i++) 189 | if(p.x == points[i].x && p.y == points[i].y) 190 | { 191 | wb.polygon.points[i].locked = true; 192 | return; 193 | } 194 | }; 195 | 196 | var resetEdgeHighlighting = function(wb) 197 | { 198 | var edges = wb.polygon.edges; 199 | for(var i = 0; i < edges.length; i++) 200 | wb.polygon.edges[i].highlight = false; 201 | }; 202 | 203 | var splitEdge = function(wb, edge, newPoint) 204 | { 205 | var edges = wb.polygon.edges; 206 | var points = wb.polygon.points; 207 | var x1 = edge[0].x, y1 = edge[0].y; 208 | for(var i = 0; i < edges.length; i++) 209 | if(edges[i][0].x == edge[0].x && edges[i][0].y == edge[0].y 210 | && edges[i][1].x == edge[1].x && edges[i][1].y == edge[1].y) 211 | { 212 | wb.polygon.edges.splice(i, 0, [edge[0], new paper.Point(newPoint.x, newPoint.y)]); 213 | wb.polygon.edges[i + 1][0] = new paper.Point(newPoint.x, newPoint.y); 214 | break; 215 | } 216 | for(var i = 0; i < points.length; i++) 217 | if(points[i].x == x1 && points[i].y == y1) 218 | { 219 | wb.polygon.points.splice(i + 1, 0, new paper.Point(newPoint.x, newPoint.y)); 220 | break; 221 | } 222 | }; 223 | 224 | var getPolygonCentroid = function(poly) 225 | { 226 | var p = new paper.Point(0, 0); 227 | var points = poly.points; 228 | 229 | for(var i = 0; i < points.length; i++) 230 | { 231 | p.x += points[i].x; 232 | p.y += points[i].y; 233 | } 234 | 235 | p.x /= points.length; 236 | p.y /= points.length; 237 | 238 | return p; 239 | }; 240 | 241 | var getPolygonTopAndBottom = function(poly) 242 | { 243 | var points = poly.points; 244 | var minY = points[0].y; 245 | var maxY = points[0].y; 246 | 247 | for(var i = 1; i < points.length; i++) 248 | { 249 | if(minY > points[i].y) 250 | minY = points[i].y; 251 | if(maxY < points[i].y) 252 | maxY = points[i].y; 253 | } 254 | 255 | return { top : minY, bottom : maxY }; 256 | }; 257 | 258 | var getEdgeList = function(room) 259 | { 260 | var edges = {}; 261 | for (var key in room.walkBoxes) 262 | { 263 | var _edges = room.walkBoxes[key].polygon.edges; 264 | for (var i = 0; i < _edges.length; i++) 265 | { 266 | var edge_str1 = '(' + _edges[i][0].x + ', ' + _edges[i][0].y + ')'; 267 | var edge_str2 = '(' + _edges[i][1].x + ', ' + _edges[i][1].y + ')'; 268 | var tmp = edge_str1 + ', ' + edge_str2; 269 | if (tmp in edges) 270 | edges[tmp]['IDs'].push(key); 271 | else 272 | { 273 | tmp = edge_str2 + ', ' + edge_str1; 274 | if (tmp in edges) 275 | edges[tmp]['IDs'].push(key); 276 | else 277 | edges[tmp] = {IDs: [key], edge: _edges[i] }; 278 | } 279 | } 280 | } 281 | return edges; 282 | }; 283 | 284 | var computeWalkboxNeighbors = function(rooms) 285 | { 286 | for(var i in rooms) 287 | { 288 | var edgeList = getEdgeList(rooms[i]); 289 | for(var key in edgeList) 290 | if(edgeList[key].IDs.length > 1) 291 | { 292 | var IDs = edgeList[key].IDs; 293 | var neighborsList = rooms[i].walkBoxes[IDs[0]].neighbors; 294 | var alreadyPresent = false; 295 | for(var j = 0; j < neighborsList.length; j++) 296 | if(neighborsList[j].wbId === IDs[1]) // has the neighbor already been added? 297 | { 298 | alreadyPresent = true; 299 | break; 300 | } 301 | 302 | if(alreadyPresent === true) 303 | continue; 304 | rooms[i].walkBoxes[IDs[0]].neighbors.push(new Neighbor(IDs[1], edgeList[key].edge)); 305 | rooms[i].walkBoxes[IDs[1]].neighbors.push(new Neighbor(IDs[0], edgeList[key].edge)); 306 | } 307 | } 308 | 309 | }; 310 | 311 | var getWalkboxFromPoint = function(wboxes, p, skipInvisible) 312 | { 313 | for(var i in wboxes) 314 | { 315 | if(skipInvisible === true && wboxes[i].visible === false) 316 | continue; 317 | if (isPointInPoly(wboxes[i].polygon.points, p)) 318 | return wboxes[i]; 319 | } 320 | return null; 321 | }; 322 | 323 | var getCommonEdge = function(wb1, wb2) 324 | { 325 | var edge1 = null, edge2 = null; 326 | 327 | for(var i = 0; i < wb1.neighbors.length; i++) 328 | { 329 | var n = wb1.neighbors[i]; 330 | if(n.wbId === wb2.id) 331 | { 332 | edge1 = n.commonEdge; 333 | break; 334 | } 335 | } 336 | 337 | if(!edge1) 338 | return null; 339 | 340 | for(var i = 0; i < wb2.neighbors.length; i++) 341 | { 342 | var n = wb2.neighbors[i]; 343 | if(n.wbId === wb1.id) 344 | { 345 | edge2 = n.commonEdge; 346 | break; 347 | } 348 | } 349 | 350 | if(!edge2) 351 | return null; 352 | 353 | if(edge1 !== edge2) 354 | return null; 355 | 356 | return edge1; 357 | }; 358 | 359 | var getNearestWalkBox = function(wboxes, point) 360 | { 361 | var wb; 362 | var minDist = Infinity; 363 | var p; 364 | 365 | for(var i in wboxes) 366 | { 367 | if(wboxes[i].visible === false) 368 | continue; 369 | p = wboxes[i].polygon.getNearestPoint(point); 370 | var dist = getDistanceBetweenPoints(p, point); 371 | if (dist < minDist) 372 | { 373 | minDist = dist; 374 | wb = wboxes[i]; 375 | } 376 | } 377 | return wb; 378 | }; 379 | 380 | var deleteWalkbox = function(roomId, wbId) 381 | { 382 | delete editorMapIdRoom[roomId].walkBoxes[wbId]; 383 | }; -------------------------------------------------------------------------------- /js/canvas-manager.js: -------------------------------------------------------------------------------- 1 | var $canvas, canvas, canvas_Char, ctx, ctx_Char; 2 | 3 | /*var canvas_cMenu = 4 | { 5 | 'spritePositioning' : 6 | [{ 7 | 'text' : 'Place object here', 8 | 'action' : function() { console.log('Elt')} 9 | }] 10 | } 11 | ;*/ 12 | 13 | paper.Point.getDistance = function(p) 14 | { 15 | return Math.sqrt(Math.pow(this.x - p.x, 2) - Math.pow(this.y - p.y, 2)); 16 | }; 17 | 18 | var drawPolygon = function(polygon, fillColor, strokeColor, ctx, drawHandles) 19 | { 20 | ctx.strokeStyle = 'black'; 21 | ctx.lineWidth = 1; 22 | 23 | if(polygon.points.length == 0) 24 | return; 25 | if (polygon.points.length == 1) 26 | { 27 | ctx.fillRect(polygon.points[0].x - 5, polygon.points[0].y - 5, 10, 10); 28 | return; 29 | } 30 | else 31 | { 32 | var shiftX = 0, shiftY = 0; 33 | if(ctx === gameCtx) 34 | { 35 | shiftX = viewport.left; 36 | shiftY = viewport.top; 37 | } 38 | ctx.beginPath(); 39 | ctx.moveTo(polygon.points[0].x - shiftX, polygon.points[0].y - shiftY); 40 | for (var i = 0; i < polygon.points.length; i++) { 41 | if (polygon.points[i + 1] != undefined) { 42 | if (polygon.points[i + 1].x == polygon.points[i].x && polygon.points[i + 1].y == polygon.points[i].y) 43 | continue; 44 | ctx.lineTo(polygon.points[i + 1].x + 0.5 - shiftX, polygon.points[i + 1].y - shiftY); 45 | } 46 | else if (polygon.closed) { 47 | ctx.closePath(); 48 | if(fillColor) 49 | { 50 | ctx.fillStyle = fillColor; 51 | ctx.fill(); 52 | break; 53 | } 54 | 55 | } 56 | } 57 | 58 | if(strokeColor) 59 | { 60 | ctx.lineWidth = 3; 61 | ctx.strokeStyle = strokeColor; 62 | } 63 | ctx.stroke(); 64 | ctx.strokeStyle = 'black'; 65 | 66 | ctx.fillStyle = 'black'; 67 | 68 | /*for(var i = 0; i < polygon.edges.length; i++) 69 | { 70 | if(polygon.edges[i].highlight) 71 | { 72 | //alert('Close to edge!'); 73 | ctx.fillRect(0, 0, 50, 50); 74 | ctx.strokeStyle = 'blue'; 75 | ctx.lineTo(polygon.edges[i][0] + 0.5, polygon.edges[i][1]); 76 | break; 77 | } 78 | } 79 | */ 80 | if (!polygon.closed || drawHandles === true) 81 | for(var i = 0; i < polygon.points.length; i++) 82 | { 83 | if(polygon.points[i].highlight) 84 | ctx.fillStyle = 'red'; 85 | ctx.fillRect(polygon.points[i].x - 5, polygon.points[i].y - 5, 10, 10); 86 | ctx.fillStyle = 'black'; 87 | } 88 | 89 | 90 | } 91 | }; 92 | 93 | 94 | /*=======================================================================================================*/ 95 | var getItemWithSpriteContaining = function(point) 96 | { 97 | /* The point must be sought starting from the highest layers down to the lowest. 98 | This allows the user to select an item whose bounding box is completely contained inside another object's bounding box */ 99 | 100 | var ks = new Array(); 101 | for(var layer in editorCurrentRoom.zOrderMap) 102 | ks.push(layer); 103 | ks.sort(); // Since you can't order an object by keys in Javascript, order its keys 104 | 105 | for(var i = ks.length - 1; i >= 0; i--) 106 | { 107 | for(var j = 0; j < editorCurrentRoom.zOrderMap[ks[i]].length; j++) 108 | { 109 | var currentItem = editorMapIdItem[editorCurrentRoom.zOrderMap[ks[i]][j]]; 110 | if (currentItem.defaultAnims.default == null) 111 | continue; 112 | var anim = editorMapIdAnim[currentItem.defaultAnims.default]; 113 | if(!anim) 114 | continue; 115 | var frame = anim.frames[anim.start_idx]; 116 | var bb = new paper.Rectangle(currentItem.position.x - frame.img.width / 2, currentItem.position.y - frame.img.height, frame.img.width, frame.img.height); 117 | if (bb.contains(point)) 118 | return currentItem; 119 | } 120 | } 121 | return null; 122 | }; 123 | 124 | var getCharacterWithSpriteContaining = function(point) 125 | { 126 | var room = editorMapIdCharacter[editorCurrentCharacter.id]; 127 | var characters = []; 128 | 129 | for(var key in editorMapIdCharacter) 130 | if(editorMapIdCharacter[key].id == room.id) 131 | characters.push(editorMapIdCharacter[key]); 132 | 133 | for(var i = 0; i < characters.length; i++) 134 | { 135 | if (characters[i].defaultAnims.stand.FL == null) 136 | continue; 137 | var anim = editorMapIdAnim[characters[i].defaultAnims.stand.FL]; 138 | if(!anim) 139 | continue; 140 | var frame = anim.frames[anim.start_idx]; 141 | var bb = new paper.Rectangle(characters[i].position.x - frame.img.width / 2, characters[i].position.y - frame.img.height, frame.img.width, frame.img.height); 142 | if (bb.contains(point)) 143 | return characters[i]; 144 | } 145 | return null; 146 | }; 147 | 148 | var drawItemBoundingBox = function(item, ctx) 149 | { 150 | if(item == null) 151 | return; 152 | var frame = getItemPlaceHolder(item); 153 | ctx.beginPath(); 154 | ctx.lineWidth = '2'; 155 | ctx.setLineDash([2]); 156 | ctx.strokeStyle = '#2200ff'; 157 | ctx.rect(item.position.x - frame.img.width / 2, item.position.y - frame.img.height, frame.img.width, frame.img.height); 158 | ctx.stroke(); 159 | }; 160 | 161 | var updateCanvas = function(room, which) 162 | { 163 | if(!room) 164 | { 165 | $('.container.' + which).hide(); 166 | return; 167 | } 168 | 169 | var _canvas; 170 | var _context; 171 | var _selectedData; 172 | var _drawRoomChunks; 173 | 174 | switch(which) 175 | { 176 | case 'room': 177 | _canvas = canvas; 178 | _context = ctx; 179 | _selectedData = editorCurrentItem; 180 | _drawRoomChunks = function() 181 | { 182 | for(var key in room.zOrderMap) 183 | { 184 | var itemsKeyList = room.zOrderMap[key]; 185 | for (var i = 0; i < itemsKeyList.length; i++) 186 | { 187 | var item = editorMapIdItem[itemsKeyList[i]]; 188 | if(item.hideFromCanvas === true) 189 | continue; 190 | var frame = getItemPlaceHolder(item); 191 | if (!frame) 192 | continue; 193 | if (item.position.x == null || item.position.y == null) 194 | continue; 195 | _context.drawImage(frame.img, item.position.x - frame.img.width / 2, item.position.y - frame.img.height); 196 | } 197 | } 198 | }; 199 | break; 200 | case 'character': 201 | _canvas = canvas_Char; 202 | _context = ctx_Char; 203 | _selectedData = editorCurrentCharacter; 204 | _drawRoomChunks = function() 205 | { 206 | for (var key in editorMapIdCharacter) 207 | { 208 | var character = editorMapIdCharacter[key]; 209 | if (character.parentRoomId != room.id) 210 | continue; 211 | var frame = getItemPlaceHolder(character); 212 | if (!frame) 213 | continue; 214 | if (character.position.x == null || character.position.y == null) 215 | continue; 216 | _context.drawImage(frame.img, character.position.x - frame.img.width / 2, character.position.y - frame.img.height); 217 | } 218 | }; 219 | break; 220 | } 221 | 222 | _context.clearRect(0, 0, _canvas.width, _canvas.height); 223 | 224 | if(room.items.length == 0) 225 | { 226 | $('.container.' + which).hide(); 227 | //$('.canvas.room').hide(); 228 | //$('.toolbar.room').hide(); 229 | //$('.item').hide(); 230 | return; 231 | } 232 | 233 | //$(_canvas).css({ 'width' : room.items[0].boundingBox.width, 'height' : room.items[0].boundingBox.height }); 234 | _canvas.width = room.items[0].boundingBox.width; 235 | //_canvas.width = resolution.width; 236 | _canvas.height = room.items[0].boundingBox.height; 237 | //_canvas.height = resolution.height; 238 | 239 | _context.drawImage(room.items[0].img, room.items[0].boundingBox.left, room.items[0].boundingBox.top); 240 | 241 | _drawRoomChunks(); 242 | switch(_canvas.state) 243 | { 244 | case 'sprite': 245 | drawItemBoundingBox(_canvas.selected, _context); 246 | break; 247 | case 'hotspot': 248 | if(_selectedData != null && _selectedData.hotspot != null) 249 | drawPolygon(_selectedData.hotspot, '', _selectedData.hotspot['closed'] ? 'red' : '', _context); 250 | break; 251 | case 'pathfinding': 252 | if(keys(editorCurrentRoom.walkBoxes).length > 0) 253 | { 254 | for(var i in editorCurrentRoom.walkBoxes) 255 | { 256 | var fillColor = 'rgba(255, 255, 0, 0.5)'; 257 | var lineColor = 'orange'; 258 | if(editorCurrentWalkBox === editorCurrentRoom.walkBoxes[i].id) 259 | { 260 | fillColor = 'rgba(255, 0, 0, 0.5)'; 261 | lineColor = 'purple'; 262 | } 263 | drawPolygon(editorCurrentRoom.walkBoxes[i].polygon, fillColor, lineColor, ctx, true); 264 | } 265 | } 266 | break; 267 | case 'crop-image': 268 | if(cropPoly != null) 269 | { 270 | drawPolygon(cropPoly, '', cropPoly['closed'] ? 'red' : '', ctx); 271 | if(cropPoly['closed'] === true) 272 | { 273 | var data = cropImage(cropPoly); 274 | var croppedImage = new Image(); 275 | croppedImage.src = data.src; 276 | $(croppedImage).css('border', '1px solid black'); 277 | var croppedImageDiv = $('#cropped-image'); 278 | croppedImageDiv.empty(); 279 | croppedImageDiv.append(croppedImage); 280 | $('#cropped-image-modal').modal('show'); 281 | cropPoly = null; 282 | } 283 | } 284 | break; 285 | case 'walk-behind': 286 | if(editorCurrentItem != null && editorCurrentItem.centralPerspectiveWalkBehind != null) 287 | { 288 | ctx.strokeStyle = 'black'; 289 | ctx.lineWidth = 1; 290 | 291 | ctx.beginPath(); 292 | ctx.moveTo(0, editorCurrentItem.centralPerspectiveWalkBehind); 293 | ctx.lineTo(canvas.width, editorCurrentItem.centralPerspectiveWalkBehind); 294 | ctx.closePath(); 295 | ctx.stroke(); 296 | } 297 | break; 298 | default: 299 | break; 300 | } 301 | $('.container.' + which).show(); // Show the right part of the page 302 | //$('.canvas.room').show(); 303 | $('.toolbar.' + which).width($('.canvas.' + which).width()); 304 | $('.item.' + which).show(); 305 | }; -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | var polyTranslate = function(p, trX, trY) 2 | { 3 | var points = []; 4 | 5 | for(var i = 0; i < p.points.length; i++) 6 | points[i] = { x : p.points[i].x + trX, y : p.points[i].y + trY }; 7 | return points; 8 | }; 9 | 10 | 11 | var cropImage = function(poly) 12 | { 13 | var maskColor = 'rgba(255, 0, 255, 255)'; 14 | var maskColorRGBA = [255, 0, 255, 255]; 15 | 16 | var pixels = { data : null, imageWidth : null}; 17 | 18 | var isMaskColor = function(pixelData) 19 | { 20 | return (pixelData[0] == maskColorRGBA[0] && 21 | pixelData[1] == maskColorRGBA[1] && 22 | pixelData[2] == maskColorRGBA[2] && 23 | pixelData[3] == maskColorRGBA[3]); 24 | }; 25 | 26 | var minX, minY, maxX, maxY; 27 | 28 | minX = maxX = poly.points[0].x; 29 | minY = maxY = poly.points[0].y; 30 | 31 | for(var i = 1; i < poly.points.length; i++) 32 | { 33 | var p = poly.points[i]; 34 | if(p.x < minX) 35 | minX = p.x; 36 | if(p.x > maxX) 37 | maxX = p.x; 38 | if(p.y < minY) 39 | minY = p.y; 40 | if(p.y > maxY) 41 | maxY = p.y; 42 | } 43 | var tmpCanvas = document.createElement('canvas'); 44 | var tmpContext = tmpCanvas.getContext('2d'); 45 | tmpCanvas.width = maxX - minX; 46 | tmpCanvas.height = maxY - minY; 47 | tmpContext.clearRect(0, 0, tmpCanvas.width, tmpCanvas.height); 48 | tmpContext.fillStyle = 'white'; 49 | tmpContext.fillRect(0, 0, tmpCanvas.width, tmpCanvas.height); 50 | var newPoly = owl.deepCopy(poly); 51 | newPoly.points = polyTranslate(newPoly, -minX, -minY); 52 | drawPolygon(newPoly, maskColor, maskColor, tmpContext); 53 | 54 | pixels.data = tmpContext.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height).data; 55 | pixels.imageWidth = tmpCanvas.width; 56 | var tmp = canvas.state; 57 | canvas.state = 'idle'; 58 | updateCanvas(editorCurrentRoom, 'room'); 59 | var cutImage = ctx.getImageData(minX, minY, tmpCanvas.width, tmpCanvas.height); 60 | canvas.state = tmp; 61 | 62 | 63 | 64 | var findPixelsIndex = function(i, j) { return (j * tmpCanvas.width + i) * 4; }; 65 | for(var i = 0; i < tmpCanvas.width; i++) 66 | for(var j = 0; j < tmpCanvas.height; j++) 67 | { 68 | var idx = findPixelsIndex(i, j); 69 | var pixelColor = [pixels.data[idx], pixels.data[idx + 1], pixels.data[idx + 2], pixels.data[idx + 3]]; 70 | if (isMaskColor(pixelColor) == false) 71 | { 72 | cutImage.data[idx] = 0; 73 | cutImage.data[idx + 1] = 0; 74 | cutImage.data[idx + 2] = 0; 75 | cutImage.data[idx + 3] = 0; 76 | } 77 | } 78 | tmpContext.putImageData(cutImage, 0, 0); 79 | 80 | return {src: tmpCanvas.toDataURL(), width: maxX - minX, height: maxY - minY, pos : { x : minX, y : minY }}; 81 | }; 82 | 83 | //+ Jonas Raoni Soares Silva 84 | //@ http://jsfromhell.com/math/is-point-in-poly [rev. #0] 85 | var isPointInPoly = function (poly, pt) 86 | { 87 | for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) 88 | ((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y)) 89 | && (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) 90 | && (c = !c); 91 | return c; 92 | }; 93 | 94 | var qSort = function(a, orderingFunction) // Quicksort for walkbehinds ordering 95 | { 96 | if (a.length == 0) return []; 97 | 98 | var left = [], right = [], pivot = a[0]; 99 | 100 | for (var i = 1; i < a.length; i++) 101 | { 102 | orderingFunction(a[i], pivot) === true ? left.push(a[i]) : right.push(a[i]); 103 | } 104 | 105 | return qSort(left, orderingFunction).concat(pivot, qSort(right, orderingFunction)); 106 | }; 107 | 108 | var orderWalkBehinds = function(wb1, wb2) 109 | { 110 | return wb1.centralPerspectiveWalkBehind < wb2.centralPerspectiveWalkBehind; 111 | }; 112 | 113 | var orderPanels = function(panel1_id, panel2_id) 114 | { 115 | return panel1_id < panel2_id; 116 | }; 117 | 118 | var setCanvasResolution = function(canvas, w, h) 119 | { 120 | $(canvas).css({ 'width' : w, 'height' : h}); 121 | scaleFactor.x = w / canvas.width; 122 | scaleFactor.y = h / canvas.height; 123 | }; 124 | 125 | var getDistanceBetweenPoints = function(p1, p2) 126 | { 127 | try 128 | { 129 | return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); 130 | } 131 | catch (exception) 132 | { 133 | return Infinity; 134 | } 135 | }; 136 | 137 | /** 138 | ** See: http://jsfromhell.com/math/dot-line-length 139 | ** 140 | ** Distance from a point to a line or segment. 141 | ** 142 | ** @param {number} x point's x coord 143 | ** @param {number} y point's y coord 144 | ** @param {number} x0 x coord of the line's A point 145 | ** @param {number} y0 y coord of the line's A point 146 | ** @param {number} x1 x coord of the line's B point 147 | ** @param {number} y1 y coord of the line's B point 148 | ** @param {boolean} overLine specifies if the distance should respect the limits 149 | ** of the segment (overLine = true) or if it should consider the segment as an 150 | ** infinite line (overLine = false), if false returns the distance from the point to 151 | ** the line, otherwise the distance from the point to the segment. 152 | **/ 153 | var dotLineLength = function(x, y, x0, y0, x1, y1, o) { 154 | function lineLength(x, y, x0, y0){ 155 | return Math.sqrt((x -= x0) * x + (y -= y0) * y); 156 | } 157 | if(o && !(o = function(x, y, x0, y0, x1, y1){ 158 | if(!(x1 - x0)) return {x: x0, y: y}; 159 | else if(!(y1 - y0)) return {x: x, y: y0}; 160 | var left, tg = -1 / ((y1 - y0) / (x1 - x0)); 161 | return {x: left = (x1 * (x * tg - y + y0) + x0 * (x * - tg + y - y1)) / (tg * (x1 - x0) + y0 - y1), y: tg * left - tg * x + y}; 162 | }(x, y, x0, y0, x1, y1), o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1))){ 163 | var l1 = lineLength(x, y, x0, y0), l2 = lineLength(x, y, x1, y1); 164 | return l1 > l2 ? l2 : l1; 165 | } 166 | else { 167 | var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1; 168 | return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b); 169 | } 170 | }; 171 | 172 | function wrapText(context, text, x, y, maxWidth, lineHeight, fillColor) 173 | { 174 | var cars = text.split("\n"); 175 | context.fillStyle = fillColor; 176 | 177 | for (var ii = 0; ii < cars.length; ii++) { 178 | 179 | var line = ""; 180 | var words = cars[ii].split(" "); 181 | var correction = 0; 182 | for (var n = 0; n < words.length; n++) { 183 | var testLine = line + words[n] + " "; 184 | var metrics = context.measureText(testLine); 185 | var testWidth = metrics.width; 186 | 187 | if (testWidth > maxWidth) { 188 | metrics = context.measureText(line); 189 | context.lineWidth = 5; 190 | var tmp = x - metrics.width / 2; 191 | if(tmp < 0) 192 | { 193 | correction = -tmp; 194 | tmp = 0; 195 | } 196 | context.strokeText(line, tmp, y); 197 | context.lineWidth = 3; 198 | context.fillText(line, tmp, y); 199 | line = words[n] + " "; 200 | y += lineHeight; 201 | } 202 | else { 203 | line = testLine; 204 | } 205 | } 206 | 207 | var metrics = context.measureText(line); 208 | context.lineWidth = 5; 209 | var tmp = x - metrics.width / 2; 210 | if(tmp < 0) 211 | { 212 | correction = 0; 213 | tmp = 0; 214 | } 215 | context.strokeText(line, tmp + correction, y); 216 | context.lineWidth = 3; 217 | context.fillText(line, tmp + correction, y); 218 | y += lineHeight; 219 | } 220 | }; 221 | 222 | var keys = function(obj) 223 | { 224 | var ks = []; 225 | for(var i in obj) 226 | ks.push(i); 227 | return ks; 228 | }; 229 | 230 | var DEBUG_drawWalkBoxes = function() 231 | { 232 | for(var key in testCurrentRoom.walkBoxes) 233 | { 234 | var wb = testCurrentRoom.walkBoxes[key]; 235 | if(wb.visible) 236 | drawPolygon(wb.polygon, '', 'green', gameCtx, false); 237 | } 238 | }; 239 | 240 | var getVector = function(p1, p2) 241 | { 242 | return new Point(p2.x - p1.x, p2.y - p1.y); 243 | }; 244 | 245 | var normalizeVector = function(v) 246 | { 247 | var norm = Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2)); 248 | v.x /= norm; 249 | v.y /= norm; 250 | return v; 251 | }; 252 | 253 | var drawStraightLine = function(p1, p2) 254 | { 255 | var v = normalizeVector(getVector(p1, p2)); 256 | var p = new Point(p1.x, p1.y); 257 | var speed = 3; 258 | v.x *= speed; 259 | v.y *= speed; 260 | 261 | ctx.fillRect(p1.x - 5, p1.y - 5, 10, 10); 262 | ctx.fillRect(p2.x - 5, p2.y - 5, 10, 10); 263 | while(p.x !== p2.x || p.y !== p2.y) 264 | { 265 | ctx.fillRect(p.x - 1, p.y - 1, 2, 2); 266 | if((p.x > p2.x && p.x + v.x < p2.x) || (p.x < p2.x && p.x + v.x > p2.x)) 267 | p.x = p2.x; 268 | else 269 | p.x += v.x; 270 | if((p.y > p2.y && p.y + v.y < p2.y) || (p.y < p2.y && p.y + v.y > p2.y)) 271 | p.y = p2.y; 272 | else 273 | p.y += v.y; 274 | } 275 | }; 276 | 277 | var getDistanceFromPoints = function(p1, p2) 278 | { 279 | return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)) 280 | }; 281 | 282 | var checkLineIntersection = function(edge1, edge2) 283 | { 284 | var denominator, a, b, numerator1, numerator2; 285 | var result = { x: null, y: null, inLines: false}; 286 | 287 | var line1StartX = edge1[0].x; 288 | var line1EndX = edge1[1].x; 289 | var line1StartY = edge1[0].y; 290 | var line1EndY = edge1[1].y; 291 | var line2StartX = edge2[0].x; 292 | var line2EndX = edge2[1].x; 293 | var line2StartY = edge2[0].y; 294 | var line2EndY = edge2[1].y; 295 | denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY)); 296 | if (denominator == 0) { 297 | return result; 298 | } 299 | a = line1StartY - line2StartY; 300 | b = line1StartX - line2StartX; 301 | numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b); 302 | numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b); 303 | a = numerator1 / denominator; 304 | b = numerator2 / denominator; 305 | 306 | // if we cast these lines infinitely in both directions, they intersect here: 307 | result.x = line1StartX + (a * (line1EndX - line1StartX)); 308 | result.y = line1StartY + (a * (line1EndY - line1StartY)); 309 | 310 | if ((a > 0 && a < 1) && (b > 0 && b < 1)) 311 | result.inLines = true; 312 | 313 | return result; 314 | }; 315 | 316 | var getNextPointInLine = function(p1, p2, speed) 317 | { 318 | var v = normalizeVector(getVector(p1, p2)); 319 | var p = new Point(p1.x, p1.y); 320 | 321 | if(Math.abs(p1.x - p2.x) < 1 && Math.abs(p1.y - p2.y) < 1) 322 | return p2; 323 | v.x *= speed; 324 | v.y *= speed; 325 | 326 | if((p.x > p2.x && p.x + v.x < p2.x) || (p.x < p2.x && p.x + v.x > p2.x)) 327 | p.x = p2.x; 328 | else 329 | p.x += v.x; 330 | if((p.y > p2.y && p.y + v.y < p2.y) || (p.y < p2.y && p.y + v.y > p2.y)) 331 | p.y = p2.y; 332 | else 333 | p.y += v.y; 334 | 335 | return p; 336 | 337 | }; 338 | 339 | var getLineSlope = function(p1, p2) 340 | { 341 | return (p1.y - p2.y) / (p1.x - p2.x); 342 | }; 343 | 344 | var downloadCroppedImage = function (filename, text) 345 | { 346 | // atob to base64_decode the data-URI 347 | var image_data = atob(text.split(',')[1]); 348 | // Use typed arrays to convert the binary data to a Blob 349 | var arraybuffer = new ArrayBuffer(image_data.length); 350 | var view = new Uint8Array(arraybuffer); 351 | for (var i=0; i"+""+" "+locale.font_styles.normal+" "+""+""+""},emphasis:function(locale,options){var size=options&&options.size?" btn-"+options.size:"";return"
  • "+""+"
  • "},lists:function(locale,options){var size=options&&options.size?" btn-"+options.size:"";return"
  • "+"
    "+""+""+""+""+"
    "+"
  • "},link:function(locale,options){var size=options&&options.size?" btn-"+options.size:"";return"
  • "+""+""+"
  • "},image:function(locale,options){var size=options&&options.size?" btn-"+options.size:"";return"
  • "+""+""+"
  • "},html:function(locale,options){var size=options&&options.size?" btn-"+options.size:"";return"
  • "+"
    "+""+"
    "+"
  • "},color:function(locale,options){var size=options&&options.size?" btn-"+options.size:"";return""}};var templates=function(key,locale,options){return tpl[key](locale,options)};var Wysihtml5=function(el,options){this.el=el;var toolbarOpts=options||defaultOptions;for(var t in toolbarOpts.customTemplates){tpl[t]=toolbarOpts.customTemplates[t]}this.toolbar=this.createToolbar(el,toolbarOpts);this.editor=this.createEditor(options);window.editor=this.editor;$("iframe.wysihtml5-sandbox").each(function(i,el){$(el.contentWindow).off("focus.wysihtml5").on({"focus.wysihtml5":function(){$("li.dropdown").removeClass("open")}})})};Wysihtml5.prototype={constructor:Wysihtml5,createEditor:function(options){options=options||{};options=$.extend(true,{},options);options.toolbar=this.toolbar[0];var editor=new wysi.Editor(this.el[0],options);if(options&&options.events){for(var eventName in options.events){editor.on(eventName,options.events[eventName])}}return editor},createToolbar:function(el,options){var self=this;var toolbar=$("
      ",{"class":"wysihtml5-toolbar",style:"display:none"});var culture=options.locale||defaultOptions.locale||"en";for(var key in defaultOptions){var value=false;if(options[key]!==undefined){if(options[key]===true){value=true}}else{value=defaultOptions[key]}if(value===true){toolbar.append(templates(key,locale[culture],options));if(key==="html"){this.initHtml(toolbar)}if(key==="link"){this.initInsertLink(toolbar)}if(key==="image"){this.initInsertImage(toolbar)}}}if(options.toolbar){for(key in options.toolbar){toolbar.append(options.toolbar[key])}}toolbar.find("a[data-wysihtml5-command='formatBlock']").click(function(e){var target=e.target||e.srcElement;var el=$(target);self.toolbar.find(".current-font").text(el.html())});toolbar.find("a[data-wysihtml5-command='foreColor']").click(function(e){var target=e.target||e.srcElement;var el=$(target);self.toolbar.find(".current-color").text(el.html())});this.el.before(toolbar);return toolbar},initHtml:function(toolbar){var changeViewSelector="a[data-wysihtml5-action='change_view']";toolbar.find(changeViewSelector).click(function(e){toolbar.find("a.btn").not(changeViewSelector).toggleClass("disabled")})},initInsertImage:function(toolbar){var self=this;var insertImageModal=toolbar.find(".bootstrap-wysihtml5-insert-image-modal");var urlInput=insertImageModal.find(".bootstrap-wysihtml5-insert-image-url");var insertButton=insertImageModal.find("a.btn-primary");var initialValue=urlInput.val();var caretBookmark;var insertImage=function(){var url=urlInput.val();urlInput.val(initialValue);self.editor.currentView.element.focus();if(caretBookmark){self.editor.composer.selection.setBookmark(caretBookmark);caretBookmark=null}self.editor.composer.commands.exec("insertImage",url)};urlInput.keypress(function(e){if(e.which==13){insertImage();insertImageModal.modal("hide")}});insertButton.click(insertImage);insertImageModal.on("shown",function(){urlInput.focus()});insertImageModal.on("hide",function(){self.editor.currentView.element.focus()});toolbar.find("a[data-wysihtml5-command=insertImage]").click(function(){var activeButton=$(this).hasClass("wysihtml5-command-active");if(!activeButton){self.editor.currentView.element.focus(false);caretBookmark=self.editor.composer.selection.getBookmark();insertImageModal.appendTo("body").modal("show");insertImageModal.on("click.dismiss.modal",'[data-dismiss="modal"]',function(e){e.stopPropagation()});return false}else{return true}})},initInsertLink:function(toolbar){var self=this;var insertLinkModal=toolbar.find(".bootstrap-wysihtml5-insert-link-modal");var urlInput=insertLinkModal.find(".bootstrap-wysihtml5-insert-link-url");var insertButton=insertLinkModal.find("a.btn-primary");var initialValue=urlInput.val();var caretBookmark;var insertLink=function(){var url=urlInput.val();urlInput.val(initialValue);self.editor.currentView.element.focus();if(caretBookmark){self.editor.composer.selection.setBookmark(caretBookmark);caretBookmark=null}self.editor.composer.commands.exec("createLink",{href:url,target:"_blank",rel:"nofollow"})};var pressedEnter=false;urlInput.keypress(function(e){if(e.which==13){insertLink();insertLinkModal.modal("hide")}});insertButton.click(insertLink);insertLinkModal.on("shown",function(){urlInput.focus()});insertLinkModal.on("hide",function(){self.editor.currentView.element.focus()});toolbar.find("a[data-wysihtml5-command=createLink]").click(function(){var activeButton=$(this).hasClass("wysihtml5-command-active");if(!activeButton){self.editor.currentView.element.focus(false);caretBookmark=self.editor.composer.selection.getBookmark();insertLinkModal.appendTo("body").modal("show");insertLinkModal.on("click.dismiss.modal",'[data-dismiss="modal"]',function(e){e.stopPropagation()});return false}else{return true}})}};var methods={resetDefaults:function(){$.fn.wysihtml5.defaultOptions=$.extend(true,{},$.fn.wysihtml5.defaultOptionsCache)},bypassDefaults:function(options){return this.each(function(){var $this=$(this);$this.data("wysihtml5",new Wysihtml5($this,options))})},shallowExtend:function(options){var settings=$.extend({},$.fn.wysihtml5.defaultOptions,options||{});var that=this;return methods.bypassDefaults.apply(that,[settings])},deepExtend:function(options){var settings=$.extend(true,{},$.fn.wysihtml5.defaultOptions,options||{});var that=this;return methods.bypassDefaults.apply(that,[settings])},init:function(options){var that=this;return methods.shallowExtend.apply(that,[options])}};$.fn.wysihtml5=function(method){if(methods[method]){return methods[method].apply(this,Array.prototype.slice.call(arguments,1))}else if(typeof method==="object"||!method){return methods.init.apply(this,arguments)}else{$.error("Method "+method+" does not exist on jQuery.wysihtml5")}};$.fn.wysihtml5.Constructor=Wysihtml5;var defaultOptions=$.fn.wysihtml5.defaultOptions={"font-styles":true,color:false,emphasis:true,lists:true,html:false,link:true,image:true,events:{},parserRules:{classes:{"wysiwyg-color-silver":1,"wysiwyg-color-gray":1,"wysiwyg-color-white":1,"wysiwyg-color-maroon":1,"wysiwyg-color-red":1,"wysiwyg-color-purple":1,"wysiwyg-color-fuchsia":1,"wysiwyg-color-green":1,"wysiwyg-color-lime":1,"wysiwyg-color-olive":1,"wysiwyg-color-yellow":1,"wysiwyg-color-navy":1,"wysiwyg-color-blue":1,"wysiwyg-color-teal":1,"wysiwyg-color-aqua":1,"wysiwyg-color-orange":1},tags:{b:{},i:{},br:{},ol:{},ul:{},li:{},h1:{},h2:{},h3:{},blockquote:{},u:1,img:{check_attributes:{width:"numbers",alt:"alt",src:"url",height:"numbers"}},a:{set_attributes:{target:"_blank",rel:"nofollow"},check_attributes:{href:"url"}},span:1,div:1,code:1,pre:1}},stylesheets:["./lib/css/wysiwyg-color.css"],locale:"en"};if(typeof $.fn.wysihtml5.defaultOptionsCache==="undefined"){$.fn.wysihtml5.defaultOptionsCache=$.extend(true,{},$.fn.wysihtml5.defaultOptions)}var locale=$.fn.wysihtml5.locale={en:{font_styles:{normal:"Normal text",h1:"Heading 1",h2:"Heading 2",h3:"Heading 3"},emphasis:{bold:"Bold",italic:"Italic",underline:"Underline"},lists:{unordered:"Unordered list",ordered:"Ordered list",outdent:"Outdent",indent:"Indent"},link:{insert:"Insert link",cancel:"Cancel"},image:{insert:"Insert image",cancel:"Cancel"},html:{edit:"Edit HTML"},colours:{black:"Black",silver:"Silver",gray:"Grey",maroon:"Maroon",red:"Red",purple:"Purple",green:"Green",olive:"Olive",navy:"Navy",blue:"Blue",orange:"Orange"}}}}(window.jQuery,window.wysihtml5); -------------------------------------------------------------------------------- /js/script-manager.js: -------------------------------------------------------------------------------- 1 | var editorScriptList = { }; 2 | 3 | var ScriptTree = function(scriptElement) 4 | { 5 | this.children = new Array(); 6 | this.scriptElement = scriptElement; 7 | this.type = null; 8 | }; 9 | 10 | var Script = function(code, scriptTriggerers) 11 | { 12 | //this.scriptTree = scriptTree; 13 | this.code = code; 14 | this.scriptTriggerers = scriptTriggerers; 15 | }; 16 | 17 | var ScriptElement = function(f, params) 18 | { 19 | this.f = f; 20 | this.params = params; 21 | this.execute = function(abort, callback) { 22 | window[f].apply(this, params.concat([abort]).concat([callback])); 23 | }; 24 | }; 25 | 26 | var ScriptTriggerer = function(type, params) 27 | { 28 | this.type = type; 29 | this.params = params; 30 | }; 31 | 32 | var Aggregator = function(type, body, cond) 33 | { 34 | this.body = body; 35 | this.type = type; 36 | this.processIdx = 0; 37 | this.execute = function(check, callback) 38 | { 39 | if(this.type == 'Parallel') 40 | { 41 | var interruptibleCount = 0; 42 | var completedInterruptible = 0; 43 | for(var i = 0; i < body.length; i++) 44 | { 45 | if(body[i].type == 'atomic') 46 | body[i].f(); 47 | if(body[i].type == 'interruptible') 48 | { 49 | interruptibleCount++; 50 | var dfd = $.Deferred(); 51 | dfd.done(function() 52 | { 53 | completedInterruptible++; 54 | if(completedInterruptible == interruptibleCount) 55 | callback.resolve(); 56 | }); 57 | body[i].f(dfd); 58 | } 59 | } 60 | if(interruptibleCount == 0) 61 | callback.resolve(); 62 | return; 63 | } 64 | if(this.type == 'If' && check == true) 65 | { 66 | if(!eval(cond)) 67 | return; 68 | } 69 | for (var i = this.processIdx; i < body.length; i++) 70 | if(body[i].type == 'atomic') 71 | body[i].f(); 72 | else if(body[i].type == 'interruptible' || body[i].type == 'Parallel') 73 | { 74 | var dfd = $.Deferred(); 75 | var that = this; 76 | dfd.done(function() 77 | { 78 | that.processIdx = i + 1; 79 | if(that.processIdx == that.body.length) 80 | { 81 | that.processIdx = 0; 82 | if(callback) 83 | callback.resolve(); 84 | } 85 | else 86 | that.execute(false, callback); 87 | }); 88 | if(body[i].type == 'interruptible') 89 | body[i].f(dfd); 90 | else 91 | body[i].execute(false, dfd); 92 | return; 93 | } 94 | else if(body[i].type == 'If') 95 | { 96 | body[i].execute(true, callback); 97 | } 98 | this.processIdx = 0; 99 | if(callback) 100 | callback.resolve(); 101 | } 102 | }; 103 | 104 | var scriptTreeInterpreter = function(scriptTree) 105 | { 106 | if(!scriptTree) 107 | return null; 108 | 109 | if (scriptTree.type == 'game-controllers') { 110 | if (scriptTree.scriptElement.f == 'Aggregator') { 111 | var body = []; 112 | 113 | for (var i = 0; i < scriptTree.children.length; i++) 114 | body.push(scriptTreeInterpreter(scriptTree.children[i])); 115 | 116 | return new Aggregator(scriptTree.scriptElement.params[0], body, true); 117 | } 118 | else if (scriptTree.scriptElement.f == 'If') 119 | { 120 | var expr = new Parser().parse(scriptTree.scriptElement.params[0]); 121 | if(expr.valid == false) 122 | throwError('Bad if-guard: \"' + scriptTree.scriptElement.params[0] + '\"')(); 123 | var body = []; 124 | 125 | for (var i = 0; i < scriptTree.children.length; i++) 126 | body.push(scriptTreeInterpreter(scriptTree.children[i])); 127 | return new Aggregator('If', body, scriptTree.scriptElement.params[0]); 128 | 129 | } 130 | else 131 | { 132 | throwError('Error: bad scriptTree.')(); 133 | } 134 | } 135 | else if (scriptTree.type == 'game-side-effects') { 136 | //if (scriptTree.scriptElement.f === 'waitEvent') 137 | // return evreact.expr.simple({});//events[scriptTree.scriptElement.params[0]]); 138 | if (scriptTree.scriptElement.f in atomicEffects) 139 | return {type : 'atomic', f : function() { 140 | atomicEffects[scriptTree.scriptElement.f].apply(null, scriptTree.scriptElement.params) }}; 141 | if (scriptTree.scriptElement.f in interruptibleEffects) 142 | return {type : 'interruptible', f : function(dfd) { 143 | interruptibleEffects[scriptTree.scriptElement.f].apply(null, scriptTree.scriptElement.params.concat([[], dfd])) }}; 144 | (function() { var errMsg = "Unknown side effect: " + scriptTree.scriptElement.f; alert(errMsg); throw errMsg; })(); 145 | 146 | return null; 147 | } 148 | 149 | 150 | }; 151 | 152 | var scriptTriggererInterpreter = function(triggerer) 153 | { 154 | var definedTriggerer = { type : triggerer.type }; 155 | 156 | switch(triggerer.type) 157 | { 158 | case 'user-trigger': 159 | definedTriggerer.action = triggerer.params[0]; 160 | definedTriggerer.obj1 = triggerer.params[1]; 161 | definedTriggerer.sentence = triggerer.params[4]; 162 | 163 | if(triggerer.params[2]) 164 | { 165 | definedTriggerer.obj2 = triggerer.params[3]; 166 | } 167 | break; 168 | case 'event-trigger': 169 | definedTriggerer.eventName = triggerer.params[0]; 170 | break; 171 | case 'timer-trigger': 172 | break; 173 | case 'enter-room-trigger': 174 | case 'exit-room-trigger': 175 | definedTriggerer.roomId = triggerer.params[0]; 176 | break; 177 | } 178 | return definedTriggerer; 179 | }; 180 | 181 | var scriptInterpreter = function(script, scriptMap) 182 | { 183 | if(!script) 184 | return null; 185 | //var scriptBody = scriptTreeInterpreter(script.scriptTree); 186 | var scriptHeader = scriptTriggerersInterpreter(script.scriptTriggerers); 187 | 188 | for(var i = 0; i < scriptHeader.length; i++) 189 | { 190 | switch(scriptHeader[i].type) 191 | { 192 | case 'user-trigger': 193 | if 194 | (scriptHeader[i].obj2) 195 | { 196 | if (!scriptMap[scriptHeader[i].action][scriptHeader[i].obj1]) 197 | scriptMap[scriptHeader[i].action][scriptHeader[i].obj1] = {}; 198 | scriptMap[scriptHeader[i].action][scriptHeader[i].obj1][scriptHeader[i].obj2] = { code: script.code, sentence: scriptHeader[i].sentence}; 199 | } 200 | else 201 | switch (scriptHeader[i].action) 202 | { 203 | case 'Mouse click': 204 | testMapIdItem[scriptHeader[i].obj1].onClick = { code: script.code, sentence: null }; 205 | break; 206 | case 'Mouse hover': 207 | testMapIdItem[scriptHeader[i].obj1].onHover = { code: script.code, sentence: null }; 208 | break; 209 | case 'Walk on': 210 | testMapIdItem[scriptHeader[i].obj1].onWalk = { code: script.code, sentence: null }; 211 | break; 212 | default: 213 | scriptMap[scriptHeader[i].action][scriptHeader[i].obj1] = { code: script.code, sentence: scriptHeader[i].sentence}; 214 | break; 215 | } 216 | break; 217 | case 'event-trigger': 218 | if(!('Events' in scriptMap)) 219 | scriptMap['Events'] = {}; 220 | scriptMap['Events'][scriptHeader[i].eventName] = script.code; 221 | break; 222 | case 'enter-room-trigger': 223 | if(!('EnterRoom' in scriptMap)) 224 | scriptMap['EnterRoom'] = {}; 225 | scriptMap['EnterRoom'][scriptHeader[i].roomId] = script.code; 226 | break; 227 | case 'exit-room-trigger': 228 | break; 229 | 230 | } 231 | } 232 | 233 | return { code : script.code }; 234 | }; 235 | 236 | var scriptTriggerersInterpreter = function(scriptTriggerers) 237 | { 238 | var triggerers = []; 239 | for(var i = 0; i < scriptTriggerers.length; i++) 240 | triggerers.push(scriptTriggererInterpreter(scriptTriggerers[i])); 241 | return triggerers; 242 | }; 243 | 244 | var replaceScriptOccurrencies = function(script, type, oldId, newId) 245 | { 246 | return; 247 | replaceScriptBodyOccurrencies(script.scriptTree, type, oldId, newId); 248 | replaceScriptTriggerersOccurrencies(script.scriptTriggerers, type, oldId, newId) 249 | }; 250 | 251 | var replaceScriptBodyOccurrencies = function(scriptTree, type, oldId, newId) 252 | { 253 | return; 254 | var length = scriptTree.children.length; 255 | 256 | for(var i = 0; i < length; i++) 257 | replaceScriptBodyOccurrencies(scriptTree.children[i], type, oldId, newId); 258 | 259 | var scriptElement = scriptTree.scriptElement; 260 | 261 | if(scriptElement.f == 'Aggregator') 262 | return; 263 | 264 | switch(type) 265 | { 266 | case 'item': 267 | switch(scriptElement.f) 268 | { 269 | case 'setPosition': 270 | case 'walkToPos': 271 | case 'sayLine': 272 | case 'show': 273 | case 'hide': 274 | case 'setState': 275 | if(scriptElement.params[0] == oldId) 276 | scriptElement.params[0] = newId; 277 | break; 278 | case 'walkToObj': 279 | if(scriptElement.params[0] == oldId) 280 | scriptElement.params[0] = newId; 281 | if(scriptElement.params[1] == oldId) 282 | scriptElement.params[1] = newId; 283 | break; 284 | } 285 | break; 286 | case 'room': 287 | switch(scriptElement.f) 288 | { 289 | case 'setPosition': 290 | if(scriptElement.params[1] == oldId) 291 | scriptElement.params[1] = newId; 292 | break; 293 | case 'setRoom': 294 | if(scriptElement.params[0] == oldId) 295 | scriptElement.params[0] = newId; 296 | break; 297 | 298 | } 299 | break; 300 | case 'inventoryItem': 301 | switch(scriptElement.f) 302 | { 303 | case 'inventoryAdd': 304 | case 'inventoryRemove': 305 | if(scriptElement.params[0] == oldId) 306 | scriptElement.params[0] = newId; 307 | break; 308 | } 309 | break; 310 | case 'dialog': 311 | switch(scriptElement.f) 312 | { 313 | case 'openDialog': 314 | if(scriptElement.params[0] == oldId) 315 | scriptElement.params[0] = newId; 316 | break; 317 | } 318 | default: 319 | break; 320 | } 321 | }; 322 | 323 | var replaceScriptTriggerersOccurrencies = function(scriptTriggerers, type, oldId, newId) 324 | { 325 | switch(type) 326 | { 327 | case 'inventoryItem': 328 | case 'item': 329 | for(var i = 0; i < scriptTriggerers.length; i++) 330 | { 331 | if(scriptTriggerers[i].type != 'user-trigger') 332 | continue; 333 | if(scriptTriggerers[i].params[1] == oldId) 334 | scriptTriggerers[i].params[1] = newId; 335 | if(scriptTriggerers[i].params[3] == oldId) 336 | scriptTriggerers[i].params[3] = newId; 337 | } 338 | break; 339 | } 340 | }; 341 | 342 | var SortedSequence = function(body, callback) 343 | { 344 | this.processIdx = 0; 345 | this.body = body; 346 | 347 | this.execute = function() 348 | { 349 | for (var i = this.processIdx; i < body.length; i++) 350 | { 351 | if (!body[i].hasOwnProperty('params')) 352 | body[i].f(); 353 | else 354 | { 355 | if(body[i].f in atomicEffects) 356 | { 357 | atomicEffects[body[i].f].apply(null, body[i].params); 358 | continue; 359 | } 360 | var dfd = $.Deferred(); 361 | var that = this; 362 | dfd.done(function () { that.execute(); }); 363 | that.processIdx = i + 1; 364 | interruptibleEffects[body[i].f].apply(null, body[i].params.concat([ 365 | [], 366 | dfd 367 | ])); 368 | 369 | return; 370 | } 371 | } 372 | if(callback) 373 | callback(); 374 | } 375 | }; 376 | 377 | var Sequence = function(body) 378 | { 379 | new SortedSequence(body, function() 380 | { 381 | if(guiObj.listening === false) 382 | enableInput(); 383 | if(guiObj.dialogOpen) 384 | { 385 | openDialog(guiObj.dialogOpen); 386 | } 387 | }).execute(); 388 | }; 389 | -------------------------------------------------------------------------------- /js/project.js: -------------------------------------------------------------------------------- 1 | var resolution = { width : 1024, height : 768 }; 2 | 3 | var newProject = function() 4 | { 5 | $('#room-accordion').empty(); 6 | for(var room in editorMapIdRoom) 7 | { 8 | deleteEditorRoom(room); 9 | view_UpdateDataLists('delete', 'rooms', room); 10 | editorRoomsCount = 0; 11 | editorItemsCount = 0; 12 | } 13 | $('#character-accordion').empty(); 14 | for(var character in editorMapIdCharacter) 15 | { 16 | deleteEditorCharacter(character); 17 | } 18 | $('#anims-accordion').empty(); 19 | for(var anim in editorMapIdAnim) 20 | { 21 | deleteEditorAnim(anim); 22 | view_UpdateDataLists('delete', 'anims', anim); 23 | } 24 | $('#inventory-accordion').empty(); 25 | for(var invItem in editorMapIdInvItem) 26 | { 27 | deleteInvItem(invItem); 28 | view_UpdateDataLists('delete', 'inventory-items', invItem); 29 | editorInvItemCount = 0; 30 | } 31 | $('#dialog-accordion').empty(); 32 | for(var dialog in editorMapIdDialog) 33 | { 34 | deleteDialog(dialog); 35 | view_UpdateDataLists('delete', 'dialogs', dialog); 36 | editorDialogsCount = 0; 37 | } 38 | $('#audio-container').empty(); 39 | for(var audio in editorMapIdAudio) 40 | { 41 | deleteAudioContent(audio) 42 | view_UpdateDataLists('delete', 'audio', audio); 43 | } 44 | for(var script in editorScriptList) 45 | { 46 | view_UpdateDataLists('delete', 'scripts', script); 47 | } 48 | editorScriptList = {}; 49 | }; 50 | 51 | var saveProject = function() 52 | { 53 | var backupRooms = owl.deepCopy(editorRoomsList); 54 | var backupCharacters = owl.deepCopy(editorCharactersList); 55 | var backupAnims = owl.deepCopy(editorAnimsList); 56 | 57 | for(var i in backupRooms) 58 | { 59 | eliminateCycles(backupRooms[i], 'room'); 60 | delete backupRooms[i].zOrderMap; 61 | } 62 | for(var i = 0; i < backupAnims.length; i++) 63 | eliminateCycles(backupAnims[i], 'anim'); 64 | 65 | view_SaveGameVariables(); 66 | var project = { resolution : JSON.stringify(resolution), rooms : JSON.stringify(backupRooms), actions: JSON.stringify(editorActionsList), characters: JSON.stringify(backupCharacters), scripts: JSON.stringify(editorScriptList), vars : JSON.stringify(editorGameVars), anims: JSON.stringify(backupAnims), inv_items : JSON.stringify(editorInvItemList), dialogs : JSON.stringify(editorMapIdDialog), audio : JSON.stringify(editorMapIdAudio) }; 67 | download('project.json', JSON.stringify(project)); 68 | }; 69 | 70 | var loadProject = function(event) 71 | { 72 | newProject(); 73 | var fileReader = new FileReader(); 74 | fileReader.onload = function(event) 75 | { 76 | var s = event.target.result; 77 | var project = JSON.parse(s); 78 | if(project.resolution) 79 | resolution = JSON.parse(project.resolution); 80 | editorRoomsList = JSON.parse(project.rooms); 81 | editorMapIdRoom = {}; 82 | editorMapIdItem = {}; 83 | editorCurrentRoom = null; 84 | editorCurrentItem = null; 85 | editorRoomsCount = 0; 86 | editorItemsCount = 0; 87 | editorInvItemList = JSON.parse(project.inv_items); 88 | editorInvItemCount = 0; 89 | editorCharactersList = JSON.parse(project.characters); 90 | editorMapIdCharacter = {}; 91 | editorAnimsList = JSON.parse(project.anims); 92 | editorMapIdAnim = {}; 93 | editorAnimsCount = 0; 94 | editorScriptList = JSON.parse(project.scripts); 95 | if(project.dialogs) 96 | editorMapIdDialog = JSON.parse(project.dialogs); 97 | if(project.audio) 98 | editorMapIdAudio = JSON.parse(project.audio); 99 | 100 | if(project.vars) editorGameVars = JSON.parse(project.vars); 101 | view_ClearRoomPanels(); 102 | 103 | for(var i = 0; i < editorAnimsList.length; i++) 104 | { 105 | editorAnimsList[i].addFrame = addAnimFrame; 106 | editorAnimsList[i].removeFrame = removeAnimFrame; 107 | editorAnimsList[i].incrCurrIdx = incrCurrFrame; 108 | editorAnimsList[i].play = startRollingFrames; 109 | editorAnimsList[i].stop = stopRollingFrames; 110 | 111 | for(var j = 0; j < editorAnimsList[i].frames.length; j++) 112 | { 113 | var frame = editorAnimsList[i].frames[j]; 114 | if(frame) 115 | { 116 | var img = new Image(); 117 | img.src = frame.img; 118 | //var newFrame = new EditorSprite(img); 119 | //newFrame.setPosition(frame.boundingBox[1], frame.boundingBox[2]); 120 | //newFrame.setSize(frame.boundingBox[3], frame.boundingBox[4]); 121 | //editorAnimsList[i].frames[j] = newFrame; 122 | editorAnimsList[i].frames[j] = {img: img}; 123 | } 124 | } 125 | editorMapIdAnim[editorAnimsList[i].id] = editorAnimsList[i]; 126 | view_CreateNewAnimPanel(editorAnimsList[i].id); 127 | editorAnimsCount++; 128 | } 129 | 130 | for(var i = 0; i < editorCharactersList.length; i++) 131 | { 132 | var currentCharacter = editorCharactersList[i]; 133 | currentCharacter.getCurrentFrame = getItemCurrentFrame; 134 | currentCharacter.setLayer = setItemLayer; 135 | for(var j in currentCharacter.sprites) 136 | for(var k in currentCharacter.sprites[j]) 137 | { 138 | var src = currentCharacter.sprites[j][k].img; 139 | var img = new Image(); 140 | img.src = src; 141 | //var sprite = new EditorSprite(img); 142 | //sprite.setPosition(currentCharacter.sprites[j][k].boundingBox[1], currentCharacter.sprites[j][k].boundingBox[2]); 143 | //sprite.setSize(currentCharacter.sprites[j][k].boundingBox[3], currentCharacter.sprites[j][k].boundingBox[4]); 144 | //currentCharacter.sprites[j][k] = sprite; 145 | currentCharacter.sprites[j][k] = {img: img}; 146 | }; 147 | 148 | var hotspot = currentCharacter.hotspot; 149 | 150 | if(hotspot != null) 151 | { 152 | var hotspotCopy = new Polygon(); 153 | for (var k = 0; k < hotspot.points.length; k++) 154 | hotspotCopy.points[k] = new paper.Point(hotspot.points[k][1], hotspot.points[k][2]); 155 | if(hotspot.closed) 156 | hotspotCopy.close(); 157 | editorCharactersList[i].hotspot = hotspotCopy; 158 | } 159 | editorMapIdCharacter[editorCharactersList[i].id] = editorCharactersList[i]; 160 | view_CreateNewCharacterPanel(editorCharactersList[i].id); 161 | } 162 | 163 | for(var i in editorRoomsList) 164 | { 165 | editorRoomsList[i].setId = setId; 166 | editorRoomsList[i].zOrderMap = {}; 167 | if(editorRoomsList[i].walkBehinds == undefined) // Project backward compatibility 168 | editorRoomsList[i].walkBehinds = []; 169 | editorMapIdRoom[editorRoomsList[i].id] = editorRoomsList[i]; 170 | editorRoomsCount++; 171 | 172 | view_CreateNewRoomPanel(editorRoomsList[i].id); 173 | 174 | if(editorRoomsList[i].walkablePath != null) 175 | { 176 | var path = editorRoomsList[i].walkablePath; 177 | var pathCopy = new Polygon(); 178 | 179 | for(var j = 0; j < path.points.length; j++) 180 | pathCopy.points[j] = new paper.Point(path.points[j][1], path.points[j][2]); 181 | if(path.closed) 182 | pathCopy.close(); 183 | 184 | if(path.holes.length) 185 | { 186 | var holesCopy = []; 187 | 188 | for(var j = 0; j < path.holes.length; j++) 189 | { 190 | var hole = path.holes[j]; 191 | var newHole = new Polygon(); 192 | 193 | for(var k = 0; k < hole.points.length; k++) 194 | { 195 | newHole.points[k] = new paper.Point(hole.points[k][1], hole.points[k][2]); 196 | } 197 | holesCopy[j] = newHole; 198 | if(hole.closed) 199 | newHole.close(); 200 | } 201 | 202 | pathCopy.holes = holesCopy; 203 | } 204 | editorRoomsList[i].walkablePath = pathCopy; 205 | } 206 | var bg = editorRoomsList[i].items[0]; 207 | if(bg) 208 | { 209 | var src = bg.img; 210 | var img = new Image(); 211 | img.src = src; 212 | editorRoomsList[i].items[0] = {img : img, boundingBox : new paper.Rectangle(bg.boundingBox[1], bg.boundingBox[2], bg.boundingBox[3], bg.boundingBox[4])}; 213 | } 214 | for(var j = 1; j < editorRoomsList[i].items.length; j++) 215 | { 216 | editorRoomsList[i].items[j].setLayer = setItemLayer; 217 | editorRoomsList[i].items[j].getCurrentFrame = getItemCurrentFrame; 218 | for(var key in editorRoomsList[i].items[j].defaultAnims) 219 | 220 | //if(animsDefined) 221 | //{ 222 | if (editorRoomsList[i].zOrderMap[editorRoomsList[i].items[j].layer] == undefined) 223 | editorRoomsList[i].zOrderMap[editorRoomsList[i].items[j].layer] = []; 224 | editorRoomsList[i].zOrderMap[editorRoomsList[i].items[j].layer].push(editorRoomsList[i].items[j].id); 225 | //} 226 | editorMapIdItem[editorRoomsList[i].items[j].id] = editorRoomsList[i].items[j]; 227 | view_CreateEditorItemPanel(editorRoomsList[i].items[j].id, editorRoomsList[i].id); 228 | editorItemsCount++; 229 | 230 | var hotspot = editorRoomsList[i].items[j].hotspot; 231 | 232 | if(hotspot != null) 233 | { 234 | var hotspotCopy = new Polygon(); 235 | for (var k = 0; k < hotspot.points.length; k++) 236 | hotspotCopy.points[k] = new paper.Point(hotspot.points[k][1], hotspot.points[k][2]); 237 | if(hotspot.closed) 238 | hotspotCopy.close(); 239 | editorRoomsList[i].items[j].hotspot = hotspotCopy; 240 | } 241 | } 242 | for(var j = 0; j < editorRoomsList[i].walkBehinds.length; j++) 243 | { 244 | var wb = editorRoomsList[i].walkBehinds[j]; 245 | editorMapIdWb[wb.id] = wb; 246 | for(var k = 0; k < wb.poly.points.length; k++) 247 | wb.poly.points[k] = new paper.Point(wb.poly.points[k][1], wb.poly.points[k][2]); 248 | view_CreateEditorWBPanel(wb.id, editorRoomsList[i].id); 249 | editorWbCount++; 250 | } 251 | for(var j in editorRoomsList[i].walkBoxes) 252 | { 253 | var wbox = editorRoomsList[i].walkBoxes[j]; 254 | var polyCopy = new Polygon(); 255 | for(var k = 0; k < wbox.polygon.points.length; k++) 256 | polyCopy.points[k] = new paper.Point(wbox.polygon.points[k][1], wbox.polygon.points[k][2]); 257 | if(wbox.polygon.closed) 258 | polyCopy.close(); 259 | /*for(var k = 0; k < wbox.polygon.edges.length; k++) 260 | { 261 | polyCopy.edges[k] = [ new paper.Point(wbox.polygon.edges[k][0][1], wbox.polygon.edges[k][0][2]), 262 | new paper.Point(wbox.polygon.edges[k][1][1], wbox.polygon.edges[k][1][2])]; 263 | }*/ 264 | editorRoomsList[i].walkBoxes[j].polygon = polyCopy; 265 | view_CreateEditorWalkBoxPanel(wbox.id, editorRoomsList[i].id); 266 | //editorWbCount++; 267 | } 268 | } 269 | 270 | for(var i = 0; i < editorInvItemList.length; i++) 271 | { 272 | editorMapIdInvItem[editorInvItemList[i].id] = editorInvItemList[i]; 273 | view_CreateNewInvItemPanel(editorInvItemList[i].id); 274 | editorInvItemCount++; 275 | } 276 | 277 | for(var key in editorScriptList) 278 | { 279 | //$('#datalist-game-scripts').append($(document.createElement('option')).append(key)); 280 | view_UpdateDataLists('add', 'scripts', key); 281 | } 282 | 283 | for(var key in editorMapIdDialog) 284 | { 285 | var d = new Dialog(); 286 | d.copy(editorMapIdDialog[key]); 287 | editorMapIdDialog[key] = d; 288 | editorDialogsCount++; 289 | view_CreateNewDialogPanel(d.id); 290 | } 291 | 292 | view_LoadGameVariables(); 293 | 294 | $('#game-resolution')[0].value = resolution.width + 'x' + resolution.height; 295 | $('#game-resolution').change(); 296 | 297 | for(var key in editorMapIdAudio) 298 | { 299 | view_AddNewSound(editorMapIdAudio[key].audioData, editorMapIdAudio[key].id); 300 | } 301 | }; 302 | 303 | fileReader.readAsText(event.target.files[0]); 304 | }; 305 | 306 | var eliminateCycles = function(data, dataType) 307 | { 308 | switch(dataType) 309 | { 310 | case 'room': 311 | if(data.items[0] != null) 312 | data.items[0].img = data.items[0].img.src; 313 | break; 314 | case 'character': 315 | if(data.sprite != null) 316 | data.sprite.img = data.sprite.img.src; 317 | for(var i in data.sprites) 318 | for(var j in data.sprites[i]) 319 | if(data.sprites[i][j]) 320 | data.sprites[i][j].img = data.sprites[i][j].img.src; 321 | else delete data.sprites[i][j]; 322 | break; 323 | case 'anim': 324 | for(var i = 0; i < data.frames.length; i++) 325 | if(data.frames[i]) 326 | data.frames[i].img = data.frames[i].img.src; 327 | break; 328 | } 329 | }; 330 | 331 | var download = function (filename, text) 332 | { 333 | var blob = new Blob([text], {type : 'text/html'}); 334 | var pom = document.createElement('a'); 335 | //pom.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(text)); 336 | pom.setAttribute('href', URL.createObjectURL(blob)); 337 | pom.setAttribute('download', filename); 338 | pom.click(); 339 | }; -------------------------------------------------------------------------------- /js/sideEffects-manager.js: -------------------------------------------------------------------------------- 1 | var setPosition = function(itemId, roomId, xPos, yPos) 2 | { 3 | var oldX = null, oldY = null; 4 | var item = testMapIdItem[itemId]; 5 | var sprite = item.getCurrentFrame(); 6 | 7 | if(sprite != null) 8 | { 9 | oldX = item.position.x; 10 | oldY = item.position.y; 11 | 12 | item.position.x = xPos; 13 | item.position.y = yPos; 14 | 15 | var hotspot = item.hotspot; 16 | if(hotspot != null) 17 | { 18 | var offsetX = xPos - oldX; 19 | var offsetY = yPos - oldY; 20 | 21 | for (var i = 0; i < hotspot.length; i++) 22 | translate(hotspot[i], offsetX, offsetY); 23 | } 24 | 25 | // The destination room is the current room 26 | /*if(roomId == testMapIdRoom[currentCharacter.parentRoomId].id) 27 | { 28 | if(hotspot != null) 29 | { 30 | var oldPoly = $('#' + itemId + '-hotspot')[0]; 31 | if(!oldPoly) 32 | return; 33 | for(var i = 0; i < oldPoly.points.length; i++) 34 | translate(oldPoly.points[i], offsetX, offsetY); 35 | 36 | } 37 | }*/ 38 | 39 | if(itemId == currentCharacter.id) 40 | { 41 | testMapIdItem[currentCharacter.id].onScreen = false; 42 | if(currentCharacter.parentRoomId !== roomId) // We're changing room here 43 | setCurrentRoom(roomId); 44 | //setObjectLocation(itemId, roomId); 45 | 46 | //drawScene(); 47 | } 48 | 49 | // The destination room is NOT the current room and the item to move there IS in the current room 50 | else if(testMapIdRoom[currentCharacter.parentRoomId].id == item.parentRoomId) 51 | { 52 | item.parentRoomId = roomId; 53 | } 54 | } 55 | 56 | }; 57 | 58 | var walkToPos = function(itemId, xPos, yPos, abort, callback) 59 | { 60 | var item = testMapIdItem[itemId]; 61 | var sprite = getItemPlaceHolder(item); 62 | if(!sprite) 63 | return; 64 | var start = item.position;//getWalkboxFromPoint(testCurrentRoom.walkBoxes, getBottomMiddlePos(itemId))//testCurrentRoom.walkablePath.getNearestLeaf(getBottomMiddlePos(itemId)); 65 | start = new Point(start.x, start.y); 66 | var goal = new Point(xPos, yPos);//getWalkboxFromPoint(testCurrentRoom.walkBoxes, destPoint); 67 | var nextPath = pathfinder.aStar(testCurrentRoom.walkBoxes, start, goal); 68 | //var currPath = testMapIdItem[itemId].path; 69 | if(nextPath.length == 0) 70 | { 71 | if(callback) 72 | { 73 | if(callback.resolve) 74 | callback.resolve(); 75 | else callback(); 76 | } 77 | return; 78 | } 79 | 80 | if(nextPath.length == 1) 81 | { 82 | var pos = item.position; 83 | if(nextPath[0].x === pos.x && nextPath[0].y === pos.y) 84 | { 85 | if(callback) 86 | { 87 | if(callback.resolve) 88 | callback.resolve(); 89 | else callback(); 90 | } 91 | return; 92 | } 93 | } 94 | 95 | var slope = getLineSlope(item.position, nextPath[0]); 96 | if (slope <= MAX_SLOPE && slope >= MIN_SLOPE ) 97 | { 98 | if (item.position.x < nextPath[0].x) 99 | setDirection(item.id, 'right'); 100 | else 101 | setDirection(item.id, 'left'); 102 | } 103 | else if(item.position.y < nextPath[0].y) 104 | setDirection(item.id, 'front'); 105 | else 106 | setDirection(item.id, 'back'); 107 | clearInterval(item.walkInt); 108 | item.path = nextPath; 109 | if(testMapIdItem[itemId].state == 'walk') 110 | { 111 | currentCharacter.walkInt = setInterval(function() {updatePath(item, callback)}, 25); 112 | return; 113 | } 114 | startPath(item, callback); 115 | }; 116 | 117 | var walkToObj = function(walkingItemId, destItemId, abort, callback) 118 | { 119 | var destItem = testMapIdItem[destItemId]; 120 | if(destItem.walkspot.x == null || destItem.walkspot.y == null) 121 | throwError('Error: bad walking spot for item ' + destItemId)(); 122 | else walkToPos(walkingItemId, destItem.walkspot.x, destItem.walkspot.y, abort, callback); 123 | }; 124 | 125 | var egoWalkToObj = function(destItemId, abort, callback) 126 | { 127 | walkToObj(currentCharacter.id, destItemId, abort, callback); 128 | }; 129 | 130 | var egoWalkToPos = function (xPos, yPos, abort, callback) 131 | { 132 | walkToPos(currentCharacter.id, xPos, yPos, abort, callback); 133 | }; 134 | 135 | var show = function(itemId) 136 | { 137 | var item = testMapIdItem[itemId]; 138 | item.visible = true; 139 | }; 140 | 141 | var hide = function(itemId) 142 | { 143 | //console.log('hide' + openB + itemId + closedB); 144 | var item = testMapIdItem[itemId]; 145 | item.visible = false; 146 | }; 147 | 148 | var inventoryAdd = function(itemId) 149 | { 150 | if(!(itemId in testMapIdInvItem)) 151 | throwError('Error: inventory item \"' + itemId + '\" is not defined. -> inventoryAdd')(); 152 | currentCharacter.inventory.push(itemId); 153 | 154 | switch(guiObj.type) 155 | { 156 | case 'MI2': 157 | drawInventory(); 158 | break; 159 | case 'CMI': 160 | guiObj.inventoryPush(itemId); 161 | break; 162 | } 163 | 164 | }; 165 | 166 | var inventoryRemove = function(itemId) 167 | { 168 | if(!(itemId in testMapIdInvItem)) 169 | throwError('Error: inventory item \"' + itemId + '\" is not defined. -> inventoryAdd')(); 170 | currentCharacter.inventory.splice(currentCharacter.inventory.indexOf(itemId), 1); 171 | }; 172 | 173 | var egoSayLine = function(sentence, abort, callback) 174 | { 175 | sayLine(currentCharacter.id, sentence, abort, callback); 176 | }; 177 | 178 | var sayLine = function(itemId, sentence, abort, callback, nextState) 179 | { 180 | var marginTop = 50; 181 | var fontSize = 30; 182 | var maxWidth = 400; 183 | var item = testMapIdItem[itemId]; 184 | var tOutID; 185 | 186 | if(item.type == 'character') 187 | { 188 | 189 | stopRollingFrames(item); 190 | if(!item.path || item.path.length == 0) 191 | item.anim_state = 'talk'; 192 | //drawSprite(item); 193 | } 194 | //abort.push(function() { }); 195 | var posX = null, posY = null; 196 | //var width = (sentence / fontSize) * 100; 197 | 198 | if(sceneSentences[itemId]) 199 | clearInterval(sceneSentences[itemId].tOutID); 200 | 201 | 202 | if(item.position.x != null && item.position.y != null && item.type == 'character') 203 | { 204 | var anim = testMapIdAnim[item.defaultAnims[item.anim_state][item.dir]]; 205 | var frameWidth = 0; 206 | var y = item.position.y; 207 | 208 | if(anim) 209 | { 210 | frameWidth = anim.frames[anim.current_frame].img.width * item.scaleFactor; 211 | y -= anim.frames[anim.current_frame].img.height * item.scaleFactor; 212 | } 213 | 214 | posX = (item.position.x + frameWidth / 2); 215 | posY = y - marginTop; 216 | } 217 | else if(item.hotspot != null) 218 | { 219 | var minX, minY, maxX, maxY; 220 | 221 | minX = maxX = item.hotspot.points[0].x; 222 | minY = maxY = item.hotspot.points[0].y; 223 | 224 | for(var i = 1; i < item.hotspot.points.length; i++) 225 | { 226 | var p = item.hotspot.points[i]; 227 | if(p.x < minX) 228 | minX = p.x; 229 | if(p.x > maxX) 230 | maxX = p.x; 231 | if(p.y < minY) 232 | minY = p.y; 233 | if(p.y > maxY) 234 | maxY = p.y; 235 | } 236 | posX = (minX + (maxX - minX) / 2); 237 | posY = minY - marginTop; 238 | } 239 | posX -= viewport.left; 240 | posY -= viewport.top; 241 | 242 | if(posX < 0) 243 | posX = 0; 244 | if(posY < 0) 245 | posY = 0; 246 | //abort.push(function() { delete sceneSentences[itemId]; }); 247 | sceneSentences[itemId] = { text : sentence, pos : { x : posX, y : posY }, tOutID : -1}; 248 | 249 | (function(callback) 250 | { 251 | var clearSentence = function (callback) { 252 | $(document).off('keydown', skipSentenceBeforeTime); 253 | stopRollingFrames(item); 254 | if (item.type === 'character') { 255 | if (!item.path || item.path.length == 0) 256 | item.anim_state = 'stand'; 257 | } 258 | else item.anim_state = 'default'; 259 | if (nextState) 260 | item.anim_state = nextState; 261 | delete sceneSentences[itemId]; 262 | if (callback && callback.hasOwnProperty('resolve')) 263 | callback.resolve(); 264 | else if (callback) 265 | callback(); 266 | }; 267 | 268 | var skipSentenceBeforeTime = function (e) { 269 | e.stopImmediatePropagation(); 270 | var keycode = 190; 271 | if (e.which === keycode) { 272 | clearTimeout(sceneSentences[itemId].tOutID); 273 | clearSentence(callback); 274 | } 275 | }; 276 | 277 | sceneSentences[itemId].tOutID = setTimeout(function() { clearSentence(callback); }, 2500); 278 | $(document).on('keydown', skipSentenceBeforeTime); 279 | })(callback); 280 | 281 | //})(sentenceDiv); 282 | //abort.push(function() { clearTimeout(sceneSentences[itemId].tOutID);}); 283 | }; 284 | 285 | var fireEvent = function(eventName) 286 | { 287 | $(document).trigger(eventName); 288 | }; 289 | 290 | var varSet = function(varName, varValue) 291 | { 292 | if(window[varName] == null) 293 | throwError('Error: variable ' + varName + ' is not defined.')(); 294 | if(isNaN(varValue)) 295 | { 296 | if(varValue.toLowerCase() == 'true' || varValue.toLowerCase() == 'false') 297 | window[varName] = varValue.toLowerCase() == 'true'; 298 | else 299 | window[varName] = varValue; 300 | } 301 | else 302 | window[varName] = parseInt(varValue); 303 | }; 304 | 305 | var varIncr = function(varName, incrAmount) 306 | { 307 | if(window[varName] == null) 308 | throwError('Error: variable ' + varName + ' is not defined.')(); 309 | incrAmount = parseInt(incrAmount); 310 | if(incrAmount == NaN) 311 | throwError('Error: attempting to increment variable ' + varName + ' by a non-numeric value.')(); 312 | window[varName] += incrAmount; 313 | }; 314 | 315 | var setCurrentRoom = function(roomId) 316 | { 317 | testCurrentRoom = testMapIdRoom[roomId]; 318 | setObjectLocation(currentCharacter.id, roomId); 319 | cameraCenterItem(currentCharacter.id); 320 | var zIndex = getItemZIndex(currentCharacter.id); 321 | currentCharacter.setLayer(zIndex, true); 322 | guiObj.setCursor('default'); 323 | hovering = false; 324 | guiObj.hovering = null; 325 | 326 | if(testCurrentRoom.onEnterScript) 327 | eval(gameScripts['EnterRoom'][roomId]); 328 | }; 329 | 330 | 331 | var setDirection = function(itemId, dir) 332 | { 333 | switch(dir.toLowerCase()) 334 | { 335 | case 'left': dir = 'FL'; 336 | break; 337 | case 'right': dir = 'FR'; 338 | break; 339 | case 'front': dir = 'FF'; 340 | break; 341 | case 'back': dir = 'FB'; 342 | break; 343 | case 'front left': dir = 'FFL'; 344 | break; 345 | case 'front right': dir = 'FFR'; 346 | break; 347 | case 'back left': dir = 'FBL'; 348 | break; 349 | case 'back right': dir = 'FBR'; 350 | break; 351 | } 352 | var item = testMapIdItem[itemId]; 353 | item.dir = dir; 354 | //drawSprite(item); 355 | }; 356 | 357 | var egoSetDirection = function(dir) 358 | { 359 | setDirection(currentCharacter.id, dir); 360 | }; 361 | 362 | var setState = function(itemId, state) 363 | { 364 | var item = testMapIdItem[itemId]; 365 | if(!item) 366 | throwError('Error. No item with ID \"' + itemId + '\".')(); 367 | if(!(state in item.defaultAnims) && !(state in item.customAnims)) 368 | throwError('Error. Item \"' + itemId + '\" does not have such state as ' + '\"' + state + '\".')(); 369 | item.anim_state = state; 370 | //drawSprite(item); 371 | }; 372 | 373 | var egoSetState = function(state) 374 | { 375 | setState(currentCharacter.id, state); 376 | }; 377 | 378 | var delay = function(millisecs, abort, callback) 379 | { 380 | setTimeout(function() { 381 | if(callback && callback.hasOwnProperty('resolve')) 382 | callback.resolve(); 383 | else if(callback) 384 | callback(); 385 | }, parseInt(millisecs)); 386 | }; 387 | 388 | var disableInput = function() 389 | { 390 | guiObj.disableListening(); 391 | }; 392 | 393 | var enableInput = function() 394 | { 395 | guiObj.enableListening(); 396 | }; 397 | 398 | var setDescription = function(id, description) 399 | { 400 | if(id in testMapIdItem) 401 | testMapIdItem[id].description = description; 402 | else if(id in testMapIdInvItem) 403 | testMapIdInvItem[id].description = description; 404 | else 405 | { 406 | alert('Error! No game entity with ID ' + id + '.'); 407 | } 408 | 409 | }; 410 | 411 | var openDialog = function(dialogId) 412 | { 413 | guiObj.disableListening(); 414 | guiObj.dialogOpen = dialogId; 415 | testMapIdDialog[dialogId].hidden = false; 416 | }; 417 | 418 | var closeDialog = function() 419 | { 420 | if(!guiObj.dialogOpen) 421 | return; 422 | testMapIdDialog[guiObj.dialogOpen].currentSubDialog = 'root'; 423 | guiObj.dialogOpen = null; 424 | enableInput(); 425 | return; 426 | }; 427 | 428 | var hideDialog = function() 429 | { 430 | testMapIdDialog[guiObj.dialogOpen].hidden = true; 431 | }; 432 | 433 | var playAudio = function(audioId) 434 | { 435 | var audio = testMapIdAudio[audioId]; 436 | audio.pause(); 437 | audio.currentTime = 0; 438 | audio.play(); 439 | }; 440 | 441 | var cameraCenterItem = function(characterId) 442 | { 443 | var character = testMapIdItem[characterId]; 444 | 445 | viewport.left = character.position.x - resolution.width / 2; 446 | if(viewport.left < 0) 447 | viewport.left = 0; 448 | else if(viewport.left + resolution.width > testCurrentRoom.items[0].img.width) 449 | viewport.left = Math.max(testCurrentRoom.items[0].img.width - resolution.width, 0); 450 | 451 | viewport.top = character.position.y - (2 * resolution.height / 3); 452 | if(viewport.top < 0) 453 | viewport.top = 0; 454 | else if(viewport.top + resolution.height > testCurrentRoom.items[0].img.height) 455 | viewport.top = Math.max(testCurrentRoom.items[0].img.height - resolution.height, 0); 456 | }; 457 | 458 | var enableWalkbox = function(walkboxId) 459 | { 460 | testMapIdWalkbox[walkboxId].visible = true; 461 | }; 462 | 463 | var disableWalkbox = function(walkboxId) 464 | { 465 | testMapIdWalkbox[walkboxId].visible = false; 466 | }; 467 | 468 | /*var playCustomAnimation = function(item, state) 469 | { 470 | var anim = editorMapIdAnim[item.defaultAnims[state]]; 471 | var img = $('#svg' + '-' + item.id + '-sprite image'); 472 | var imgContainer = $('#' + item.id + '-sprite-container'); 473 | if(anim.frames.length < 2) 474 | { 475 | img.attr({'href' : anim.frames[anim.current_frame].img.src, 'x' : 0, 'y' : 0}); 476 | imgContainer.attr({'x' : item.position.x, 'y' : item.position.y }); 477 | return; 478 | } 479 | activeAnims.push(setInterval( 480 | function() 481 | { 482 | anim.incrCurrIdx(); img.attr({'href' : anim.frames[anim.current_frame].img.src, 'x' : 0, 'y' : 0}); 483 | imgContainer.attr({'x' : item.position.x, 'y' : item.position.y }); 484 | }, anim.frame_rate)); 485 | 486 | }; 487 | 488 | var stopRollingFrames = function(item) 489 | { 490 | var anim = item.type == 'character' ? editorMapIdAnim[item.defaultAnims[item.anim_state][item.dir]] : editorMapIdAnim[item.defaultAnims[item.anim_state]]; 491 | if(!anim) 492 | return; 493 | anim.current_frame = anim.start_idx; 494 | }; 495 | */ --------------------------------------------------------------------------------