diff --git a/Source/MenuGraphr.d.ts b/Source/MenuGraphr.d.ts new file mode 100644 index 0000000..f6a446b --- /dev/null +++ b/Source/MenuGraphr.d.ts @@ -0,0 +1,15 @@ +declare module MenuGraphr { + export interface IMenuGraphrSettings { + GameStarter: GameStartr.IGameStartr; + schemas?: any; + aliases?: any; + replacements?: any; + replacerKey?: string; + replaceFromItemsHolder?: any; + replacementStatistics?: any; + } + + export interface IMenuGraphr { + + } +} \ No newline at end of file diff --git a/Source/MenuGraphr.js b/Source/MenuGraphr.js new file mode 100644 index 0000000..9cb4586 --- /dev/null +++ b/Source/MenuGraphr.js @@ -0,0 +1,944 @@ +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @ifdef INCLUDE_DEFINITIONS +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +// @endif +// @include ../Source/MenuGraphr.d.ts +var MenuGraphr; +(function (_MenuGraphr) { + /** + * + */ + var MenuGraphr = (function () { + /** + * + */ + function MenuGraphr(settings) { + /** + * + */ + this.getActiveMenu = function () { + return this.activeMenu; + }; + /** + * + */ + this.getActiveMenuName = function () { + return this.activeMenu.name; + }; + /** + * + */ + this.registerUp = function () { + if (!this.activeMenu) { + return; + } + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, 0, -1); + } + if (this.activeMenu.onUp) { + this.activeMenu.onUp(this.GameStarter); + } + }; + /** + * + */ + this.registerA = function () { + if (!this.activeMenu || this.activeMenu.ignoreA) { + return; + } + if (this.activeMenu.callback) { + this.activeMenu.callback(this.activeMenu.name); + } + }; + /** + * + */ + this.registerB = function () { + if (!this.activeMenu) { + return; + } + if (this.activeMenu.progress && !this.activeMenu.ignoreProgressB) { + return this.registerA(); + } + if (this.activeMenu.ignoreB) { + return; + } + if (this.activeMenu.onBPress) { + this.activeMenu.onBPress(this.activeMenu.name); + return; + } + if (this.activeMenu.keepOnBack) { + this.setActiveMenu(this.activeMenu.backMenu); + } + else { + this.deleteMenu(this.activeMenu.name); + } + }; + /** + * + */ + this.registerStart = function () { + if (!this.activeMenu) { + return; + } + if (this.activeMenu.startMenu) { + this.setActiveMenu(this.activeMenu.startMenu); + } + }; + this.GameStarter = settings.GameStarter; + this.schemas = settings.schemas || {}; + this.aliases = settings.aliases || {}; + this.replacements = settings.replacements || {}; + this.replacerKey = settings.replacerKey || "%%%%%%%"; + this.replaceFromItemsHolder = settings.replaceFromItemsHolder; + this.replacementStatistics = settings.replacementStatistics; + this.menus = {}; + } + /* Simple gets + */ + /** + * + */ + MenuGraphr.prototype.getMenus = function () { + return this.menus; + }; + /** + * + */ + MenuGraphr.prototype.getMenu = function (name) { + return this.menus[name]; + }; + /** + * + */ + MenuGraphr.prototype.getExistingMenu = function (name) { + if (!this.menus[name]) { + throw new Error("'" + name + "' menu does not exist."); + } + return this.menus[name]; + }; + /** + * + */ + MenuGraphr.prototype.getAliases = function () { + return this.aliases; + }; + /** + * + */ + MenuGraphr.prototype.getReplacements = function () { + return this.replacements; + }; + /* Menu positioning + */ + /** + * + */ + MenuGraphr.prototype.createMenu = function (name, attributes) { + var schemaRaw = this.GameStarter.proliferate({}, this.schemas[name]), schema = this.GameStarter.proliferate(schemaRaw, attributes), menu = this.GameStarter.ObjectMaker.make("Menu", schema), container = schema.container ? this.menus[schema.container] : { + "top": 0, + "left": 0, + "right": this.GameStarter.MapScreener.width, + "bottom": this.GameStarter.MapScreener.height, + "width": Math.ceil(this.GameStarter.MapScreener.width / this.GameStarter.unitsize), + "height": Math.ceil(this.GameStarter.MapScreener.height / this.GameStarter.unitsize), + "GameStarter": this.GameStarter + }; + this.deleteMenu(name); + this.menus[name] = menu; + menu.name = name; + this.positionItem(menu, schema.size, schema.position, container); + menu.children = []; + menu.textAreaWidth = (menu.width - menu.textXOffset * 2) * this.GameStarter.unitsize; + if (menu.childrenSchemas) { + menu.childrenSchemas.forEach(this.createChild.bind(undefined, name)); + } + if (container.children) { + container.children.push(menu); + } + this.GameStarter.proliferate(menu, attributes); + }; + /** + * + */ + MenuGraphr.prototype.createChild = function (name, schema, attributes) { + switch (schema.type) { + case "menu": + this.createMenu(schema.name, schema.attributes); + break; + case "text": + this.createMenuWord(name, schema); + break; + case "thing": + this.createMenuThing(name, schema); + break; + } + }; + /** + * + */ + MenuGraphr.prototype.createMenuWord = function (name, schema) { + var menu = this.getExistingMenu(name), container = this.GameStarter.ObjectMaker.make("Menu"); + this.positionItem(container, schema.size, schema.position, menu, true); + menu.textX = container.left; + this.addMenuWord(name, schema.words, 0, container.left, container.top); + }; + /** + * + */ + MenuGraphr.prototype.createMenuThing = function (name, schema) { + var menu = this.getExistingMenu(name), thing = this.GameStarter.ObjectMaker.make(schema.thing, schema.args); + this.positionItem(thing, schema.size, schema.position, menu); + this.GameStarter.GroupHolder.switchObjectGroup(thing, thing.groupType, "Text"); + menu.children.push(thing); + return thing; + }; + /** + * + */ + MenuGraphr.prototype.hideMenu = function (name) { + var menu = this.menus[name]; + if (menu) { + menu.hidden = true; + this.deleteMenuChildren(name); + } + }; + /** + * + */ + MenuGraphr.prototype.deleteMenu = function (name) { + var menu = this.menus[name]; + if (menu) { + this.deleteMenuChild(menu); + } + }; + /** + * + */ + MenuGraphr.prototype.deleteActiveMenu = function () { + if (this.activeMenu) { + this.deleteMenu(this.activeMenu.name); + } + }; + /** + * + */ + MenuGraphr.prototype.deleteMenuChild = function (child) { + if (this.activeMenu === child) { + if (child.backMenu) { + this.setActiveMenu(child.backMenu); + } + else { + this.activeMenu = undefined; + } + } + if (child.killOnB) { + child.killOnB.forEach(this.deleteMenu); + } + if (child.name) { + delete this.menus[child.name]; + } + this.GameStarter.killNormal(child); + this.deleteMenuChildren(name); + if (child.onMenuDelete) { + child.onMenuDelete.call(this.GameStarter); + } + if (child.children) { + child.children.forEach(this.deleteMenuChild); + } + }; + /** + * + */ + MenuGraphr.prototype.deleteMenuChildren = function (name) { + var menu = this.menus[name]; + if (menu && menu.children) { + menu.children.forEach(this.deleteMenuChild); + } + }; + /** + * + */ + MenuGraphr.prototype.positionItem = function (item, size, position, container, skipAdd) { + var offset, i; + if (!position) { + position = {}; + offset = {}; + } + else { + offset = position.offset || {}; + } + if (!size) { + size = {}; + } + if (size.width) { + this.GameStarter.setWidth(item, size.width); + } + else if (position.horizontal === "stretch") { + this.GameStarter.setLeft(item, 0); + this.GameStarter.setWidth(item, container.width - (offset.left || 0) - (offset.right || 0)); + } + if (size.height) { + this.GameStarter.setHeight(item, size.height); + } + else if (position.vertical === "stretch") { + this.GameStarter.setTop(item, 0); + this.GameStarter.setHeight(item, container.height - (offset.top || 0) - (offset.bottom || 0)); + } + switch (position.horizontal) { + case "center": + this.GameStarter.setMidXObj(item, container); + break; + case "right": + this.GameStarter.setRight(item, container.right); + break; + default: + this.GameStarter.setLeft(item, container.left); + break; + } + switch (position.vertical) { + case "center": + this.GameStarter.setMidYObj(item, container); + break; + case "bottom": + this.GameStarter.setBottom(item, container.bottom); + break; + default: + this.GameStarter.setTop(item, container.top); + break; + } + if (offset.top) { + this.GameStarter.shiftVert(item, position.offset.top * this.GameStarter.unitsize); + } + if (offset.left) { + this.GameStarter.shiftHoriz(item, position.offset.left * this.GameStarter.unitsize); + } + if (!skipAdd) { + this.GameStarter.addThing(item, item.left, item.top); + } + }; + /* Menu text + */ + /** + * + */ + MenuGraphr.prototype.addMenuDialog = function (name, dialog, onCompletion) { + if (!dialog) { + dialog = [""]; + } + else if (dialog.constructor === String) { + dialog = [dialog]; + } + else if (!(dialog instanceof Array)) { + dialog = [String(dialog)]; + } + this.addMenuText(name, dialog[0], function () { + if (dialog.length === 1) { + if (this.menus[name].deleteOnFinish) { + this.deleteMenu(name); + } + if (onCompletion) { + return onCompletion(); + } + return true; + } + this.deleteMenuChildren(name); + this.addMenuDialog(name, dialog.slice(1), onCompletion); + return false; + }); + }; + /** + * + */ + MenuGraphr.prototype.addMenuText = function (name, words, onCompletion) { + var menu = this.getExistingMenu(name), x = this.GameStarter.getMidX(menu), y = menu.top + menu.textYOffset * this.GameStarter.unitsize; + switch (menu.textStartingX) { + case "right": + x += menu.textAreaWidth / 2; + break; + case "center": + break; + default: + x -= menu.textAreaWidth / 2; + } + if (words.constructor === String) { + words = words.split(/ /); + } + menu.callback = this.continueMenu; + menu.textX = x; + this.addMenuWord(name, words, 0, x, y, onCompletion); + }; + /** + * + * + * @todo The calculation of whether a word can fit assumes equal width for + * all children, although apostrophes are tiny. + */ + MenuGraphr.prototype.addMenuWord = function (name, words, i, x, y, onCompletion) { + var menu = this.getExistingMenu(name), word = this.filterWord(words[i]), textProperties = this.GameStarter.ObjectMaker.getPropertiesOf("Text"), things = [], textWidth, textHeight, textPaddingX, textPaddingY, textSpeed, textWidthMultiplier, title, character, j; + if (word.constructor === Object && word.command) { + switch (word.command) { + case "attribute": + menu[word.attribute + "Old"] = menu[word.attribute]; + menu[word.attribute] = word.value; + if (word.applyUnitsize) { + menu[word.attribute] *= this.GameStarter.unitsize; + } + break; + case "attributeReset": + menu[word.attribute] = menu[word.attribute + "Old"]; + break; + case "position": + if (word.x) { + x += word.x; + } + if (word.y) { + y += word.y; + } + break; + } + } + textSpeed = menu.textSpeed; + textWidth = (menu.textWidth || textProperties.width) * this.GameStarter.unitsize, textHeight = (menu.textHeight || textProperties.height) * this.GameStarter.unitsize, textPaddingX = (menu.textPaddingX || textProperties.paddingX) * this.GameStarter.unitsize; + textPaddingY = (menu.textPaddingY || textProperties.paddingY) * this.GameStarter.unitsize; + textWidthMultiplier = menu.textWidthMultiplier || 1; + if (word.constructor === Object && word.command) { + title = this.filterWord(this.getCharacterEquivalent(word.word)); + switch (word.command) { + case "padLeft": + if (word.length.constructor === String) { + word = this.GameStarter.stringOf(" ", (this.filterWord(word.length).length - title.length)) + this.filterWord(title); + } + else { + word = this.GameStarter.stringOf(" ", word.length - title.length) + title; + } + break; + } + } + if ((word.constructor === String && word !== "\n") || word.constructor === Array) { + for (j = 0; j < word.length; j += 1) { + if (word[j] !== " ") { + title = "Char" + this.getCharacterEquivalent(word[j]); + character = this.GameStarter.ObjectMaker.make(title); + character.paddingY = textPaddingY; + menu.children.push(character); + things.push(character); + if (textSpeed) { + this.GameStarter.TimeHandler.addEvent(this.GameStarter.addThing.bind(this.GameStarter), j * textSpeed, character, x, y); + } + else { + this.GameStarter.addThing(character, x, y); + } + x += textWidthMultiplier * (character.width * this.GameStarter.unitsize + textPaddingX); + } + else { + x += textWidth * textWidthMultiplier; + } + } + } + if (i === words.length - 1) { + menu.progress = { + "complete": true, + "onCompletion": onCompletion + }; + if (menu.finishAutomatically) { + this.GameStarter.TimeHandler.addEvent(onCompletion, (word.length + (menu.finishAutomaticSpeed || 1)) * textSpeed); + } + return things; + } + if (!word.skipSpacing) { + if (word === "\n" || (x + ((this.filterWord(words[i + 1]).length + .5) * textWidthMultiplier * textWidth + menu.textXOffset * this.GameStarter.unitsize) > this.GameStarter.getMidX(menu) + menu.textAreaWidth / 2)) { + x = menu.textX; + y += textPaddingY; + } + else { + x += textWidth * textWidthMultiplier; + } + } + if (y >= menu.bottom - (menu.textYOffset - 1) * this.GameStarter.unitsize) { + menu.progress = { + "words": words, + "i": i + 1, + "x": x, + "y": y - (textPaddingY), + "onCompletion": onCompletion + }; + return things; + } + if (textSpeed) { + this.GameStarter.TimeHandler.addEvent(this.addMenuWord, (j + 1) * textSpeed, name, words, i + 1, x, y, onCompletion); + } + else { + this.addMenuWord(name, words, i + 1, x, y, onCompletion); + } + return things; + }; + /** + * + */ + MenuGraphr.prototype.continueMenu = function (name) { + var menu = this.getExistingMenu(name), children = menu.children, progress = menu.progress, character, i; + if (!progress || progress.working) { + return; + } + progress.working = true; + if (progress.complete) { + if (!progress.onCompletion || progress.onCompletion(this.GameStarter, menu)) { + this.deleteMenu(name); + } + return; + } + for (i = 0; i < children.length; i += 1) { + character = children[i]; + this.GameStarter.TimeHandler.addEventInterval(this.scrollCharacterUp, 1, character.paddingY / this.GameStarter.unitsize, character, menu, -1); + } + this.GameStarter.TimeHandler.addEvent(this.addMenuWord, character.paddingY / this.GameStarter.unitsize + 1, name, progress.words, progress.i, progress.x, progress.y, progress.onCompletion); + }; + /* Lists + */ + /** + * + */ + MenuGraphr.prototype.addMenuList = function (name, settings) { + var menu = this.getExistingMenu(name), options = settings.options instanceof Function ? settings.options() : settings.options, left = menu.left + menu.textXOffset * this.GameStarter.unitsize, top = menu.top + menu.textYOffset * this.GameStarter.unitsize, textProperties = this.GameStarter.ObjectMaker.getPropertiesOf("Text"), textWidth = (menu.textWidth || textProperties.width) * this.GameStarter.unitsize, textHeight = (menu.textHeight || textProperties.height) * this.GameStarter.unitsize, textPaddingY = (menu.textPaddingY || textProperties.paddingY) * this.GameStarter.unitsize, arrowXOffset = (menu.arrowXOffset || 0) * this.GameStarter.unitsize, arrowYOffset = (menu.arrowYOffset || 0) * this.GameStarter.unitsize, selectedIndex = settings.selectedIndex || [0, 0], optionChildren = [], index = 0, y = top, option, optionChild, schema, title, character, column, x, i, j, k; + menu.options = options; + menu.optionChildren = optionChildren; + menu.callback = this.selectMenuListOption; + menu.onActive = this.activateMenuList; + menu.onInactive = this.deactivateMenuList; + menu.grid = []; + menu.grid[0] = column = []; + menu.gridRows = 0; + if (!options.length) { + return; + } + for (i = 0; i < options.length; i += 1) { + x = left; + option = options[i]; + optionChild = { + "option": option, + "things": [] + }; + optionChildren.push(optionChild); + option.x = x; + option.y = y; + column.push(option); + option.column = column; + option.index = index; + option.columnNumber = menu.grid.length - 1; + option.rowNumber = column.length - 1; + menu.gridRows = Math.max(menu.gridRows, column.length); + index += 1; + if (option.things) { + for (j = 0; j < option.things.length; j += 1) { + schema = option.things[j]; + character = this.createMenuThing(name, schema); + menu.children.push(character); + optionChild.things.push(character); + if (!schema.position || !schema.position.relative) { + this.GameStarter.shiftVert(character, y - menu.top); + } + } + } + if (option.textsFloating) { + for (j = 0; j < option.textsFloating.length; j += 1) { + schema = option.textsFloating[j]; + optionChild.things = optionChild.things.concat(this.addMenuWord(name, [schema.text], 0, x + schema.x * this.GameStarter.unitsize, y + schema.y * this.GameStarter.unitsize)); + } + } + option.schema = schema = this.filterWord(option.text); + if (schema !== "\n") { + for (j = 0; j < schema.length; j += 1) { + if (schema[j].command) { + if (schema[j].x) { + x += schema[j].x * this.GameStarter.unitsize; + } + if (schema[j].y) { + y += schema[j].y * this.GameStarter.unitsize; + } + } + else if (schema[j] !== " ") { + option.title = title = "Char" + this.getCharacterEquivalent(schema[j]); + character = this.GameStarter.ObjectMaker.make(title); + menu.children.push(character); + optionChild.things.push(character); + this.GameStarter.addThing(character, x, y); + x += character.width * this.GameStarter.unitsize; + } + else { + x += textWidth; + } + } + } + y += textPaddingY; + if (y > menu.bottom - textHeight + 1) { + y = top; + left += menu.textColumnWidth * this.GameStarter.unitsize; + column = []; + menu.grid.push(column); + } + } + while (menu.grid[menu.grid.length - 1].length === 0) { + menu.grid.pop(); + } + menu.gridColumns = menu.grid.length; + if (settings.bottom) { + option = settings.bottom; + option.schema = schema = this.filterWord(option.text); + optionChild = { + "option": option, + "things": [] + }; + optionChildren.push(optionChild); + x = menu.left + (menu.textXOffset + option.position.left) * this.GameStarter.unitsize; + y = menu.top + (menu.textYOffset + option.position.top) * this.GameStarter.unitsize; + option.x = x; + option.y = y; + for (j = 0; j < schema.length; j += 1) { + if (schema[j].command) { + if (schema[j].x) { + x += schema[j].x * this.GameStarter.unitsize; + } + if (schema[j].y) { + y += schema[j].y * this.GameStarter.unitsize; + } + } + else if (schema[j] !== " ") { + option.title = title = "Char" + this.getCharacterEquivalent(schema[j]); + character = this.GameStarter.ObjectMaker.make(title); + menu.children.push(character); + optionChild.things.push(character); + this.GameStarter.addThing(character, x, y); + x += character.width * this.GameStarter.unitsize; + } + else { + x += textWidth; + } + } + menu.gridRows += 1; + for (j = 0; j < menu.grid.length; j += 1) { + menu.grid[j].push(option); + } + } + if (menu.scrollingItems) { + menu.scrollingAmount = 0; + menu.scrollingAmountReal = 0; + for (i = menu.scrollingItems; i < menu.gridRows; i += 1) { + optionChild = optionChildren[i]; + for (j = 0; j < optionChild.things.length; j += 1) { + optionChild.things[j].hidden = true; + } + } + } + menu.selectedIndex = selectedIndex; + menu.arrow = character = this.GameStarter.ObjectMaker.make("CharArrowRight"); + menu.children.push(character); + character.hidden = (this.activeMenu !== menu); + option = menu.grid[selectedIndex[0]][selectedIndex[1]]; + this.GameStarter.addThing(character); + this.GameStarter.setRight(character, option.x - menu.arrowXOffset * this.GameStarter.unitsize); + this.GameStarter.setTop(character, option.y + menu.arrowYOffset * this.GameStarter.unitsize); + }; + /** + * + */ + MenuGraphr.prototype.activateMenuList = function (name) { + if (this.menus[name] && this.menus[name].arrow) { + this.menus[name].arrow.hidden = false; + } + }; + /** + * + */ + MenuGraphr.prototype.deactivateMenuList = function (name) { + if (this.menus[name] && this.menus[name].arrow) { + this.menus[name].arrow.hidden = true; + } + }; + /** + * + */ + MenuGraphr.prototype.getMenuSelectedIndex = function (name) { + return this.menus[name].selectedIndex; + }; + /** + * + */ + MenuGraphr.prototype.getMenuSelectedOption = function (name) { + var menu = this.menus[name]; + return menu.grid[menu.selectedIndex[0]][menu.selectedIndex[1]]; + }; + /** + * + */ + MenuGraphr.prototype.shiftSelectedIndex = function (name, dx, dy) { + var menu = this.getExistingMenu(name), textProperties = this.GameStarter.ObjectMaker.getPropertiesOf("Text"), textWidth = textProperties.width * this.GameStarter.unitsize, textHeight = textProperties.height * this.GameStarter.unitsize, textPaddingY = (menu.textPaddingY || textProperties.paddingY) * this.GameStarter.unitsize, x, y, option; + if (menu.scrollingItems) { + x = menu.selectedIndex[0] + dx; + y = menu.selectedIndex[1] + dy; + x = Math.max(Math.min(menu.gridColumns - 1, x), 0); + y = Math.max(Math.min(menu.gridRows - 1, y), 0); + } + else { + x = (menu.selectedIndex[0] + dx) % menu.gridColumns; + y = (menu.selectedIndex[1] + dy) % menu.gridRows; + while (x < 0) { + x += menu.gridColumns; + } + while (y < 0) { + y += menu.gridRows; + } + } + if (x === menu.selectedIndex[0] && y === menu.selectedIndex[1]) { + return; + } + //y = Math.min(menu.grid[x].length - 1, y); + menu.selectedIndex[0] = x; + menu.selectedIndex[1] = y; + option = this.getMenuSelectedOption(name); + if (menu.scrollingItems) { + this.adjustVerticalScrollingListThings(name, dy, textPaddingY); + } + this.GameStarter.setRight(menu.arrow, option.x - menu.arrowXOffset * this.GameStarter.unitsize); + this.GameStarter.setTop(menu.arrow, option.y + menu.arrowYOffset * this.GameStarter.unitsize); + }; + /** + * + */ + MenuGraphr.prototype.setSelectedIndex = function (name, x, y) { + var menu = this.getExistingMenu(name), selectedIndex = menu.selectedIndex; + this.shiftSelectedIndex(name, x - selectedIndex[0], y - selectedIndex[1]); + }; + /** + * + */ + MenuGraphr.prototype.adjustVerticalScrollingListThings = function (name, dy, textPaddingY) { + var menu = this.getExistingMenu(name), scrollingItems = menu.scrollingItems, scrollingOld = menu.scrollingAmount, offset = -dy * textPaddingY, scrollingNew, indexNew, option, optionChild, i, j; + menu.scrollingAmount += dy; + if (dy > 0) { + if (scrollingOld < menu.scrollingItems - 2) { + return; + } + } + else if (menu.scrollingAmount < menu.scrollingItems - 2) { + return; + } + menu.scrollingAmountReal += dy; + for (i = 0; i < menu.optionChildren.length; i += 1) { + option = menu.options[i]; + optionChild = menu.optionChildren[i]; + option.y += offset; + for (j = 0; j < optionChild.things.length; j += 1) { + this.GameStarter.shiftVert(optionChild.things[j], offset); + if (i < menu.scrollingAmountReal || i >= menu.scrollingItems + menu.scrollingAmountReal) { + optionChild.things[j].hidden = true; + } + else { + optionChild.things[j].hidden = false; + } + } + } + }; + /** + * + */ + MenuGraphr.prototype.selectMenuListOption = function (name, index) { + var menu = this.getExistingMenu(name), selected = this.getMenuSelectedOption(name); + if (selected.callback) { + selected.callback(name); + } + }; + /* Interactivity + */ + /** + * + */ + MenuGraphr.prototype.setActiveMenu = function (name) { + if (this.activeMenu && this.activeMenu.onInactive) { + this.activeMenu.onInactive(this.activeMenu.name); + } + this.activeMenu = this.menus[name]; + if (this.activeMenu && this.activeMenu.onActive) { + this.activeMenu.onActive(name); + } + }; + /** + * + */ + MenuGraphr.prototype.registerDirection = function (direction) { + switch (direction) { + case 0: + return this.registerUp(); + case 1: + return this.registerRight(); + case 2: + return this.registerDown(); + case 3: + return this.registerLeft(); + } + }; + /** + * + */ + MenuGraphr.prototype.registerLeft = function () { + if (!this.activeMenu) { + return; + } + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, -1, 0); + } + if (this.activeMenu.onLeft) { + this.activeMenu.onLeft(this.GameStarter); + } + }; + /** + * + */ + MenuGraphr.prototype.registerRight = function () { + if (!this.activeMenu) { + return; + } + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, 1, 0); + } + if (this.activeMenu.onRight) { + this.activeMenu.onRight(this.GameStarter); + } + }; + /** + * + */ + MenuGraphr.prototype.registerDown = function () { + if (!this.activeMenu) { + return; + } + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, 0, 1); + } + if (this.activeMenu.onDown) { + this.activeMenu.onDown(this.GameStarter); + } + }; + /* Utilities + */ + /** + * + */ + MenuGraphr.prototype.scrollCharacterUp = function (character, menu) { + this.GameStarter.shiftVert(character, -this.GameStarter.unitsize); + if (character.top < menu.top + (menu.textYOffset - 1) * this.GameStarter.unitsize) { + this.GameStarter.killNormal(character); + return true; + } + }; + /** + * + */ + MenuGraphr.prototype.getCharacterEquivalent = function (character) { + if (this.aliases.hasOwnProperty(character)) { + return this.aliases[character]; + } + return character; + }; + /** + * + */ + MenuGraphr.prototype.filterWord = function (word) { + var start = 0, end, inside; + if (word.constructor !== String) { + return word; + } + while (true) { + start = word.indexOf("%%%%%%%", start); + end = word.indexOf("%%%%%%%", start + 1); + if (start === -1 || end === -1) { + return word; + } + inside = word.substring(start + "%%%%%%%".length, end); + word = word.substring(0, start) + this.getReplacement(inside) + word.substring(end + "%%%%%%%".length); + start = end; + } + return word; + }; + /** + * + */ + MenuGraphr.prototype.getReplacement = function (key) { + var value = this.replacements[key]; + if (typeof value === "undefined") { + return value; + } + if (this.replacementStatistics && this.replacementStatistics[value]) { + return this.replacements[value](this.GameStarter); + } + if (this.replaceFromItemsHolder) { + if (this.GameStarter.ItemsHolder.hasKey(value)) { + return this.GameStarter.ItemsHolder.getItem(value); + } + } + return value; + }; + /** + * + */ + MenuGraphr.prototype.getAliasOf = function (key, forced) { + if (forced) { + return this.aliases[key]; + } + else { + return typeof this.aliases[key] === "undefined" ? key : this.aliases[key]; + } + }; + return MenuGraphr; + })(); + _MenuGraphr.MenuGraphr = MenuGraphr; +})(MenuGraphr || (MenuGraphr = {})); diff --git a/Source/MenuGraphr.ts b/Source/MenuGraphr.ts new file mode 100644 index 0000000..c161f5e --- /dev/null +++ b/Source/MenuGraphr.ts @@ -0,0 +1,1259 @@ +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' +// @echo '/// ' + +// @ifdef INCLUDE_DEFINITIONS +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +// @endif + +// @include ../Source/MenuGraphr.d.ts + +module MenuGraphr { + /** + * + */ + export class MenuGraphr { + private GameStarter: GameStartr.IGameStartr; + + private menus; + + private activeMenu; + + private schemas; + + private aliases; + + private replacements; + + private replacerKey; + + private replaceFromItemsHolder; + + private replacementStatistics; + + /** + * + */ + constructor(settings: IMenuGraphrSettings) { + this.GameStarter = settings.GameStarter; + + this.schemas = settings.schemas || {}; + this.aliases = settings.aliases || {}; + this.replacements = settings.replacements || {}; + this.replacerKey = settings.replacerKey || "%%%%%%%"; + this.replaceFromItemsHolder = settings.replaceFromItemsHolder; + this.replacementStatistics = settings.replacementStatistics; + + this.menus = {}; + } + + + /* Simple gets + */ + + /** + * + */ + getMenus() { + return this.menus; + } + + /** + * + */ + getMenu(name) { + return this.menus[name]; + } + + /** + * + */ + getExistingMenu(name) { + if (!this.menus[name]) { + throw new Error("'" + name + "' menu does not exist."); + } + return this.menus[name]; + } + + /** + * + */ + getAliases() { + return this.aliases; + } + + /** + * + */ + getReplacements() { + return this.replacements; + } + + + /* Menu positioning + */ + + /** + * + */ + createMenu(name, attributes) { + var schemaRaw = this.GameStarter.proliferate({}, this.schemas[name]), + schema = this.GameStarter.proliferate(schemaRaw, attributes), + menu = this.GameStarter.ObjectMaker.make("Menu", schema), + container = schema.container + ? this.menus[schema.container] + : { + "top": 0, + "left": 0, + "right": this.GameStarter.MapScreener.width, + "bottom": this.GameStarter.MapScreener.height, + "width": Math.ceil(this.GameStarter.MapScreener.width / this.GameStarter.unitsize), + "height": Math.ceil(this.GameStarter.MapScreener.height / this.GameStarter.unitsize), + "GameStarter": this.GameStarter + }; + + this.deleteMenu(name); + + this.menus[name] = menu; + menu.name = name; + this.positionItem(menu, schema.size, schema.position, container); + + menu.children = []; + menu.textAreaWidth = (menu.width - menu.textXOffset * 2) * this.GameStarter.unitsize; + + if (menu.childrenSchemas) { + menu.childrenSchemas.forEach(this.createChild.bind(undefined, name)); + } + + if (container.children) { + container.children.push(menu); + } + + this.GameStarter.proliferate(menu, attributes); + } + + /** + * + */ + createChild(name, schema, attributes) { + switch (schema.type) { + case "menu": + this.createMenu(schema.name, schema.attributes); + break; + case "text": + this.createMenuWord(name, schema); + break; + case "thing": + this.createMenuThing(name, schema); + break; + } + } + + /** + * + */ + createMenuWord(name, schema) { + var menu = this.getExistingMenu(name), + container = this.GameStarter.ObjectMaker.make("Menu"); + + this.positionItem(container, schema.size, schema.position, menu, true); + + menu.textX = container.left; + this.addMenuWord(name, schema.words, 0, container.left, container.top) + } + + /** + * + */ + createMenuThing(name, schema) { + var menu = this.getExistingMenu(name), + thing = this.GameStarter.ObjectMaker.make(schema.thing, schema.args); + + this.positionItem(thing, schema.size, schema.position, menu); + + this.GameStarter.GroupHolder.switchObjectGroup( + thing, + thing.groupType, + "Text"); + + menu.children.push(thing); + + return thing; + } + + /** + * + */ + hideMenu(name) { + var menu = this.menus[name]; + + if (menu) { + menu.hidden = true; + this.deleteMenuChildren(name); + } + } + + /** + * + */ + deleteMenu(name) { + var menu = this.menus[name]; + + if (menu) { + this.deleteMenuChild(menu); + } + } + + /** + * + */ + deleteActiveMenu() { + if (this.activeMenu) { + this.deleteMenu(this.activeMenu.name); + } + } + + /** + * + */ + deleteMenuChild(child) { + if (this.activeMenu === child) { + if (child.backMenu) { + this.setActiveMenu(child.backMenu); + } else { + this.activeMenu = undefined; + } + } + + if (child.killOnB) { + child.killOnB.forEach(this.deleteMenu); + } + + if (child.name) { + delete this.menus[child.name]; + } + + this.GameStarter.killNormal(child); + this.deleteMenuChildren(name); + + if (child.onMenuDelete) { + child.onMenuDelete.call(this.GameStarter); + } + + if (child.children) { + child.children.forEach(this.deleteMenuChild) + } + } + + /** + * + */ + deleteMenuChildren(name) { + var menu = this.menus[name]; + if (menu && menu.children) { + menu.children.forEach(this.deleteMenuChild); + } + } + + /** + * + */ + positionItem(item, size, position, container, skipAdd?) { + var offset, i; + + if (!position) { + position = {}; + offset = {}; + } else { + offset = position.offset || {}; + } + + if (!size) { + size = {}; + } + + if (size.width) { + this.GameStarter.setWidth(item, size.width); + } else if (position.horizontal === "stretch") { + this.GameStarter.setLeft(item, 0); + this.GameStarter.setWidth( + item, + container.width - (offset.left || 0) - (offset.right || 0)); + } + + if (size.height) { + this.GameStarter.setHeight(item, size.height); + } else if (position.vertical === "stretch") { + this.GameStarter.setTop(item, 0); + this.GameStarter.setHeight( + item, + container.height - (offset.top || 0) - (offset.bottom || 0)); + } + + switch (position.horizontal) { + case "center": + this.GameStarter.setMidXObj(item, container); + break; + case "right": + this.GameStarter.setRight(item, container.right); + break; + default: + this.GameStarter.setLeft(item, container.left); + break; + } + + switch (position.vertical) { + case "center": + this.GameStarter.setMidYObj(item, container); + break; + case "bottom": + this.GameStarter.setBottom(item, container.bottom); + break; + default: + this.GameStarter.setTop(item, container.top); + break; + } + + if (offset.top) { + this.GameStarter.shiftVert( + item, position.offset.top * this.GameStarter.unitsize); + } + + if (offset.left) { + this.GameStarter.shiftHoriz( + item, position.offset.left * this.GameStarter.unitsize); + } + + if (!skipAdd) { + this.GameStarter.addThing(item, item.left, item.top); + } + } + + + /* Menu text + */ + + /** + * + */ + addMenuDialog(name, dialog, onCompletion) { + if (!dialog) { + dialog = [""]; + } else if (dialog.constructor === String) { + dialog = [dialog]; + } else if (!(dialog instanceof Array)) { + dialog = [String(dialog)]; + } + + this.addMenuText(name, dialog[0], function () { + if (dialog.length === 1) { + if (this.menus[name].deleteOnFinish) { + this.deleteMenu(name); + } + if (onCompletion) { + return onCompletion(); + } + return true; + } + + this.deleteMenuChildren(name); + this.addMenuDialog(name, dialog.slice(1), onCompletion); + + return false; + }); + } + + /** + * + */ + addMenuText(name, words, onCompletion) { + var menu = this.getExistingMenu(name), + x = this.GameStarter.getMidX(menu), // - menu.textAreaWidth / 2, + y = menu.top + menu.textYOffset * this.GameStarter.unitsize; + + switch (menu.textStartingX) { + case "right": + x += menu.textAreaWidth / 2; + break; + + case "center": + break; + + default: + x -= menu.textAreaWidth / 2; + } + + if (words.constructor === String) { + words = words.split(/ /); + } + + menu.callback = this.continueMenu; + menu.textX = x; + + this.addMenuWord(name, words, 0, x, y, onCompletion); + } + + /** + * + * + * @todo The calculation of whether a word can fit assumes equal width for + * all children, although apostrophes are tiny. + */ + addMenuWord(name, words, i, x, y, onCompletion?) { + var menu = this.getExistingMenu(name), + word = this.filterWord(words[i]), + textProperties = this.GameStarter.ObjectMaker.getPropertiesOf("Text"), + things = [], + textWidth, textHeight, textPaddingX, textPaddingY, textSpeed, + textWidthMultiplier, + title, character, j; + + if (word.constructor === Object && word.command) { + switch (word.command) { + case "attribute": + menu[word.attribute + "Old"] = menu[word.attribute]; + menu[word.attribute] = word.value; + if (word.applyUnitsize) { + menu[word.attribute] *= this.GameStarter.unitsize; + } + break; + + case "attributeReset": + menu[word.attribute] = menu[word.attribute + "Old"]; + break; + + case "position": + if (word.x) { + x += word.x; + } + if (word.y) { + y += word.y; + } + break; + } + } + + textSpeed = menu.textSpeed; + textWidth = (menu.textWidth || textProperties.width) * this.GameStarter.unitsize, + textHeight = (menu.textHeight || textProperties.height) * this.GameStarter.unitsize, + textPaddingX = (menu.textPaddingX || textProperties.paddingX) * this.GameStarter.unitsize; + textPaddingY = (menu.textPaddingY || textProperties.paddingY) * this.GameStarter.unitsize; + textWidthMultiplier = menu.textWidthMultiplier || 1; + + if (word.constructor === Object && word.command) { + title = this.filterWord(this.getCharacterEquivalent(word.word)); + + switch (word.command) { + case "padLeft": + if (word.length.constructor === String) { + word = this.GameStarter.stringOf( + " ", + ( + this.filterWord(word.length).length + - title.length + ) + ) + this.filterWord(title); + } else { + word = this.GameStarter.stringOf( + " ", word.length - title.length + ) + title; + } + break; + } + } + + if ( + (word.constructor === String && word !== "\n") + || word.constructor === Array + ) { + for (j = 0; j < word.length; j += 1) { + if (word[j] !== " ") { + title = "Char" + this.getCharacterEquivalent(word[j]); + character = this.GameStarter.ObjectMaker.make(title); + character.paddingY = textPaddingY; + menu.children.push(character); + things.push(character); + + if (textSpeed) { + this.GameStarter.TimeHandler.addEvent( + this.GameStarter.addThing.bind(this.GameStarter), + j * textSpeed, + character, + x, + y); + } else { + this.GameStarter.addThing(character, x, y); + } + + x += textWidthMultiplier * ( + character.width * this.GameStarter.unitsize + textPaddingX); + } else { + x += textWidth * textWidthMultiplier; + } + } + } + + if (i === words.length - 1) { + menu.progress = { + "complete": true, + "onCompletion": onCompletion + }; + if (menu.finishAutomatically) { + this.GameStarter.TimeHandler.addEvent( + onCompletion, + (word.length + (menu.finishAutomaticSpeed || 1)) * textSpeed); + } + return things; + } + + if (!word.skipSpacing) { + if ( + word === "\n" + || ( + x + ( + (this.filterWord(words[i + 1]).length + .5) + * textWidthMultiplier * textWidth + + menu.textXOffset * this.GameStarter.unitsize + ) + > this.GameStarter.getMidX(menu) + menu.textAreaWidth / 2) + ) { + x = menu.textX; + y += textPaddingY; + } else { + x += textWidth * textWidthMultiplier; + } + } + + if (y >= menu.bottom - (menu.textYOffset - 1) * this.GameStarter.unitsize) { + menu.progress = { + "words": words, + "i": i + 1, + "x": x, + "y": y - (textPaddingY), + "onCompletion": onCompletion + }; + return things; + } + + if (textSpeed) { + this.GameStarter.TimeHandler.addEvent( + this.addMenuWord, + (j + 1) * textSpeed, + name, + words, + i + 1, + x, + y, + onCompletion); + } else { + this.addMenuWord(name, words, i + 1, x, y, onCompletion); + } + + return things; + } + + /** + * + */ + continueMenu(name) { + var menu = this.getExistingMenu(name), + children = menu.children, + progress = menu.progress, + character, i; + + if (!progress || progress.working) { + return; + } + + progress.working = true; + + if (progress.complete) { + if (!progress.onCompletion || progress.onCompletion(this.GameStarter, menu)) { + this.deleteMenu(name); + } + return; + } + + for (i = 0; i < children.length; i += 1) { + character = children[i]; + + this.GameStarter.TimeHandler.addEventInterval( + this.scrollCharacterUp, + 1, + character.paddingY / this.GameStarter.unitsize, + character, + menu, + -1); + } + + this.GameStarter.TimeHandler.addEvent( + this.addMenuWord, + character.paddingY / this.GameStarter.unitsize + 1, + name, + progress.words, + progress.i, + progress.x, + progress.y, + progress.onCompletion); + } + + + /* Lists + */ + + /** + * + */ + addMenuList(name, settings) { + var menu = this.getExistingMenu(name), + options = settings.options instanceof Function + ? settings.options() + : settings.options, + left = menu.left + menu.textXOffset * this.GameStarter.unitsize, + top = menu.top + menu.textYOffset * this.GameStarter.unitsize, + textProperties = this.GameStarter.ObjectMaker.getPropertiesOf("Text"), + textWidth = (menu.textWidth || textProperties.width) * this.GameStarter.unitsize, + textHeight = (menu.textHeight || textProperties.height) * this.GameStarter.unitsize, + textPaddingY = (menu.textPaddingY || textProperties.paddingY) * this.GameStarter.unitsize, + arrowXOffset = (menu.arrowXOffset || 0) * this.GameStarter.unitsize, + arrowYOffset = (menu.arrowYOffset || 0) * this.GameStarter.unitsize, + selectedIndex = settings.selectedIndex || [0, 0], + optionChildren = [], + index = 0, + y = top, + option, optionChild, schema, title, character, column, + x, i, j, k; + + menu.options = options; + menu.optionChildren = optionChildren; + + menu.callback = this.selectMenuListOption; + menu.onActive = this.activateMenuList; + menu.onInactive = this.deactivateMenuList; + + menu.grid = []; + menu.grid[0] = column = []; + menu.gridRows = 0; + + if (!options.length) { + return; + } + + for (i = 0; i < options.length; i += 1) { + x = left; + option = options[i]; + optionChild = { + "option": option, + "things": [] + }; + + optionChildren.push(optionChild); + + option.x = x; + option.y = y; + + column.push(option); + option.column = column; + option.index = index; + option.columnNumber = menu.grid.length - 1; + option.rowNumber = column.length - 1; + menu.gridRows = Math.max(menu.gridRows, column.length); + index += 1; + + if (option.things) { + for (j = 0; j < option.things.length; j += 1) { + schema = option.things[j]; + character = this.createMenuThing(name, schema); + menu.children.push(character); + optionChild.things.push(character); + + if (!schema.position || !schema.position.relative) { + this.GameStarter.shiftVert(character, y - menu.top); + } + } + } + + if (option.textsFloating) { + for (j = 0; j < option.textsFloating.length; j += 1) { + schema = option.textsFloating[j]; + + optionChild.things = optionChild.things.concat( + this.addMenuWord( + name, + [schema.text], + 0, + x + schema.x * this.GameStarter.unitsize, + y + schema.y * this.GameStarter.unitsize) + ); + } + } + + option.schema = schema = this.filterWord(option.text); + + if (schema !== "\n") { + for (j = 0; j < schema.length; j += 1) { + if (schema[j].command) { + if (schema[j].x) { + x += schema[j].x * this.GameStarter.unitsize; + } + if (schema[j].y) { + y += schema[j].y * this.GameStarter.unitsize; + } + } else if (schema[j] !== " ") { + option.title = title = "Char" + this.getCharacterEquivalent(schema[j]); + character = this.GameStarter.ObjectMaker.make(title); + menu.children.push(character); + optionChild.things.push(character); + + this.GameStarter.addThing(character, x, y); + + x += character.width * this.GameStarter.unitsize; + } else { + x += textWidth; + } + } + } + + y += textPaddingY; + + if (y > menu.bottom - textHeight + 1) { + y = top; + left += menu.textColumnWidth * this.GameStarter.unitsize; + column = []; + menu.grid.push(column); + } + } + + while (menu.grid[menu.grid.length - 1].length === 0) { + menu.grid.pop(); + } + menu.gridColumns = menu.grid.length; + + if (settings.bottom) { + option = settings.bottom; + option.schema = schema = this.filterWord(option.text); + + optionChild = { + "option": option, + "things": [] + } + optionChildren.push(optionChild); + + x = menu.left + (menu.textXOffset + option.position.left) * this.GameStarter.unitsize; + y = menu.top + (menu.textYOffset + option.position.top) * this.GameStarter.unitsize; + + option.x = x; + option.y = y; + + // Copy & pasted from the above options loop + // To do: make this into its own helper function? + for (j = 0; j < schema.length; j += 1) { + if (schema[j].command) { + if (schema[j].x) { + x += schema[j].x * this.GameStarter.unitsize; + } + if (schema[j].y) { + y += schema[j].y * this.GameStarter.unitsize; + } + } else if (schema[j] !== " ") { + option.title = title = "Char" + this.getCharacterEquivalent(schema[j]); + character = this.GameStarter.ObjectMaker.make(title); + menu.children.push(character); + optionChild.things.push(character); + + this.GameStarter.addThing(character, x, y); + + x += character.width * this.GameStarter.unitsize; + } else { + x += textWidth; + } + } + + menu.gridRows += 1; + for (j = 0; j < menu.grid.length; j += 1) { + menu.grid[j].push(option); + } + } + + if (menu.scrollingItems) { + menu.scrollingAmount = 0; + menu.scrollingAmountReal = 0; + + for (i = menu.scrollingItems; i < menu.gridRows; i += 1) { + optionChild = optionChildren[i]; + for (j = 0; j < optionChild.things.length; j += 1) { + optionChild.things[j].hidden = true; + } + } + } + + menu.selectedIndex = selectedIndex; + menu.arrow = character = this.GameStarter.ObjectMaker.make("CharArrowRight"); + menu.children.push(character); + character.hidden = (this.activeMenu !== menu); + + option = menu.grid[selectedIndex[0]][selectedIndex[1]]; + + this.GameStarter.addThing(character); + this.GameStarter.setRight(character, option.x - menu.arrowXOffset * this.GameStarter.unitsize); + this.GameStarter.setTop(character, option.y + menu.arrowYOffset * this.GameStarter.unitsize); + } + + /** + * + */ + activateMenuList(name) { + if (this.menus[name] && this.menus[name].arrow) { + this.menus[name].arrow.hidden = false; + } + } + + /** + * + */ + deactivateMenuList(name) { + if (this.menus[name] && this.menus[name].arrow) { + this.menus[name].arrow.hidden = true; + } + } + + /** + * + */ + getMenuSelectedIndex(name) { + return this.menus[name].selectedIndex; + } + + /** + * + */ + getMenuSelectedOption(name) { + var menu = this.menus[name]; + + return menu.grid[menu.selectedIndex[0]][menu.selectedIndex[1]]; + } + + /** + * + */ + shiftSelectedIndex(name, dx, dy) { + var menu = this.getExistingMenu(name), + textProperties = this.GameStarter.ObjectMaker.getPropertiesOf("Text"), + textWidth = textProperties.width * this.GameStarter.unitsize, + textHeight = textProperties.height * this.GameStarter.unitsize, + textPaddingY = (menu.textPaddingY || textProperties.paddingY) * this.GameStarter.unitsize, + x, y, option; + + if (menu.scrollingItems) { + x = menu.selectedIndex[0] + dx; + y = menu.selectedIndex[1] + dy; + + x = Math.max(Math.min(menu.gridColumns - 1, x), 0); + y = Math.max(Math.min(menu.gridRows - 1, y), 0); + } else { + x = (menu.selectedIndex[0] + dx) % menu.gridColumns; + y = (menu.selectedIndex[1] + dy) % menu.gridRows; + + while (x < 0) { + x += menu.gridColumns; + } + + while (y < 0) { + y += menu.gridRows; + } + } + + if (x === menu.selectedIndex[0] && y === menu.selectedIndex[1]) { + return; + } + + //y = Math.min(menu.grid[x].length - 1, y); + + menu.selectedIndex[0] = x; + menu.selectedIndex[1] = y; + option = this.getMenuSelectedOption(name); + + if (menu.scrollingItems) { + this.adjustVerticalScrollingListThings(name, dy, textPaddingY); + } + + this.GameStarter.setRight( + menu.arrow, option.x - menu.arrowXOffset * this.GameStarter.unitsize); + this.GameStarter.setTop( + menu.arrow, option.y + menu.arrowYOffset * this.GameStarter.unitsize); + } + + /** + * + */ + setSelectedIndex(name, x, y) { + var menu = this.getExistingMenu(name), + selectedIndex = menu.selectedIndex; + + this.shiftSelectedIndex(name, x - selectedIndex[0], y - selectedIndex[1]); + } + + /** + * + */ + adjustVerticalScrollingListThings(name, dy, textPaddingY) { + var menu = this.getExistingMenu(name), + scrollingItems = menu.scrollingItems, + scrollingOld = menu.scrollingAmount, + offset = -dy * textPaddingY, + scrollingNew, indexNew, option, optionChild, i, j; + + menu.scrollingAmount += dy; + + if (dy > 0) { + if (scrollingOld < menu.scrollingItems - 2) { + return; + } + } else if (menu.scrollingAmount < menu.scrollingItems - 2) { + return; + } + + menu.scrollingAmountReal += dy; + + for (i = 0; i < menu.optionChildren.length; i += 1) { + option = menu.options[i]; + optionChild = menu.optionChildren[i]; + + option.y += offset; + + for (j = 0; j < optionChild.things.length; j += 1) { + this.GameStarter.shiftVert(optionChild.things[j], offset); + if ( + i < menu.scrollingAmountReal + || i >= menu.scrollingItems + menu.scrollingAmountReal + ) { + optionChild.things[j].hidden = true; + } else { + optionChild.things[j].hidden = false; + } + } + } + } + + /** + * + */ + selectMenuListOption(name, index) { + var menu = this.getExistingMenu(name), + selected = this.getMenuSelectedOption(name); + + if (selected.callback) { + selected.callback(name); + } + } + + + /* Interactivity + */ + + /** + * + */ + setActiveMenu(name) { + if (this.activeMenu && this.activeMenu.onInactive) { + this.activeMenu.onInactive(this.activeMenu.name); + } + + this.activeMenu = this.menus[name]; + + if (this.activeMenu && this.activeMenu.onActive) { + this.activeMenu.onActive(name); + } + } + + /** + * + */ + getActiveMenu = function () { + return this.activeMenu; + } + + /** + * + */ + getActiveMenuName = function () { + return this.activeMenu.name; + } + + /** + * + */ + registerDirection(direction) { + switch (direction) { + case 0: + return this.registerUp(); + case 1: + return this.registerRight(); + case 2: + return this.registerDown(); + case 3: + return this.registerLeft(); + } + } + + /** + * + */ + registerLeft() { + if (!this.activeMenu) { + return; + } + + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, -1, 0); + } + + if (this.activeMenu.onLeft) { + this.activeMenu.onLeft(this.GameStarter); + } + } + + /** + * + */ + registerRight() { + if (!this.activeMenu) { + return; + } + + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, 1, 0); + } + + if (this.activeMenu.onRight) { + this.activeMenu.onRight(this.GameStarter); + } + } + + /** + * + */ + registerUp = function () { + if (!this.activeMenu) { + return; + } + + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, 0, -1); + } + + if (this.activeMenu.onUp) { + this.activeMenu.onUp(this.GameStarter); + } + }; + + /** + * + */ + registerDown() { + if (!this.activeMenu) { + return; + } + + if (this.activeMenu.selectedIndex) { + this.shiftSelectedIndex(this.activeMenu.name, 0, 1); + } + + if (this.activeMenu.onDown) { + this.activeMenu.onDown(this.GameStarter); + } + } + + /** + * + */ + registerA = function () { + if (!this.activeMenu || this.activeMenu.ignoreA) { + return; + } + + if (this.activeMenu.callback) { + this.activeMenu.callback(this.activeMenu.name); + } + } + + /** + * + */ + registerB = function () { + if (!this.activeMenu) { + return; + } + + if (this.activeMenu.progress && !this.activeMenu.ignoreProgressB) { + return this.registerA(); + } + + if (this.activeMenu.ignoreB) { + return; + } + + if (this.activeMenu.onBPress) { + this.activeMenu.onBPress(this.activeMenu.name); + return; + } + + if (this.activeMenu.keepOnBack) { + this.setActiveMenu(this.activeMenu.backMenu); + } else { + this.deleteMenu(this.activeMenu.name); + } + } + + /** + * + */ + registerStart = function () { + if (!this.activeMenu) { + return; + } + + if (this.activeMenu.startMenu) { + this.setActiveMenu(this.activeMenu.startMenu); + // } else if (activeMenu.callback) { + // activeMenu.callback(activeMenu.name); + } + } + + + /* Utilities + */ + + /** + * + */ + private scrollCharacterUp(character, menu) { + this.GameStarter.shiftVert(character, -this.GameStarter.unitsize); + if (character.top < menu.top + (menu.textYOffset - 1) * this.GameStarter.unitsize) { + this.GameStarter.killNormal(character); + return true; + } + } + + /** + * + */ + private getCharacterEquivalent(character) { + if (this.aliases.hasOwnProperty(character)) { + return this.aliases[character]; + } + return character; + } + + /** + * + */ + private filterWord(word) { + var start = 0, + end, inside; + + if (word.constructor !== String) { + return word; + } + + while (true) { + start = word.indexOf("%%%%%%%", start); + end = word.indexOf("%%%%%%%", start + 1); + if (start === -1 || end === -1) { + return word; + } + + inside = word.substring(start + "%%%%%%%".length, end); + word = + word.substring(0, start) + + this.getReplacement(inside) + + word.substring(end + "%%%%%%%".length); + + start = end; + } + + return word; + } + + /** + * + */ + private getReplacement(key) { + var value = this.replacements[key]; + + if (typeof value === "undefined") { + return value; + } + + if (this.replacementStatistics && this.replacementStatistics[value]) { + return this.replacements[value](this.GameStarter); + } + + if (this.replaceFromItemsHolder) { + if (this.GameStarter.ItemsHolder.hasKey(value)) { + return this.GameStarter.ItemsHolder.getItem(value); + } + } + + return value; + } + + /** + * + */ + private getAliasOf(key, forced) { + if (forced) { + return this.aliases[key]; + } else { + return typeof this.aliases[key] === "undefined" ? key : this.aliases[key]; + } + } + } +} diff --git a/Source/References/AudioPlayr-0.2.1.ts b/Source/References/AudioPlayr-0.2.1.ts new file mode 100644 index 0000000..d78ed70 --- /dev/null +++ b/Source/References/AudioPlayr-0.2.1.ts @@ -0,0 +1,788 @@ +/// + +declare module AudioPlayr { + export interface IAudioPlayrSettings { + /** + * The names of the audio files to be preloaded for on-demand playback. + */ + library: { + [i: string]: { + [i: string]: string; + } + }; + + /** + * The directory in which all sub-directories of audio files are stored. + */ + directory: string; + + /** + * The allowed filetypes for each audio file. Each of these should have a + * directory of their name under the main directory, which should contain + * each file of the filetype. + */ + fileTypes: string[]; + + /** + * A storage container to store mute/volume status locally. This can be + * either a ItemsHoldr or localStorage equivalent. + */ + ItemsHolder: ItemsHoldr.IItemsHoldr | Storage; + + /** + * A String or Function to get the default theme for playTheme calls. + * Functions are called for a return value, and Strings are constant + * (defaults to "Theme"). + * + */ + getThemeDefault?: string | { (...args: any[]): string }; + + /** + * A Number or Function to get the "local" volume for playLocal calls. + * Functions are called for a return value, and Numbers are constant + * (defaults to 1). + * + */ + getVolumeLocal?: number | { (...args: any[]): number }; + } + + export interface IAudioPlayr { + getLibrary(): any; + getFileTypes(): string[]; + getSounds(): any; + getTheme(): HTMLAudioElement; + getDirectory(): string; + getVolume(): number; + setVolume(volume: number): void; + getMuted(): boolean; + setMuted(muted: boolean): void; + toggleMuted(): void; + setMutedOn(): void; + setMutedOff(): void; + getGetVolumeLocal(): any; + setGetVolumeLocal(getVolumeLocalNew: any): void; + getGetThemeDefault(): any; + setGetThemeDefault(getThemeDefaultNew: any): void; + play(name: string): HTMLAudioElement; + pauseAll(): void; + resumeAll(): void; + pauseTheme(): void; + resumeTheme(): void; + clearTheme(): void; + playLocal(name: string, location?: any): HTMLAudioElement; + playTheme(name?: string, loop?: boolean): HTMLAudioElement; + playThemePrefixed(prefix?: string, name?: string, loop?: boolean): HTMLAudioElement; + addEventListener(name: string, event: string, callback: any): void; + removeEventListeners(name: string, event: string): void; + addEventImmediate(name: string, event: string, callback: any): void; + } +} + + +module AudioPlayr { + "use strict"; + + /** + * An audio library to automate preloading and controlled playback of multiple + * audio tracks, with support for different browsers' preferred file types. + * Volume and mute status are stored locally using a ItemsHoldr. + */ + export class AudioPlayr implements IAudioPlayr { + /** + * A listing of filenames to be turned into