//=============================================================================
// Bluebooth Plugins - Map Controls
// BBS_MapControls.js
//=============================================================================
//=============================================================================
/*:
* @title Map Controls Plugin
* @author Michael Morris (https://www.patreon.com/bluebooth)
* @date Feb 13, 2016
* @filename BBS_MapControls.js
* If you enjoy my work, consider supporting me on Patreon!
*
* https://www.patreon.com/bluebooth
*
* @plugindesc v1.10 Creates and displays key/mouse/touch responsive input buttons
* on the map screen. Original design was merged with elements of Masked's MBS MobileDirPad,
* and then new enhancements / reworkings were added on top of that. Swipe support.
* REQUIRES: BBS_MultiTouch.js. This script must be below BBS_MultiTouch.js in Plugin Manager.
* Special Thanks to Tsukihime for all the help.
* Special Thanks to Masked for MBS MobileDirPad on which the Map Buttons are based.
* Special Thanks to 'Ramza' Michael Sweeney and Lakaroth for helping so much with testing.
*
* ============================================================================
* Terms of Use
* ============================================================================
* - Free for use in non-commercial projects with credits
* - Contact me for commercial use
*
* ============================================================================
* Parameters
* ============================================================================
* @param -----Core-----
* @param DPad Buttonset Image
* @desc Relative filepath for display imageset for the DPad buttons.
* @default ./img/system/DPadButtonSet.png
*
* @param Action Buttonset Image
* @desc Relative filepath for display image for the action (non DPad) buttons.
* @default ./img/system/ActionButtonSet.png
*
* @param Opacity
* @desc How opaque to make all displayed controls. 0 - transparent, 255 - opaque.
* @default 255
*
* @param Fade Duration
* @desc How long, in frames (each frame 1/60th of a second), it should take to fade in or out a control.
* @default 10
*
* @param Disable Map Controls Option
* @desc Name of command to show in options menu to enable/disable map controls.
* @default Disable Map Controls
*
* @param Block Map Touch Input
* @desc If true, MapControls is "greedy" and will block all default mouse and touch input processing while custom buttons are visible.
* @default true
*
* @param Debug Mode
* @desc Enable to activate console variable logging. Use for debugging odd behaviour.
* true to enable console variable logging.
* @default false
*
* @param -----Button Positioning-----
* @param DPad Spacer
* @desc Gap in pixels between player and the DPad pictures.
* @default 10
*
* @param DPad Up Position
* @desc The DPad Up Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param DPad Down Position
* @desc The DPad Down Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param DPad Left Position
* @desc The DPad Left Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param DPad Right Position
* @desc The DPad Right Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param Action Button Position
* @desc The Action Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param Cancel Button Position
* @desc The Cancel Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param Menu Button Position
* @desc The Menu Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @param Shift Button Position
* @desc The Other Button image position on screen (in format x; y). Use -1, -1 to center on player.
* @default -1; -1
*
* @help
* ============================================================================
* Description
* ============================================================================
*
* To be used with mini-games, this creates a series of sprite buttons on screen that will respond to
* keyboard, mouse, and touch. Very flexible, can be used to create any mini-game of your choosing.
* First created to replace static arrow pictures for BBS_WorldMap.js.
*
* ============================================================================
* Plugin Commands
* ============================================================================
*
* Use the following plugin commands to manipulate custom controls.
*
* Plugin Commands:
*
* MapControls init # Initialize Map Controls, none are enabled or visible by default.
* MapControls overrideDefaultTouch override # If true, blocks all default touch processing. Use to prevent players from moving at undesirable times, etc.
* MapControls clearGui # Sets all Map Controls to disabled and invisible. Useful for changing up visible controls.
* MapControls blockMapTouchInput isBlocked # If true, GUI is "greedy" and will block all map mouse and touch input while GUI is visible.
* MapControls setButtonState btn visible enabled # Sets a specific button btn visibility to isVisible.
* MapControls setNewButtonPos btn x y # Sets a specific button btn to new x and y.
*
* ============================================================================
* Script Commands
* ============================================================================
* Script Commands:
*
* SceneManager._scene.isPressed(btn); # Used to check if a specific button is pressed. Use in conditionals.
* SceneManager._scene.isButtonEnabled(btn); # Used to check if a specific button is enabled. Use in conditionals.
*
* ============================================================================
* Change Log
* ============================================================================
* 1.10 - Fixed override check - Map Controls only ignore default input functions when at least one button is visible.
* This is to prevent input freezing during dialogue boxes, etc.
* 1.09 - Multi-touch seperated into own script to facilitate further growth.
* - Removed isolated / redundent variables.
* - Made options menu support for MapControls.
* - Added more safety checks for this._buttons while adding options menu support.
* - Fixed mouse support with new Multi-touch.
* 1.08 - Gesture history tracking added.
* 1.07 - Had to redo all major TouchInput core functions in order to fully support mult-touch and gestures.
* - integrated with https://github.com/jairajs89/Touchy.js
* - Multiple controls now appear down at same time.
* - Added in functions for swipe support (up, down, left, right).
* - Setup to allow for gesture support.
* - Successful integration of swipe support.
* - Added gesture parameters.
* 1.06 - Multi-touch support successfully added!
* - Added debug functionality to display last pressed buttons for testing.
* - Dialogue show/hide and disabling of entire UI now works properly.
* - First touch doesn't register bug fixed.
* - Touch interface more responsive (especially when displaying hot frame for multiple buttons).
* - Invisible buttons now automatically don't respond to input.
* - All Scene_Map functions now convert input to lower-case, to make script access more friendly.
* - Cleaned up block default touch handling to use only one check.
* 1.05 - Fixed issue with fadein/fadeout not activating. Used this instead of scene.
* - Fixed forgotten hardcode that prevented proper gui customization.
* - Fixed a number of other small bugs.
* 1.04 - Fixed flash of all controls when map scene first loaded. Looked cheap.
* - First few arrow X, Y calculations are wrong... fixed. Buttons now only show where they should.
* - Fixed handling fade interaction with Map Controls.
* 1.03 - Fixed input buttons responding inconsistently to touch/mouse input.
* - Removed all redundent tolowercase string manipulation.
* - Removed this._touching, does not handle mouseover.
* - Fixed logic error in handling showGui.
* 1.02 - Added in fade and button frame support. Includes hot/cold/disabled support. Fade support fixed.
* 1.01 - Plugin finished. Logic separated out from world map, added touch and mouse support to arrows.
*
*/
//=============================================================================
//=============================================================================
var Imported = Imported || {} ;
var BBS = BBS || {};
Imported.MapControls = 1;
BBS.MapControls = BBS.MapControls || {};
(function() {
//=============================================================================
// Parameter Variables
//=============================================================================
var parameters = PluginManager.parameters('BBS_MapControls');
var pDPadImg = String(parameters['DPad Up Image'] || './img/system/DPadButtonSet.png');
var pDActionBtnImg = String(parameters['Action Buttonset Image'] || './img/system/ActionButtonSet.png');
var pOpacity = Number(parameters['Opacity'] || '255');
var pFadeDuration = Number(parameters['Fade Duration'] || '15');
var pDisableMapControlsCmd = String(parameters['Disable Map Controls Option'] || 'Disable Map Controls');
var pBlockMapTouch = eval(String(parameters['Block Map Touch Input'] || 'true'));
var pDebugging = eval(String(parameters['Debug Mode'] || 'false'));
var pSpacerSize = Number(parameters['DPad Spacer'] || '10');
var pDPadUpPos = String(parameters['DPad Up Position'] || '-1; -1');
var pDPadDownPos = String(parameters['DPad Down Position'] || '-1; -1');
var pDPadLeftPos = String(parameters['DPad Left Position'] || '-1; -1');
var pDPadRightPos = String(parameters['DPad Right Position'] || '-1; -1');
var pAButtonPos = String(parameters['Action Button Position'] || '-1; -1');
var pBButtonPos = String(parameters['Cancel Button Position'] || '-1; -1');
var pXButtonPos = String(parameters['Menu Button Position'] || '-1; -1');
var pYButtonPos = String(parameters['Shift Button Position'] || '-1; -1');
//=============================================================================
// Game_Interpreter
//=============================================================================
var BBS_MC_Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
if (command === 'MapControls')
{
switch (args[0]) {
case 'init':
SceneManager._scene.initMapControls();
break;
case 'clearGui':
SceneManager._scene.clearGui();
break;
case 'overrideDefaultTouch':
SceneManager._scene.blockDefaultTouchResponse(eval(String(args[1])));
break;
case 'setButtonState':
SceneManager._scene.setButtonState(String(args[1]).toLowerCase(), eval(String(args[2])), eval(String(args[3])) );
break;
case 'setNewButtonPos':
SceneManager._scene.setNewPos(String(args[1]).toLowerCase(), Number(args[2]), Number(args[3]) );
break;
};
}
else {
BBS_MC_Game_Interpreter_pluginCommand.call(this, command, args);
}
};
//=============================================================================
// ConfigManager
//=============================================================================
ConfigManager.disableMapControls = false;
var BBS_MC_ConfigManager_makeData = ConfigManager.makeData;
ConfigManager.makeData = function() {
var config = BBS_MC_ConfigManager_makeData.call(this);
config.disableMapControls = this.disableMapControls;
return config;
};
var BBS_MC_ConfigManager_applyData = ConfigManager.applyData;
ConfigManager.applyData = function(config) {
BBS_MC_ConfigManager_applyData.call(this, config);
this.disableMapControls = this.readConfigDisableMapControls(config, 'disableMapControls');
};
ConfigManager.readConfigDisableMapControls = function(config, name) {
var value = config[name];
if (value !== undefined) {
return value;
} else {
return false;
}
};
//=============================================================================
// Window_Options
//=============================================================================
var BBS_DisableMapControls_Window_Options_addGeneralOptions = Window_Options.prototype.addGeneralOptions;
Window_Options.prototype.addGeneralOptions = function() {
BBS_DisableMapControls_Window_Options_addGeneralOptions.call(this);
this.addCommand(pDisableMapControlsCmd, 'disableMapControls');
};
//=============================================================================
// Sprite_MapButton
//=============================================================================
function Sprite_MapButton() {
this.initialize.apply(this, arguments);
this.anchor.x = 0.5;
this.anchor.y = 0.5;
this._fadeDuration = 0;
this._fadeSpeed = 0;
this.z = 5;
};
Sprite_MapButton.prototype = Object.create(Sprite_Base.prototype);
Sprite_MapButton.prototype.constructor = Sprite_MapButton;
Sprite_MapButton.prototype.initialize = function(btn, bitmapName, originStr, xRectOffset, xOffset, yOffset) {
Sprite_Base.prototype.initialize.call(this);
this._btn = btn;
this.visible = false;
this._centerOnPlayer = false;
var tmpStr = originStr.split(';');
this.x = Number(tmpStr[0]);
this.y = Number(tmpStr[1]);
this._rectXOffset = xRectOffset;
this.bitmap = ImageManager.loadNormalBitmap(bitmapName, 0);
// Account for player-centered controls.
if (this.x < 0 && this.y < 0) {
this._centerOnPlayer = true;
this._xOffset = xOffset;
this._yOffset = yOffset;
}
};
// Cuts out unnecessary load checks.
Sprite_MapButton.prototype._onBitmapLoad = function() {
this.setFrames();
this.updateMovement();
};
Sprite_MapButton.prototype.setFrames = function() {
// Reject attempt to fit Frame if bitmap not finished loading.
if (!this.bitmap.width) return;
rectWidth = Math.floor(this.bitmap.width / 4);
rectHeight = Math.floor(this.bitmap.height / 3);
this._hotFrame = new Rectangle(this._rectXOffset * rectWidth, rectHeight * 0, rectWidth, rectHeight);
this._coldFrame = new Rectangle(this._rectXOffset * rectWidth, rectHeight * 1, rectWidth, rectHeight);
this._disabledFrame = new Rectangle(this._rectXOffset * rectWidth, rectHeight * 2, rectWidth, rectHeight);
};
Sprite_MapButton.prototype.update = function() {
this.updateMovement();
if (!this.visible) return;
Sprite_Base.prototype.update.call(this);
this.updateFrame();
};
Sprite_MapButton.prototype.updateMovement = function() {
if (this._fadeDuration > 0) {
this.opacity += this._fadeSpeed;
this._fadeDuration--;
// Only truly hide when fade complete.
if (this.opacity <= 0) {
Sprite_Base.prototype.hide.call(this);
}
return;
}
if (this._centerOnPlayer) {
if (!this.width) return;
this.x = $gamePlayer.screenX() + (this._xOffset * this.width);
this.y = $gamePlayer.screenY() + (this._yOffset * this.height);
//if (pDebugging) {
// console.log(this._btn);
// console.log(this.x);
// console.log(this.y);
//}
}
};
Sprite_MapButton.prototype.updateFrame = function() {
var frame;
if (!this.enabled) {
frame = this._disabledFrame;
}
else
{
frame = this._coldFrame;
if (this.isPressed() ) {
frame = this._hotFrame;
}
}
if (frame) {
this.setFrame(frame.x, frame.y, frame.width, frame.height);
}
};
// Uses new touch input functions.
Sprite_MapButton.prototype.isTouched = function() {
var rect = new PIXI.Rectangle(this.x - this.width * this.anchor.x, this.y - this.height * this.anchor.y, this.width, this.height);
if (TouchInput.isClicked(rect)) return true;
if (TouchInput.fingers === null) return false;
return TouchInput.isTouchingArea(rect);
};
Sprite_MapButton.prototype.isPressed = function() {
if (!this.visible || !this.enabled) return false;
var pressed = Input.isPressed(this._btn) || this.isTouched();
if (pressed) {
TouchInput.addLastButton(this._btn);
}
return pressed;
};
Sprite_MapButton.prototype.hide = function() {
this._fadeDuration = pFadeDuration;
this._fadeSpeed = -1 * (pOpacity / pFadeDuration);
};
Sprite_MapButton.prototype.show = function() {
// Show begins immediately with opacity 0.
Sprite_Base.prototype.show.call(this);
this._fadeDuration = pFadeDuration;
this._fadeSpeed = 1 * (pOpacity / pFadeDuration);
};
Sprite_MapButton.prototype.toggleVisibility = function(isVisible) {
if (isVisible) {
this.show();
return;
}
this.hide();
};
//=============================================================================
// Scene_Map
//=============================================================================
Scene_Map.prototype.initMapControls = function() {
this._blockDefaultTouch = pBlockMapTouch;
this._buttonsVisible = false;
this.createControls();
};
Scene_Map.prototype.createControls = function() {
if (ConfigManager.disableMapControls) return;
this._buttons = [];
this._buttons['up'] = new Sprite_MapButton('up', pDPadImg, pDPadUpPos, 0, 0, -1.5);
this._buttons['down'] = new Sprite_MapButton('down', pDPadImg, pDPadDownPos, 1, 0, 0.5);
this._buttons['left'] = new Sprite_MapButton('left', pDPadImg, pDPadLeftPos, 2, -1, -0.5);
this._buttons['right'] = new Sprite_MapButton('right', pDPadImg, pDPadRightPos, 3, 1, -0.5);
this._buttons['ok'] = new Sprite_MapButton('ok', pDActionBtnImg, pAButtonPos, 0, 0, 0);
this._buttons['cancel'] = new Sprite_MapButton('cancel', pDActionBtnImg, pBButtonPos, 1, 0, 0);
this._buttons['menu'] = new Sprite_MapButton('menu', pDActionBtnImg, pXButtonPos, 2, 0, 0);
this._buttons['shift'] = new Sprite_MapButton('shift', pDActionBtnImg, pYButtonPos, 3, 0, 0);
this.addChild(this._buttons['up']);
this.addChild(this._buttons['down']);
this.addChild(this._buttons['left']);
this.addChild(this._buttons['right']);
this.addChild(this._buttons['ok']);
this.addChild(this._buttons['cancel']);
this.addChild(this._buttons['menu']);
this.addChild(this._buttons['shift']);
};
// Hide/Disable GUI during dialogue messages.
var BBS_IA_Scene_Map_createMessageWindows = Scene_Map.prototype.createMessageWindow;
Scene_Map.prototype.createMessageWindow = function() {
BBS_IA_Scene_Map_createMessageWindows.call(this);
var scene = this;
var oldStartMessage = this._messageWindow.startMessage;
this._messageWindow.startMessage = function() {
oldStartMessage.apply(this, arguments);
scene._hideGui();
};
var oldTerminateMessage = this._messageWindow.terminateMessage;
Window_Message.prototype.terminateMessage = function() {
oldTerminateMessage.apply(this, arguments);
TouchInput._clearHistory();
scene._showGui();
};
};
Scene_Map.prototype.blockDefaultTouchResponse = function(block) {
this._blockDefaultTouch = block;
};
// While GUI visible, override default touch functionality.
var BBS_IA_Scene_Map_processMapTouch = Scene_Map.prototype.processMapTouch;
Scene_Map.prototype.processMapTouch = function() {
// Only block map controls (including message controls) while our GUI is defined...
if (this._buttons !== undefined) {
// ...and active.
if (this._anyButtonsVisible() === true) {
//console.log("Buttons are visible");
if (this._blockDefaultTouch) return;
}
}
BBS_IA_Scene_Map_processMapTouch.call(this, arguments);
};
Scene_Map.prototype.isPressed = function(btn) {
if (this._buttons === undefined) return;
var btnSafe = btn.toLowerCase();
var pressed = this._buttons[btnSafe].isPressed() || TouchInput._history.wasPressed(btnSafe);
if (pressed) {
if (pDebugging) console.log(btnSafe);
TouchInput._history.removeBtn(btnSafe);
}
return pressed;
};
Scene_Map.prototype.setButtonState = function(btn, isVisible, isEnabled) {
if (this._buttons === undefined) return;
var btnSafe = btn.toLowerCase();
this._buttons[btnSafe].enabled = isEnabled;
this._buttons[btnSafe].toggleVisibility(isVisible);
};
// Suspected method of boolean on Show/HideGUI does NOT work.
Scene_Map.prototype._anyButtonsVisible = function() {
if (this._buttons['up'].visible) { return true; }
if (this._buttons['down'].visible) { return true; }
if (this._buttons['left'].visible) { return true; }
if (this._buttons['right'].visible) { return true; }
if (this._buttons['ok'].visible) { return true; }
if (this._buttons['cancel'].visible) { return true; }
if (this._buttons['menu'].visible) { return true; }
if (this._buttons['shift'].visible) { return true; }
return false;
}
Scene_Map.prototype._showButton = function(btn) {
if (this._buttons === undefined) return;
var btnSafe = btn.toLowerCase();
if (this._buttons[btnSafe]._hiding) {
this._buttons[btnSafe].enabled = true;
this._buttons[btnSafe].show();
}
};
Scene_Map.prototype._hideButton = function(btn) {
if (this._buttons === undefined) return;
var btnSafe = btn.toLowerCase();
if (this._buttons[btnSafe].visible) {
this._buttons[btnSafe].hide();
}
};
Scene_Map.prototype.isButtonEnabled = function(btn) {
if (this._buttons === undefined) return;
var btnSafe = btn.toLowerCase();
return this._buttons[btnSafe].enabled;
};
Scene_Map.prototype.setNewPos = function(btn, x, y) {
if (this._buttons === undefined) return;
var btnSafe = btn.toLowerCase();
this._buttons[btnSafe].x = x;
this._buttons[btnSafe].y = y;
};
Scene_Map.prototype._showGui = function() {
if (this._buttons === undefined) return;
// Ugly, but faster than a for ... in ...
this._showButton('up');
this._showButton('down');
this._showButton('left');
this._showButton('right');
this._showButton('ok');
this._showButton('cancel');
this._showButton('menu');
this._showButton('shift');
};
Scene_Map.prototype._hideGui = function() {
if (this._buttons === undefined) return;
// Ugly, but faster than a for ... in ...
this._hideButton('up');
this._hideButton('down');
this._hideButton('left');
this._hideButton('right');
this._hideButton('ok');
this._hideButton('cancel');
this._hideButton('menu');
this._hideButton('shift');
};
Scene_Map.prototype.clearGui = function() {
this._hideGui();
};
})(BBS.MapControls);
//=============================================================================
// End of File
//=============================================================================