"use strict"; /*: * @plugindesc v2.0.1 Creates buttons on the screen for touch input * @author Aloe Guvner * * * @param dPadSettings * @text D-Pad Settings * @type struct * @desc Settings for the D-Pad. * * @param keyButtonSettings * @text Key Button Settings * @type struct[] * @desc Settings for on-screen buttons that simulate key presses. * * @param controlButtonSettings * @text Control Button Settings * @type struct * @desc A "toggle" button that allows players to turn the UI * on and off. * * @param fadeDuration * @text Fade Duration * @desc Duration of hiding the buttons (number of frames) * for the buttons to fade and un-fade. * @default 20 * @type number * * @param fadeDelay * @text Fade Delay * @desc Delay before hiding and unhiding buttons (number * of frames) * @default 1 * @type number * * @param disableTouchWindows * @text Disable Touch Selectable Windows * @type text[] * @desc Disable the touch input for selectable windows * in these scenes. * @default ["Scene_Menu"] * * @param disableTouchMovement * @text Disable Touch Movement * @type boolean * @desc Disable touch movement on the map when a DPad is active. * @default false * * @param enableDiagonalInput * @text Enable Diagonal Input * @type boolean * @desc If the player touches in the corners of the D-Pad, both * direction inputs are recorded. See info in help file. * @default false * * @param hideButtonsDuringDialogue * @text Hide Buttons During Dialogue * @type boolean * @desc Hide the virtual buttons during event dialogue. * @default true * * @param enableDPadDebugWindow * @text Enable DPad Debug Window * @type boolean * @desc Shows a window with the current D-Pad state. For * plugin debugging only. * @default false * * @help * * //============================================================================= * // Background: * //============================================================================= * This plugin focuses on improving the user interface for mobile games created * in RPG Maker MV. This plugin allows the developer to have virtual buttons * on the screen that interact with touch input. * * This plugin allows maximum flexibility for the developer, you can add * as many or as few buttons as you want to the screen, and you can add these buttons * on whichever screens you would like (i.e. map, menu, credits, title, etc.). * * //============================================================================= * // Functionality: * //============================================================================= * * This plugin can create 3 different types of buttons: * -Directional Pad * --A single picture which is used for up, left, right, and down movement. * --The picture is divided into 9 sections. The top 3 sections trigger the "up" * input, the left 3 sections trigger the "left" input, the right 3 sections * trigger the "right" input, and the bottom 3 section triggers the "down" input. * --The middle section does not trigger any input. * --The scenes that this button appears in can be defined. * --This button is not mandatory. * * -Key buttons * --These buttons can be used to represent any key. Common keys to use would be * "ok" , "escape", "pagedown", "pageup". * --However, these can be any key, and there can be as many or as few as the developer * would like. * --Additionally, the scenes that these buttons appear in can be controlled individually. * * * -Control button * --The control button, if pressed, will collapse and hide other buttons on the screen. * --If pressed again, it will expand and show other buttons on the screen. * --You can configure which other buttons are affected. This can allow you to create * a dynamic menu where pressing this button opens other buttons for "Items", "Save", * etc., while leaving the DPad or any other button active all of the time. * --The scenes that this button appears in can be defined. * --This button is not mandatory. * * //============================================================================= * // Touch Input Methods: * //============================================================================= * * The following methods can be chosen for any of the key buttons. The default * method is "triggered". * * Triggered: * This input method occurs when the button is just pressed down. It occurs only * once, in the same frame that the button was pressed. * * Pressed: * This input method occurs every frame while the button is pressed down. Any action * that this button is doing will execute every frame (60 frames per second) * * Repeated: * This input method occurs after 24 frames from when the button is pressed, and * then occurs every 6 frames while the button is still pressed. * * Long Pressed: * This input method occurs after 24 frames from when the button is pressed, and * then occurs every frame while the button is still pressed. * * Released: * This input method occurs when the button is no longer being pressed. * * //============================================================================= * // Setup: * //============================================================================= * This plugin requires a new folder to be created within the project "img" folder. * The folder must be titled "VirtualButtons". * Place all UI button images into this folder, and they can be accessed from the * plugin parameters. * * //============================================================================= * // Vibrate Parameter * //============================================================================= * Buttons can trigger a vibrate on the mobile device when pressed, controlled by * a parameter. * This parameter follows a pattern of vibrate,pause,vibrate,pause, etc. * Separate each time interval by a comma. * Examples: * 200 --> vibrate for 200ms * 100,30,100,30,100,30 --> vibrate for 100ms, pause for 30ms; repeat 2 more times * * Note that most devices support the Vibration API, but not all. * Additionally, this may not work in all methods of deployment. * * //============================================================================= * // Plugin Commands: * //============================================================================= * All plugin commands begin with VirtualButtons or MobileUI (for backwards compatibility). * All plugin commands are not case sensitive * (i.e. virtualbuttons is the same as VirtualButtons) * (i.e. DPad is the same as dpad) * * //============================================================================= * hide: hides the specified button * //============================================================================= * Allowed first arguments: * -all * -DPad * -Control * -Any key button defined in the parameters * * Allowed second arguments: * -instant (optional, this will hide the button instantly) * * Examples: * MobileUI hide DPad * mobileui hide Ok instant * MobileUI hide PageDown * virtualbuttons hide all * * //============================================================================= * show: shows the specified button * //============================================================================= * Allowed first arguments: * -all * -DPad * -Control * -Any key button defined in the parameters * * Allowed second arguments: * -instant (optional, this will show the button instantly) * * Examples: * MobileUI show dpad * mobileui show ok * MobileUI show PageUp instant * virtualbuttons show all * * //============================================================================= * opacity: changes the opacity of the specified button * //============================================================================= * * Allowed first arguments: * -all * -DPad * -Control * -Any key button defined in the parameters * * Allowed second arguments: * -A number between 0 and 255 corresponding to the new opacity for the button * * Examples: * virtualbuttons opacity dpad 100 * VirtualButtons opacity menu 200 (assuming 'menu' is a key button) * virtualbuttons opacity all 150 * * //============================================================================= * Diagonal Movement Parameter * //============================================================================= * * There is a parameter that controls whether diagonal input is recorded from the * D-Pad. This is not a diagonal movement plugin! This parameter merely controls * whether touching on the top left will add the input values of both "top" and * "left" to the input state. Other diagonal movement plugins would consume these * input values to move the character diagonally. * * If your game uses diagonal movement, this parameter must be on. If your game * does not use diagonal movement, it is recommended to turn this parameter off. * * //============================================================================= * Terms of Use: * //============================================================================= * Free for use in commercial or non-commercial projects. * Credits required to: Aloe Guvner * * //============================================================================= * Version History: * //============================================================================= * v2.0.1 (May 13 2019) * --Fix bug where DPad got stuck in menus * v2.0.0 (May 4 2019) * --Clears input state on transfer to mitigate stuck DPad input bug * --Improves clearing of input state each frame to mitigate bug * --Fix bug where the DPad would not clear the direction after a parallel event * checking for a input direction triggered a Show Choices event command * --Add plugin parameter to toggle whether the buttons are hidden during dialogue * --Plugin command to change button opacity * --Plugin command option to hide all buttons * --Plugin command option to show all buttons * --Delay parameter to fade-in * --Option to use a "hot" image that shows when the button is pressed * --Key buttons can trigger common events * --Buttons hidden via plugin command will stay hidden until the show plugin command * v1.4.0 (December 13 2018) * --Added ability to configure which buttons are affected by the "control" button * Can be used to create dynamic menus. * v1.3.1 (October 30 2018) * --Added a parameter to control whether diagonal movement is detected as a * possible fix for a hard to reproduce movement bug. * v1.3.0 (September 27 2018) * --Added a parameter to choose to disable the normal touch input on any chosen * scene. The only touch input enabled on these scenes is the mobile UI. * v1.2.3 (September 27 2018) * --Fixed a bug where buttons that the player had chosen to hide would reappear * after a game message. * v1.2.2 (September 27 2018) * --Fixed a bug where buttons could be pressed before they were fully visible * v1.2.1 (September 27 2018) * --Added an "instant" feature to hide/show for smoother cutscene transitions * v1.2.0 (August 26 2018) * --Added ability to vibrate when button is pressed * v1.1.0 (June 27 2018) * --Fixed bug with awkward player movement on the DPad * --Added ability to specify the type of touch input on key buttons * v1.0.3 (May 14 2018) * --Added ability to run custom code when a key button is pressed * v1.0.2 (May 9 2018) * --Added ability to play a sound effect when a button is pressed * --Fixed a bug where the parameters weren't read correctly due to plugin name change * --Fixed a bug where the control button didn't hide the dpad properly * v1.0.1 (May 8 2018) * --Added a version compatible with MV earlier than 1.6.0 using Babel.js * v1.0.0 (April 17 2018) * --Initial release * * //============================================================================= * End of Help File * //============================================================================= */ /*~struct~dpad: * @param image * @text Image * @type file * @dir img/VirtualButtons * @desc File path for the D-Pad image * @require 1 * * @param hotImage * @text Hot Image * @type file * @dir img/VirtualButtons * @desc File path for the "Hot" button image * This image shows while the dpad is being pressed * @require 1 * * @param activeScenes * @text Scenes to show the D-Pad * @type text[] * @desc A list of scenes where the D-Pad will be active. * Ex. Scene_Map, Scene_Title, etc. * @default ["Scene_Title","Scene_Map"] * * @param x * @text X * @desc X position of the D-Pad. Formulas are allowed. * (ex. Graphics.width - 96) * @type text * @default 0 * * @param y * @text Y * @desc Y position of the D-Pad. Formulas are allowed. * (ex. Graphics.height - 96) * @type text * @default 0 * * @param soundEffect * @text Sound Effect * @type struct * @desc Sound Effect to play when button is pressed. * Depending on scenario, SE might already play. Test first. * */ /*~struct~keyButton: * @param name * @text Name * @type text * @desc The name of the button * * @param inputMethod * @text Input Method * @type select * @option Triggered * @value 0 * @option Pressed * @value 1 * @option Repeated * @value 2 * @option Long Pressed * @value 3 * @option Released * @value 4 * @desc The type of touch input that will trigger the button. * See the help file for full descriptions of the options. * @default 0 * * @param inputTrigger * @text Input Code * @type text * @desc The input code triggered when the button is pressed. * ex. ok / escape / pagedown / pageup * * @param image * @text Image * @type file * @dir img/VirtualButtons * @desc File path for the button image * @require 1 * * @param hotImage * @text Hot Image * @type file * @dir img/VirtualButtons * @desc File path for the "Hot" button image * This image shows while the button is being pressed * @require 1 * * @param activeScenes * @text Scenes to show the button * @type text[] * @desc A list of scenes where the button will be active. * Ex. Scene_Map, Scene_Title, etc. * @default ["Scene_Title","Scene_Map"] * * @param x * @text X * @type text * @desc X position of the button. Formulas are allowed. * (ex. Graphics.width - 96) * @default 0 * * @param y * @text Y * @type text * @desc Y position of the button. Formulas are allowed. * (ex. Graphics.height - 96) * @default 0 * * @param soundEffect * @text Sound Effect * @type struct * @desc Sound Effect to play when button is pressed. * Depending on scenario, SE might already play. Test first. * * @param commonEvent * @text Common Event * @type number * @desc Common Event to trigger when the button is pressed. * @default 0 * @min 0 * * @param customCode * @text Custom Code * @type note * @desc Custom Javascript code to run on button press. * Use the 'this' keyword to refer to the current scene. * * @param vibratePattern * @text Vibrate Pattern * @type text * @default 0 * @desc Pattern of miliseconds to vibrate on press. * Use 0 for no vibration. See help for more info. */ /*~struct~controlButton: * @param image * @text Image * @type file * @dir img/VirtualButtons * @desc File path for the button image * @require 1 * * @param activeScenes * @text Scenes to show the control button * @type text[] * @desc A list of scenes where the button will be active. * Ex. Scene_Map, Scene_Title, etc. * @default ["Scene_Title","Scene_Map"] * * @param x * @text X * @type text * @desc X position of the button. Formulas are allowed. * (ex. Graphics.width - 96) * @default 0 * * @param y * @text Y * @type text * @desc Y position of the button. Formulas are allowed. * (ex. Graphics.height - 96) * @default 0 * * @param soundEffect * @text Sound Effect * @type struct * @desc Sound Effect to play when button is pressed. * Depending on scenario, SE might already play. Test first. * * @param buttonsToHide * @text Buttons To Show / Hide * @type text[] * @desc A list of the Key Buttons to show and hide when * this button is pressed. Leave empty to hide all. * @default [] * * @param hideDPad * @text Show / Hide DPad? * @type boolean * @desc Controls whether the DPad is affected when * this button is pressed. * @default true * */ /*~struct~soundEffect: * @param name * @text Sound Effect Name * @type file * @dir audio/se * @desc Sound effect to play when the button is pressed. * @default * @require 1 * * @param volume * @text Volume * @type number * @min 0 * @max 100 * @desc Volume of the sound effect, in % * Allowed values: 0% - 100% * @default 90 * * @param pitch * @text Pitch * @type number * @min 50 * @max 150 * @desc Pitch of the sound effect, in % * Allowed values: 50% - 150% * @default 100 * * @param pan * @text Pan * @type number * @min -100 * @max 100 * @desc Pan of the sound effect * Allowed values: -100 - 100 * @default 0 * */ var ALOE = ALOE || {}; (function () { "use strict"; var Alias = {}; var Parameters = {}; //============================================================================= // Utils //============================================================================= // Create a utility function to parse complex parameters. //============================================================================= ALOE.recursiveParse = function (param) { try { return JSON.parse(param, function (key, value) { try { return this.recursiveParse(value); } catch (e) { return value; } }.bind(this)); } catch (e) { return param; } }; //============================================================================= // Parameters //============================================================================= // Read and parse parameters into a locally scoped Parameters object. //============================================================================= Object.keys(PluginManager.parameters("ALOE_VirtualButtons")).forEach(function (a) { return Parameters[a] = ALOE.recursiveParse(PluginManager.parameters("ALOE_VirtualButtons")[a]); }); //============================================================================= // ImageManager //============================================================================= // Load and reserve virtual button images. //============================================================================= ImageManager.loadVirtualButton = function (filename, hue) { return this.loadBitmap('img/VirtualButtons/', filename, hue, true); }; ImageManager.reserveVirtualButton = function (filename, hue, reservationId) { return this.reserveBitmap('img/VirtualButtons/', filename, hue, true, reservationId); }; //============================================================================= // Sprite_VirtualButton //============================================================================= // Sprite for the UI button(s) // Parent class for Sprite_DirectionalPad, Sprite_KeyButton, Sprite_ControlButton //============================================================================= function Sprite_VirtualButton() { this.initialize.apply(this, arguments); } Sprite_VirtualButton.prototype = Object.create(Sprite_Base.prototype); Sprite_VirtualButton.prototype.constructor = Sprite_VirtualButton; Sprite_VirtualButton.prototype.initialize = function (x, y, normalImage, soundEffect, vibratePattern, hotImage) { Sprite_Base.prototype.initialize.call(this); if (normalImage) { this.bitmap = ImageManager.loadVirtualButton(normalImage); this.normalImage = this.bitmap; } if (hotImage) { this.hotImage = ImageManager.loadVirtualButton(hotImage); } if (soundEffect) { this._soundEffect = soundEffect; } if (vibratePattern) { if (!window.navigator.vibrate) { this._vibratePattern = 0; } else if (typeof vibratePattern === 'number') { this._vibratePattern = vibratePattern; } else { this._vibratePattern = vibratePattern.split(',').map(Number); } } if (isNaN(x)) { x = eval(x); } if (isNaN(y)) { y = eval(y); } this.move(x, y); this._start = new Point(null, null); this._distance = new Point(null, null); this._destination = new Point(null, null); this._velocity = new Point(null, null); this._origin = new Point(x, y); this._hiding = false; this._showing = false; this._duration = Parameters["fadeDuration"]; this._delay = Parameters["fadeDelay"]; this._delayCounter = 0; this.active = true; this._pluginHidden = false; this.z = 5; }; Sprite_VirtualButton.prototype.update = function () { Sprite_Base.prototype.update.call(this); if (this.active) { this.updateTouchInput(); } if (this.active && this.updateHotImage) { this.updateHotImage(); } if (this.moving) { this.updatePosition(); } if (!this.active) { this.updateActive(); } }; Sprite_VirtualButton.prototype.updateTouchInput = function () {}; Sprite_VirtualButton.prototype.updateHotImage = function () { if (TouchInput.isPressed()) { var point = new Point(TouchInput.x, TouchInput.y); if (this.containsPoint(point)) { if (this.hotImage) { this.bitmap = this.hotImage; } } } else { if (this.bitmap !== this.normalImage) { this.bitmap = this.normalImage; } } }; Sprite_VirtualButton.prototype.updateVisibility = function () { if (this._hiding && this.opacity > 0) { if (this._delayCounter < this._delay) { this._delayCounter++; } else { this.opacity -= 255 / this._duration; if (this.opacity <= 0) { this._delayCounter = 0; this._showing = false; } } } else if (this._showing && this.opacity < 255) { if (this._delayCounter < this._delay) { this._delayCounter++; } else { this.opacity += 255 / this._duration; if (this.opacity >= 255) this._delayCounter = 0; } } }; Sprite_VirtualButton.prototype.updateActive = function () { if (this.opacity === 255) { this.active = true; } }; Sprite_VirtualButton.prototype.updatePosition = function () { this.x += this._velocity.x; this.y += this._velocity.y; var currentPos = new Point(this.x, this.y); var currentDistance = this.absDistance(this._start, currentPos); if (currentDistance >= this._distance.abs) { this.x = this._destination.x; this.y = this._destination.y; this._velocity.x = 0; this._velocity.y = 0; this.moving = false; } }; Sprite_VirtualButton.prototype.hide = function () { this._hiding = true; this.active = false; }; Sprite_VirtualButton.prototype.show = function () { this._hiding = false; this._showing = true; }; Sprite_VirtualButton.prototype.hideInstant = function () { this._hiding = true; this.opacity = 0; this.active = false; this._delayCounter = this._delay; }; Sprite_VirtualButton.prototype.showInstant = function () { this._hiding = false; this._showing = true; this.opacity = 255; this.active = true; this._delayCounter = this._delay; }; Sprite_VirtualButton.prototype.collapse = function (x, y) { this._destination.x = x; this._destination.y = y; this._start.x = this.x; this._start.y = this.y; this._distance.x = this._destination.x - this._start.x; this._distance.y = this._destination.y - this._start.y; this._distance.abs = this.absDistance(this._destination, this._start); this._velocity.x = this._distance.x / this._duration; this._velocity.y = this._distance.y / this._duration; this.moving = true; }; Sprite_VirtualButton.prototype.expand = function () { this._destination.x = this._origin.x; this._destination.y = this._origin.y; this._start.x = this.x; this._start.y = this.y; this._distance.x = this._destination.x - this._start.x; this._distance.y = this._destination.y - this._start.y; this._distance.abs = this.absDistance(this._destination, this._start); this._velocity.x = this._distance.x / this._duration; this._velocity.y = this._distance.y / this._duration; this.moving = true; }; Sprite_VirtualButton.prototype.absDistance = function (pos1, pos2) { return Math.sqrt(Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2)); }; //============================================================================= // Sprite_DirectionalPad //============================================================================= // Sprite for the Directional Pad //============================================================================= function Sprite_DirectionalPad() { this.initialize.apply(this, arguments); } Sprite_DirectionalPad.prototype = Object.create(Sprite_VirtualButton.prototype); Sprite_DirectionalPad.prototype.constructor = Sprite_DirectionalPad; Sprite_DirectionalPad.prototype.initialize = function (x, y, image, hotImage, soundEffect) { Sprite_VirtualButton.prototype.initialize.call(this, x, y, image, soundEffect, undefined, hotImage); this._lastInput = ""; this._hiding = false; }; Sprite_DirectionalPad.prototype.updateTouchInput = function () { this.clearLastDirection(); if (TouchInput.isPressed()) { var point = new Point(TouchInput.x, TouchInput.y); if (this.containsPoint(point)) { if (this._soundEffect) { AudioManager.playSe(this._soundEffect); } var index = this.whichIndex(point); switch (index) { case 0: if (Parameters.enableDiagonalInput) { Input._currentState["up"] = true; Input._currentState["left"] = true; this._lastInput = "up-left"; } break; case 1: Input._currentState["up"] = true; this._lastInput = "up"; break; case 2: if (Parameters.enableDiagonalInput) { Input._currentState["right"] = true; Input._currentState["up"] = true; this._lastInput = "up-right"; } break; case 3: Input._currentState["left"] = true; this._lastInput = "left"; break; case 4: break; case 5: Input._currentState["right"] = true; this._lastInput = "right"; break; case 6: if (Parameters.enableDiagonalInput) { Input._currentState["left"] = true; Input._currentState["down"] = true; this._lastInput = "down-left"; } break; case 7: Input._currentState["down"] = true; this._lastInput = "down"; break; case 8: if (Parameters.enableDiagonalInput) { Input._currentState["down"] = true; Input._currentState["right"] = true; this._lastInput = "down-right"; } break; default: break; } } } }; Sprite_DirectionalPad.prototype.whichIndex = function (point) { var index = 0; index += point.x - this.x > this.width / 3 ? point.x - this.x > this.width * 2 / 3 ? 2 : 1 : 0; index += point.y - this.y > this.height / 3 ? point.y - this.y > this.height * 2 / 3 ? 6 : 3 : 0; return index; }; Sprite_DirectionalPad.prototype.clearLastDirection = function () { if (this._lastInput) { this._lastInput.split("-").forEach(function (direction) { return Input._currentState[direction] = false; }); this._lastInput = ""; } }; //============================================================================= // Sprite_KeyButton //============================================================================= // Sprite for the buttons that simulate a key input (besides arrow keys). // Ex. "ok", "cancel", "pageup", "pagedown" //============================================================================= function Sprite_KeyButton() { this.initialize.apply(this, arguments); } Sprite_KeyButton.prototype = Object.create(Sprite_VirtualButton.prototype); Sprite_KeyButton.prototype.constructor = Sprite_KeyButton; Sprite_KeyButton.prototype.initialize = function (x, y, image, hotImage, soundEffect, inputTrigger, customCode, vibratePattern) { var inputMethod = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0; var commonEvent = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 0; Sprite_VirtualButton.prototype.initialize.call(this, x, y, image, soundEffect, vibratePattern, hotImage); if (inputTrigger) { this._inputTrigger = inputTrigger; } if (customCode) { this._customCode = customCode; this._customFunction = new Function(customCode).bind(SceneManager._scene); } this._commonEvent = commonEvent; this._inputMethod = inputMethod; }; Sprite_KeyButton.prototype.isTouchTriggered = function () { switch (this._inputMethod) { case 0: // Was just pressed return TouchInput.isTriggered(); case 1: //Currently pressed down return TouchInput.isPressed(); case 2: //Is repeated return TouchInput.isRepeated(); case 3: //Is kept pressed return TouchInput.isLongPressed(); case 4: //Was just released return TouchInput.isReleased(); default: return TouchInput.isTriggered(); } }; Sprite_KeyButton.prototype.updateTouchInput = function () { if (this.isTouchTriggered()) { var point = new Point(TouchInput.x, TouchInput.y); if (this.containsPoint(point)) { if (this._soundEffect) { AudioManager.playSe(this._soundEffect); } if (this._vibratePattern) { window.navigator.vibrate(this._vibratePattern); } if (this._customFunction) { this._customFunction(); } if (this._commonEvent && $gameTemp) { $gameTemp.reserveCommonEvent(this._commonEvent); } if (this._inputTrigger) { Input._currentState[this._inputTrigger] = true; } } else { Input._currentState[this._inputTrigger] = false; } } else { Input._currentState[this._inputTrigger] = false; } }; //============================================================================= // Sprite_ControlButton //============================================================================= // Sprite for the button that activates / deactivates all other buttons. //============================================================================= function Sprite_ControlButton() { this.initialize.apply(this, arguments); } Sprite_ControlButton.prototype = Object.create(Sprite_VirtualButton.prototype); Sprite_ControlButton.prototype.constructor = Sprite_ControlButton; Sprite_ControlButton.prototype.initialize = function (x, y, image, soundEffect) { Sprite_VirtualButton.prototype.initialize.call(this, x, y, image, soundEffect); this._inputTrigger = "control"; this._buttonsHidden = false; }; Sprite_ControlButton.prototype.updateTouchInput = function () { if (TouchInput.isTriggered()) { var point = new Point(TouchInput.x, TouchInput.y); if (this.containsPoint(point)) { if (this._soundEffect) { AudioManager.playSe(this._soundEffect); } if (this._buttonsHidden) { this.showAllButtons(); } else { this.hideAllButtons(); } } } }; Sprite_ControlButton.prototype.showAllButtons = function () { var _this = this; var params = Parameters["controlButtonSettings"]; if (params.buttonsToHide.length > 0) { params.buttonsToHide.forEach(function (buttonName) { if (!_this._keyButtons[buttonName]) { console.error("".concat(buttonName, " is not a key button, check your Mobile UI plugin configuration.")); return; } _this._keyButtons[buttonName].show(); _this._keyButtons[buttonName].expand(); }); } else { if (this._keyButtons) { Object.values(this._keyButtons).forEach(function (button) { button.show(); button.expand(); }); } } if (params.hideDPad && this._directionalPad) { this._directionalPad.show(); this._directionalPad.expand(); } this._buttonsHidden = false; }; Sprite_ControlButton.prototype.hideAllButtons = function () { var _this2 = this; var params = Parameters["controlButtonSettings"]; if (params.buttonsToHide.length > 0) { params.buttonsToHide.forEach(function (buttonName) { if (!_this2._keyButtons[buttonName]) { console.error("".concat(buttonName, " is not a key button, check your Mobile UI plugin configuration.")); return; } _this2._keyButtons[buttonName].hide(); _this2._keyButtons[buttonName].collapse(_this2.x, _this2.y); }); } else { if (this._keyButtons) { Object.values(this._keyButtons).forEach(function (button) { button.hide(); button.collapse(_this2.x, _this2.y); }); } } if (params.hideDPad && this._directionalPad) { this._directionalPad.hide(); this._directionalPad.collapse(this.x, this.y); } this._buttonsHidden = true; }; //============================================================================= // Scene_Base //============================================================================= // Methods to create the buttons in any scene. //============================================================================= Alias.Scene_Boot_create = Scene_Boot.prototype.create; Scene_Boot.prototype.create = function () { Alias.Scene_Boot_create.call(this); if (Parameters["dPadSettings"].activeScenes) { Parameters["dPadSettings"].activeScenes = Parameters["dPadSettings"].activeScenes.map(function (a) { return eval(a); }); } if (Parameters["keyButtonSettings"]) { Parameters["keyButtonSettings"].forEach(function (a) { return a.activeScenes = a.activeScenes.map(function (b) { return b = eval(b); }); }); } if (Parameters["controlButtonSettings"].activeScenes) { Parameters["controlButtonSettings"].activeScenes = Parameters["controlButtonSettings"].activeScenes.map(function (a) { return eval(a); }); } }; Alias.Scene_Base_start = Scene_Base.prototype.start; Scene_Base.prototype.start = function () { Alias.Scene_Base_start.call(this); this.createDirPad(); this.createKeyButtons(); this.createControlButton(); }; Scene_Base.prototype.createDirPad = function () { var params = Parameters["dPadSettings"]; if (params) { if (params.activeScenes.length > 0 && params.activeScenes.contains(this.constructor)) { var x = params.x; var y = params.y; var image = params.image || ""; var hotImage = params.hotImage || ""; var soundEffect = params.soundEffect; this._directionalPad = new Sprite_DirectionalPad(x, y, image, hotImage, soundEffect); this.addChild(this._directionalPad); } } }; Scene_Base.prototype.createKeyButtons = function () { var params = Parameters["keyButtonSettings"]; if (params) { if (params.length > 0) { this._keyButtons = {}; for (var i = 0; i < params.length; i++) { if (params[i].activeScenes.length > 0 && params[i].activeScenes.contains(this.constructor)) { var a = params[i]; this._keyButtons[a.name.toLowerCase()] = new Sprite_KeyButton(a.x, a.y, a.image, a.hotImage, a.soundEffect, a.inputTrigger.toLowerCase(), a.customCode, a.vibratePattern, a.inputMethod, a.commonEvent); this.addChild(this._keyButtons[a.name.toLowerCase()]); } } } } }; Scene_Base.prototype.createControlButton = function () { var params = Parameters["controlButtonSettings"]; if (params) { if (params.activeScenes.length > 0 && params.activeScenes.contains(this.constructor)) { var x = params.x; var y = params.y; var image = params.image || ""; var soundEffect = params.soundEffect; this._controlButton = new Sprite_ControlButton(x, y, image, soundEffect); this.addChild(this._controlButton); this._controlButton._keyButtons = this._keyButtons; this._controlButton._directionalPad = this._directionalPad; } } }; Scene_Base.prototype.hideVirtualButtons = function () { var _this3 = this; if (this._directionalPad) { this._directionalPad.hide(); } if (this._keyButtons) { Object.keys(this._keyButtons).forEach(function (a) { return _this3._keyButtons[a].hide(); }); } if (this._controlButton) { this._controlButton.hide(); } }; Scene_Base.prototype.showVirtualButtons = function () { var _this4 = this; if (this._directionalPad && !this._directionalPad._pluginHidden) { this._directionalPad.show(); } if (this._keyButtons) { Object.keys(this._keyButtons).forEach(function (button) { if (!_this4._keyButtons[button]._pluginHidden) _this4._keyButtons[button].show(); }); } if (this._controlButton && !this._controlButton._pluginHidden) { this._controlButton.show(); } }; Alias.Scene_Base_terminate = Scene_Base.prototype.terminate; Scene_Base.prototype.terminate = function () { var _this5 = this; Alias.Scene_Base_terminate.call(this); if (this._directionalPad) { this.removeChild(this._directionalPad); } if (this._keyButtons) { Object.keys(this._keyButtons).forEach(function (a) { return _this5.removeChild(_this5._keyButtons[a]); }); } if (this._controlButton) { this.removeChild(this._controlButton); } }; //============================================================================= // Scene_Map //============================================================================= // If map movement is disabled from the parameters, return. // If an active button is pressed, don't do the usual map movement. //============================================================================= Alias.Scene_Map_processMapTouch = Scene_Map.prototype.processMapTouch; Scene_Map.prototype.processMapTouch = function () { var _this6 = this; if (Parameters['disableTouchMovement'] && this._directionalPad && this._directionalPad.active) { return; } if (TouchInput.isTriggered()) { var point = new Point(TouchInput.x, TouchInput.y); if (!!this._controlButton) { if (this._controlButton.containsPoint(point)) { return; } } if (this._directionalPad) { if (this._directionalPad.active && this._directionalPad.containsPoint(point)) { return; } } if (this._keyButtons) { if (Object.keys(this._keyButtons).some(function (a) { return _this6._keyButtons[a].containsPoint(point); })) { return; } } } Alias.Scene_Map_processMapTouch.call(this); }; //============================================================================= // Window_Selectable //============================================================================= // Disable Touch Input on selectable windows if configured in the parameters. //============================================================================= Alias.Window_Selectable_processTouch = Window_Selectable.prototype.processTouch; Window_Selectable.prototype.processTouch = function () { if (Parameters['disableTouchWindows'].contains(SceneManager._scene.constructor.name)) { return; } Alias.Window_Selectable_processTouch.call(this); }; //============================================================================= // Window_Message //============================================================================= // Control UI visibility when the dialogue window is activated. //============================================================================= if (Parameters.hideButtonsDuringDialogue) { Alias.Window_Message_startMessage = Window_Message.prototype.startMessage; Window_Message.prototype.startMessage = function () { SceneManager._scene.hideVirtualButtons(); ALOE.clearDpadInput(); Alias.Window_Message_startMessage.call(this); }; Alias.Window_Message_terminateMessage = Window_Message.prototype.terminateMessage; Window_Message.prototype.terminateMessage = function () { Alias.Window_Message_terminateMessage.call(this); if (SceneManager._scene._controlButton && SceneManager._scene._controlButton._buttonsHidden) { SceneManager._scene._controlButton.show(); } else { SceneManager._scene.showVirtualButtons(); } }; } //============================================================================= // Game_Interpreter //============================================================================= // Plugin commands //============================================================================= function pluginCommandHideDpad(scene, args) { if (scene._directionalPad) { if (args[2] && args[2].toLowerCase() === 'instant') { scene._directionalPad.hideInstant(); } else { scene._directionalPad.hide(); } scene._directionalPad._pluginHidden = true; } } function pluginCommandHideControl(scene, args) { if (scene._controlButton) { if (args[2] && args[2].toLowerCase() === 'instant') { scene._controlButton.hideInstant(); } else { scene._controlButton.hide(); } scene._controlButton._pluginHidden = true; } } function pluginCommandHideAllKeyButtons(scene, args) { if (scene._keyButtons) { if (args[2] && args[2].toLowerCase() === 'instant') { Object.keys(scene._keyButtons).forEach(function (keyButton) { scene._keyButtons[keyButton].hideInstant(); scene._keyButtons[keyButton]._pluginHidden = true; }); } else { Object.keys(scene._keyButtons).forEach(function (keyButton) { scene._keyButtons[keyButton].hide(); scene._keyButtons[keyButton]._pluginHidden = true; }); } } } function pluginCommandHideKeyButton(scene, args) { if (scene._keyButtons[args[1].toLowerCase()]) { if (args[2] && args[2].toLowerCase() === 'instant') { scene._keyButtons[args[1].toLowerCase()].hideInstant(); } else { scene._keyButtons[args[1].toLowerCase()].hide(); } scene._keyButtons[args[1].toLowerCase()]._pluginHidden = true; } } function pluginCommandShowDpad(scene, args) { if (scene._directionalPad) { if (args[2] && args[2].toLowerCase() === 'instant') { scene._directionalPad.showInstant(); } else { scene._directionalPad.show(); } scene._directionalPad._pluginHidden = false; } } function pluginCommandShowControl(scene, args) { if (scene._controlButton) { if (args[2] && args[2].toLowerCase() === 'instant') { scene._controlButton.showInstant(); } else { scene._controlButton.show(); } scene._controlButton._pluginHidden = false; } } function pluginCommandShowAllKeyButtons(scene, args) { if (scene._keyButtons) { if (args[2] && args[2].toLowerCase() === 'instant') { Object.keys(scene._keyButtons).forEach(function (keyButton) { scene._keyButtons[keyButton].showInstant(); scene._keyButtons[keyButton]._pluginHidden = false; }); } else { Object.keys(scene._keyButtons).forEach(function (keyButton) { scene._keyButtons[keyButton].show(); scene._keyButtons[keyButton]._pluginHidden = false; }); } } } function pluginCommandShowKeyButton(scene, args) { if (scene._keyButtons[args[1].toLowerCase()]) { if (args[2] && args[2].toLowerCase() === 'instant') { scene._keyButtons[args[1].toLowerCase()].showInstant(); } else { scene._keyButtons[args[1].toLowerCase()].show(); } scene._keyButtons[args[1].toLowerCase()]._pluginHidden = false; } } function pluginCommandOpacityDpad(scene, args) { if (scene._directionalPad) { scene._directionalPad.opacity = parseInt(args[2]); } } function pluginCommandOpacityControlButton(scene, args) { if (scene._controlButton) { scene._controlButton.opacity = parseInt(args[2]); } } function pluginCommandOpacityKeyButton(scene, args) { if (scene._keyButtons[args[1].toLowerCase()]) { scene._keyButtons[args[1].toLowerCase()].opacity = parseInt(args[2]); } } function pluginCommandOpacityAllKeyButtons(scene, args) { Object.keys(scene._keyButtons).forEach(function (keyButton) { return scene._keyButtons[keyButton].opacity = parseInt(args[2]); }); } Alias.Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand; Game_Interpreter.prototype.pluginCommand = function (command, args) { Alias.Game_Interpreter_pluginCommand.call(this, command, args); if (command.toLowerCase() === "mobileui" || command.toLowerCase() === "virtualbuttons") { var scene = SceneManager._scene; switch (args[0].toLowerCase()) { case "hide": switch (args[1].toLowerCase()) { case "dpad": pluginCommandHideDpad(scene, args); break; case "control": pluginCommandHideControl(scene, args); break; case "all": pluginCommandHideDpad(scene, args); pluginCommandHideControl(scene, args); pluginCommandHideAllKeyButtons(scene, args); break; default: pluginCommandHideKeyButton(scene, args); break; } break; case "show": switch (args[1].toLowerCase()) { case "dpad": pluginCommandShowDpad(scene, args); break; case "control": pluginCommandShowControl(scene, args); break; case "all": pluginCommandShowDpad(scene, args); pluginCommandShowControl(scene, args); pluginCommandShowAllKeyButtons(scene, args); default: pluginCommandShowKeyButton(scene, args); break; } break; case "opacity": switch (args[1].toLowerCase()) { case "dpad": pluginCommandOpacityDpad(scene, args); break; case "control": pluginCommandOpacityControlButton(scene, args); break; case "all": pluginCommandOpacityDpad(scene, args); pluginCommandOpacityControlButton(scene, args); pluginCommandOpacityAllKeyButtons(scene, args); default: pluginCommandOpacityKeyButton(scene, args); break; } } } }; if (Parameters.enableDPadDebugWindow) { //============================================================================= // Window_TouchInputTest //============================================================================= // The window to test what inputs are currently pressed on the D-Pad //============================================================================= var Window_TouchInputTest = function Window_TouchInputTest() { this.initialize.apply(this, arguments); }; Window_TouchInputTest.prototype = Object.create(Window_Base.prototype); Window_TouchInputTest.prototype.constructor = Window_TouchInputTest; Window_TouchInputTest.prototype.initialize = function () { Window_Base.prototype.initialize.call(this, Graphics.width - 300, 0, 300, 200); this._lastState = { up: false, right: false, down: false, left: false }; this.refresh(); }; Window_TouchInputTest.prototype.update = function () { Window_Base.prototype.update.call(this); if (this.stateHasChanged()) { this.refresh(); } }; Window_TouchInputTest.prototype.refresh = function () { this.contents.clear(); this.drawText("Up: ".concat(Input._currentState["up"]), 6, 0); this.drawText("Right: ".concat(Input._currentState["right"]), 6, this.lineHeight()); this.drawText("Down: ".concat(Input._currentState["down"]), 6, this.lineHeight() * 2); this.drawText("Left: ".concat(Input._currentState["left"]), 6, this.lineHeight() * 3); }; Window_TouchInputTest.prototype.stateHasChanged = function () { if (this._lastState.up !== Input._currentState["up"]) { this._lastState.up = Input._currentState["up"]; return true; } if (this._lastState.right !== Input._currentState["right"]) { this._lastState.right = Input._currentState["right"]; return true; } if (this._lastState.down !== Input._currentState["down"]) { this._lastState.down = Input._currentState["down"]; return true; } if (this._lastState.left !== Input._currentState["left"]) { this._lastState.left = Input._currentState["left"]; return true; } return false; }; var Scene_Map_createMapNameWindow = Scene_Map.prototype.createMapNameWindow; Scene_Map.prototype.createMapNameWindow = function () { this._touchInputTestWindow = new Window_TouchInputTest(); this.addChild(this._touchInputTestWindow); Scene_Map_createMapNameWindow.call(this); }; } // end if Parameters.enableDPadDebugWindow //============================================================================= // Game_Player //============================================================================= // Help solve bug with stuck movement by clearing input on map transfer. //============================================================================= var Game_Player_performTransfer = Game_Player.prototype.performTransfer; Game_Player.prototype.performTransfer = function () { if (this.isTransferring()) { Game_Player_performTransfer.call(this); ALOE.clearDpadInput(); } }; ALOE.clearDpadInput = function () { delete Input._currentState["left"]; delete Input._currentState["right"]; delete Input._currentState["up"]; delete Input._currentState["down"]; }; //============================================================================== // Array.prototype.includes // Array.prototype.find //============================================================================== // Polyfill for old versions of MV (1.5 and earlier) //============================================================================== // https://tc39.github.io/ecma262/#sec-array.prototype.includes if (!Array.prototype.includes) { Object.defineProperty(Array.prototype, 'includes', { value: function value(valueToFind, fromIndex) { if (this == null) { throw new TypeError('"this" is null or not defined'); } // 1. Let O be ? ToObject(this value). var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If len is 0, return false. if (len === 0) { return false; } // 4. Let n be ? ToInteger(fromIndex). // (If fromIndex is undefined, this step produces the value 0.) var n = fromIndex | 0; // 5. If n ≥ 0, then // a. Let k be n. // 6. Else n < 0, // a. Let k be len + n. // b. If k < 0, let k be 0. var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); function sameValueZero(x, y) { return x === y || typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y); } // 7. Repeat, while k < len while (k < len) { // a. Let elementK be the result of ? Get(O, ! ToString(k)). // b. If SameValueZero(valueToFind, elementK) is true, return true. if (sameValueZero(o[k], valueToFind)) { return true; } // c. Increase k by 1. k++; } // 8. Return false return false; } }); } // https://tc39.github.io/ecma262/#sec-array.prototype.find if (!Array.prototype.find) { Object.defineProperty(Array.prototype, 'find', { value: function value(predicate) { // 1. Let O be ? ToObject(this value). if (this == null) { throw new TypeError('"this" is null or not defined'); } var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception. if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. var thisArg = arguments[1]; // 5. Let k be 0. var k = 0; // 6. Repeat, while k < len while (k < len) { // a. Let Pk be ! ToString(k). // b. Let kValue be ? Get(O, Pk). // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). // d. If testResult is true, return kValue. var kValue = o[k]; if (predicate.call(thisArg, kValue, k, o)) { return kValue; } // e. Increase k by 1. k++; } // 7. Return undefined. return undefined; }, configurable: true, writable: true }); } //============================================================================== // Swap Plugin Parameters //============================================================================== // If both ALOE_MobileUI (old name) and ALOE_VirtualButtons (new name) are ON, // then copy the plugin parameters over. Also copy images from img/mobileui to // img/VirtualButtons. //============================================================================== if (!Utils.isOptionValid('test') && PluginManager._scripts.includes("ALOE_MobileUI")) { console.error("Conflicting version of ALOE_VirtualButtons (ALOE_MobileUI) found."); } if (Utils.isOptionValid('test') && PluginManager._scripts.includes("ALOE_MobileUI")) { nw.Window.get().showDevTools(); var fs = require('fs'); console.log("Both ALOE_VirtualButtons and ALOE_MobileUI are activated."); console.log("Initiating procedure to copy plugin parameters and images..."); console.log("Copying plugin parameters..."); var pluginsjs = fs.readFileSync('js/plugins.js', 'utf-8'); var grabParametersRegex = /ALOE_MobileUI.+"parameters":(.+)},?$/m; var match = pluginsjs.match(grabParametersRegex); if (match && match[1]) { var mobileUIParameters = match[1]; var replaceParametersRegex = /(ALOE_VirtualButtons.+"parameters":)(.+)(},?$)/m; var trailingComma = ','; // If it's the last plugin in the list, no trailing comma if (PluginManager._scripts[PluginManager._scripts.length - 1] === 'ALOE_VirtualButtons') { trailingComma = ''; } var newPluginsjs = pluginsjs.replace(replaceParametersRegex, "$1".concat(mobileUIParameters, "}").concat(trailingComma)); fs.writeFileSync('js/plugins.js', newPluginsjs); } else { console.error("Could not locate ALOE_MobileUI parameters."); } console.log("Copying plugin images..."); // Create Image Directory if (!fs.existsSync('img/VirtualButtons')) { fs.mkdirSync('img/VirtualButtons'); } if (fs.existsSync('img/mobileUI')) { fs.readdirSync('img/mobileUI').forEach(function (image) { return fs.copyFileSync("img/mobileUI/".concat(image), "img/VirtualButtons/".concat(image)); }); } else { console.error('Unable to copy from img/mobileUI to img/VirtualButtons. img/mobileUI does not exist'); } console.log("Plugin parameters and images copy successfully completed!"); console.log("============ Instructions ============\n"); console.log("1. Close the MV editor. If you press 'save' or open the Plugin Manager, it will undo the copying of the plugin parameters."); console.log("2. Verify the images were copied from img/mobileUI to img/VirtualButtons then you can remove the img/mobileUI folder"); console.log("3. Open the MV editor again, go to the Plugin Manager, right-click on ALOE_VirtualButtons and press \"Refresh\"."); console.log("4. Verify the plugin parameters were copied over and then you can remove ALOE_MobileUI."); } })();