{"size": 19121, "ext": "js", "max_stars_repo_path": "Plugins/Gimmer_ControllerType/Gimmer_ControllerType.js", "max_stars_repo_name": "gimmer/RPG-Maker-MV-Plugins", "max_stars_repo_stars_event_min_datetime": "2020-10-14T22:26:10.000Z", "max_stars_repo_stars_event_max_datetime": "2021-07-13T22:51:15.000Z", "max_issues_repo_path": "Plugins/Gimmer_ControllerType/Gimmer_ControllerType.js", "max_issues_repo_name": "gimmer/RPG-Maker-MV-Plugins", "max_issues_repo_issues_event_min_datetime": "2022-02-23T06:09:27.000Z", "max_issues_repo_issues_event_max_datetime": "2022-02-24T03:54:01.000Z", "max_forks_repo_path": "Plugins/Gimmer_ControllerType/Gimmer_ControllerType.js", "max_forks_repo_name": "gimmer/RPG-Maker-MV-Plugins", "max_forks_repo_forks_event_min_datetime": "2020-10-18T02:53:49.000Z", "max_forks_repo_forks_event_max_datetime": "2022-01-16T00:47:17.000Z"}
{"max_stars_count": 2, "max_issues_count": 1, "max_forks_count": 5, "avg_line_length": 34.1446428571, "max_line_length": 146, "alphanum_fraction": 0.6437424821}
if(Gimmer_Core === undefined){
    throw "Gimmer_Core is required for this plugin";
}

Imported = Imported || {}

Gimmer_Core['ControllerType'] = {'loaded':true};

//=============================================================================
/*:
 * @plugindesc v1.1 - Add a plugin command to return controller type
 * @author Gimmer_
 * @help Use the plugin command GimmerControllerType to get if the controller is Xbox, Playstation, or Other layouts
 *
 * ===========
 * Gimmer_ControllerType
 * ===========
 *
 * Terms of Use:
 * =======================================================================
 * Free for both commercial and non-commercial use, with credit.
 * More Gimmer_ plugins at: https://github.com/gimmer/RPG-Maker-MV-Plugins
 * =======================================================================
 *
 * @param Keyboard Ok
 * @parent ---Parameters---
 * @type select
 * @option z
 * @option space
 * @option enter
 * @desc What button do you want to display as the primary ok button for Keyboard?
 * Default: z
 * @default z
 *
 * @param Keyboard Menu
 * @parent ---Parameters---
 * @type select
 * @option x
 * @option escape
 * @option insert
 * @option numpad0
 * @desc What button do you want to display as the primary menu button for Keyboard?
 * Default: x
 * @default x
 *
 * @param Keyboard System Menu
 * @parent ---Parameters---
 * @type select
 * @option x
 * @option escape
 * @option insert
 * @option numpad0
 * @desc What button do you want to display as the primary system menu button for Keyboard? (Only used with the Gimmer_SystemMenu plugin)
 * Default: escape
 * @default escape
 *
 * @param Keyboard Cancel
 * @parent ---Parameters---
 * @type select
 * @option x
 * @option escape
 * @option insert
 * @option numpad0
 * @desc What button do you want to display as the primary cancel button for Keyboard?
 * Default: x
 * @default x
 *
 * @param Keyboard Page Up
 * @parent ---Parameters---
 * @type select
 * @option pageup
 * @option q
 * @desc What button do you want to display as the primary page up button for Keyboard?
 * Default: q
 * @default q
 *
 * @param Keyboard Page Down
 * @parent ---Parameters---
 * @type select
 * @option pagedown
 * @option w
 * @desc What button do you want to display as the primary page down button for Keyboard?
 * Default: w
 * @default w
 *
 * @param Game Pad Index
 * @parent ---Parameters---
 * @desc ADVANCED: your own game pad index to map buttons to specific icons
 * @type struct<GamePadIndexMap>
 *
 * @param Keyboard Index
 * @parent ---Parameters---
 * @desc ADVANCED: your own key board index to map keyboard keys used by RPG Maker MV to specific icons
 * @type struct<KeyboardIndexMap>
 */

/*~struct~GamePadIndexMap:
 * @param 0
 * @desc icon info for button 0
 * @type struct<IconData>
 *
 * @param 1
 * @desc icon info for button 1
 * @type struct<IconData>
 *
 * @param 2
 * @desc icon info for button 2
 * @type struct<IconData>
 *
 * @param 3
 * @desc icon info for button 3
 * @type struct<IconData>
 *
 * @param 4
 * @desc icon info for button 4
 * @type struct<IconData>
 *
 * @param 5
 * @desc icon info for button 5
 * @type struct<IconData>
 *
 * @param directions
 * @desc icon info for direction pad
 * @type struct<IconData>
 *
 */

/*~struct~KeyboardIndexMap:
 * @param enter
 * @desc icon info for enter key
 * @type struct<IconData>
 *
 * @param space
 * @desc icon info for space bar
 * @type struct<IconData>
 *
 * @param z
 * @desc icon info for z key
 * @type struct<IconData>
 *
 * @param escape
 * @desc icon info for escape key
 * @type struct<IconData>
 *
 * @param insert
 * @desc icon info for insert key
 * @type struct<IconData>
 *
 * @param x
 * @desc icon info for x key
 * @type struct<IconData>
 *
 * @param numpad0
 * @desc icon info for numpad 0 key
 * @type struct<IconData>
 *
 * @param shift
 * @desc icon info for shift key
 * @type struct<IconData>
 *
 * @param pageup
 * @desc icon info for pageup key
 * @type struct<IconData>
 *
 * @param pagedown
 * @desc icon info for pagedown key
 * @type struct<IconData>
 *
 * @param q
 * @desc icon info for q key
 * @type struct<IconData>
 *
 * @param w
 * @desc icon info for w key
 * @type struct<IconData>
 *
 * @param directions
 * @desc icon info for direction pad
 * @type struct<IconData>
 *
 */

/*~struct~IconData:
 * @param iconIndex
 * @type Number
 *
 * @param iconUnitWidth
 * @desc Multiplier of _iconWidth that makes up the width of this icon, usually 1
 * @type Number
 * @default 1
 * @Default 1
 *
 * @param iconYMod
 * @desc What iconNumber needs to be added to move to the row this icon is in (0,16,32, etc. assuming 16 icons per row)
 * @type Number
 *
 */

var ctParameters = PluginManager.parameters('Gimmer_ControllerType');
Gimmer_Core.ControllerType.ProvidedKeyBoardMap = {}
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['ok'] = ctParameters['Keyboard Ok'];
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['menu'] = ctParameters['Keyboard Menu'];
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['system'] = ctParameters['Keyboard System Menu'];
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['cancel'] = ctParameters['Keyboard Cancel'];
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['shift'] = 'shift';
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['pageup'] = ctParameters['Keyboard Page Up'];
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['pagedown'] = ctParameters['Keyboard Page Down'];
Gimmer_Core.ControllerType.ProvidedKeyBoardMap['directions'] = 'directions';
Gimmer_Core.ControllerType.CustomGamePadIndexMap = (ctParameters['Game Pad Index'].length > 0 ? JSON.parse(ctParameters['Game Pad Index']) : "");
Gimmer_Core.ControllerType.CustomKeyboardIndexMap = (ctParameters['Keyboard Index'].length > 0 ? JSON.parse(ctParameters['Keyboard Index']) : "");

//Function to validate provided custom gamepad index map
Gimmer_Core.ControllerType.validateGamePadIndexMap = function(){
    if(typeof this.CustomGamePadIndexMap === "object"){
        let valid = true;
        Object.keys(this.CustomGamePadIndexMap).every(function(value){
            if(typeof this.CustomGamePadIndexMap[value] === 'object'
                && 'iconIndex' in this.CustomGamePadIndexMap[value]
                && 'iconUnitWidth' in this.CustomGamePadIndexMap[value]
                && 'iconYMod' in this.CustomGamePadIndexMap[value]
            ){
                this.CustomGamePadIndexMap[value].iconIndex = Number(this.CustomGamePadIndexMap[value].iconIndex);
                this.CustomGamePadIndexMap[value].iconUnitWidth = Number(this.CustomGamePadIndexMap[value].iconUnitWidth);
                this.CustomGamePadIndexMap[value].iconYMod = Number(this.CustomGamePadIndexMap[value].iconYMod);
                return true;
            }
            valid = false;
            return true;
        }, this);
        if(!valid){
            this.setDefaultGamepadIndexMap();
        }
        else{
            this.GamePadIndexMap = this.CustomGamePadIndexMap;
        }
    }
    else{
        this.setDefaultGamepadIndexMap();
    }
}

//Function to validate provided custom keyboard index map
Gimmer_Core.ControllerType.validateKeyboardPadIndexMap = function(){
    if(typeof this.CustomKeyboardIndexMap === "object"){
        let valid = true;
        Object.keys(this.CustomKeyboardIndexMap).every(function(value){
            if(typeof this.CustomKeyboardIndexMap[value] === 'object'
                && 'iconIndex' in this.CustomKeyboardIndexMap[value]
                && 'iconUnitWidth' in this.CustomKeyboardIndexMap[value]
                && 'iconYMod' in this.CustomKeyboardIndexMap[value]
            ){
                this.CustomKeyboardIndexMap[value].iconIndex = Number(this.CustomKeyboardIndexMap[value].iconIndex);
                this.CustomKeyboardIndexMap[value].iconUnitWidth = Number(this.CustomKeyboardIndexMap[value].iconUnitWidth);
                this.CustomKeyboardIndexMap[value].iconYMod = Number(this.CustomKeyboardIndexMap[value].iconYMod);
                return true;
            }
            valid = false;
            return true;
        }, this);
        if(!valid){
            this.setDefaultKeyboardIndexMap();
        }
        else{
            this.KeyboardIndexMap = this.CustomKeyboardIndexMap;
        }
    }
    else{
        this.setDefaultKeyboardIndexMap();
    }
}

//Set default index map
Gimmer_Core.ControllerType.setDefaultGamepadIndexMap = function(){
    this.GamePadIndexMap = {
        '0': {iconIndex: 3, iconUnitWidth: 1, iconYMod: 0}, //Ok
        '1': {iconIndex: 2, iconUnitWidth: 1, iconYMod: 0}, //Cancel
        '2': {iconIndex: 1, iconUnitWidth: 1, iconYMod: 0}, //menu
        '3': {iconIndex: 0, iconUnitWidth: 1, iconYMod: 0}, //shift
        '4': {iconIndex: 7, iconUnitWidth: 2, iconYMod: 0}, //LB
        '5': {iconIndex: 5, iconUnitWidth: 2, iconYMod: 0}, //RB
        '8': {iconIndex: -1, iconUnitWidth: 1, iconYMod: 0}, //Select or "middle button on left"
        '9': {iconIndex: -1, iconUnitWidth: 1, iconYMod: 0}, //start or "middle button on right"
        'directions': {iconIndex: 4, iconUnitWidth: 1, iconYmod: 0} // directionPad
    }
}

//Set default keyboard map
Gimmer_Core.ControllerType.setDefaultKeyboardIndexMap = function(){
    this.KeyboardIndexMap = {
        'enter' : {iconIndex: 8, iconUnitWidth: 2, iconYMod: 48},
        'space' : {iconIndex: 11, iconUnitWidth: 3, iconYMod: 32},
        'z': {iconIndex: 5, iconUnitWidth: 1, iconYMod: 32},
        //menu / cancel
        'escape': {iconIndex: 14, iconUnitWidth: 1, iconYMod: 32},
        'insert': {iconIndex: -1, iconUnitWidth: 1, iconYMod: 32},
        'x': {iconIndex: 6, iconUnitWidth: 1, iconYMod: 32},
        'numpad0': {iconIndex: 14, iconUnitWidth: 2, iconYMod: 48},
        'shift': {iconIndex: 2, iconUnitWidth: 2, iconYMod: 48},
        //Pageup / page down
        'pageup': {iconIndex: 4, iconUnitWidth: 1, iconYMod: 48},
        'pagedown': {iconIndex: 5, iconUnitWidth: 1, iconYMod: 48},
        'q': {iconIndex: 13, iconUnitWidth: 1, iconYMod: 48},
        'w': {iconIndex: 0, iconUnitWidth: 1, iconYMod: 32},
        //directions
        'directions': {iconIndex: 1, iconUnitWidth: 2, iconYMod: 64}
    }
}


//Validate and include custom maps if provided
Gimmer_Core.ControllerType.validateGamePadIndexMap();
Gimmer_Core.ControllerType.validateKeyboardPadIndexMap();

//Constants
Gimmer_Core.ControllerType.TYPE_SONY = 'playstation';
Gimmer_Core.ControllerType.TYPE_MICROSOFT = 'xbox';
Gimmer_Core.ControllerType.TYPE_NONE = 'none';
Gimmer_Core.ControllerType.TYPE_OTHER = 'other';

//Reserve the system image at startup
ImageManager.reserveSystem('GimmerControllerIconSet');

//Extend Input to support recording last input
Input._onKeyDown = function(event) {
    if (this._shouldPreventDefault(event.keyCode)) {
        event.preventDefault();
    }
    if (event.keyCode === 144) {    // Numlock
        this.clear();
    }
    var buttonName = this.keyMapper[event.keyCode];
    if (ResourceHandler.exists() && buttonName === 'ok') {
        ResourceHandler.retry();
    } else if (buttonName) {
        this._currentState[buttonName] = true;
        this.lastInputType = 'keyboard';
    }
};

//Extend _updateGamepadState to support recording last input:
//I hate doing a full replace, but the nature of the code doesn't work for what I want to do
Input._updateGamepadState = function(gamepad) {
    var lastState = this._gamepadStates[gamepad.index] || [];
    var newState = [];
    var buttons = gamepad.buttons;
    var axes = gamepad.axes;
    var threshold = 0.5;
    newState[12] = false;
    newState[13] = false;
    newState[14] = false;
    newState[15] = false;
    for (var i = 0; i < buttons.length; i++) {
        newState[i] = buttons[i].pressed;
    }
    if (axes[1] < -threshold) {
        newState[12] = true;    // up
    } else if (axes[1] > threshold) {
        newState[13] = true;    // down
    }
    if (axes[0] < -threshold) {
        newState[14] = true;    // left
    } else if (axes[0] > threshold) {
        newState[15] = true;    // right
    }
    for (var j = 0; j < newState.length; j++) {
        if (newState[j] !== lastState[j]) {
            var buttonName = this.gamepadMapper[j];
            if (buttonName) {
                this._currentState[buttonName] = newState[j];
                if(newState[j]){
                    this.lastInputType = 'gamepad';
                }
            }
        }
    }
    this._gamepadStates[gamepad.index] = newState;
};

/**
 * The last input that went in
 *
 * @static
 * @property lastInputType
 * @type String
 */
Object.defineProperty(Input, 'lastInputType', {
    get: function() {
        return this._lastInputType;
    },
    set: function (type){
        this._lastInputType = type;
    },
    configurable: true
});


//Helper function to get the controller type as a string
Gimmer_Core.ControllerType.getControllerTypeIfPresent = function(){
    let controllerType = this.TYPE_NONE;
    if (navigator.getGamepads && Input.lastInputType === 'gamepad') {
        var gamepads = navigator.getGamepads();
        if (gamepads) {
            for (var i = 0; i < gamepads.length; i++) {
                var gamepad = gamepads[i];
                if (gamepad && gamepad.connected) {
                    controllerType = this.getControllerType(gamepad);
                }
            }
        }
    }
    return controllerType;
}

//Gets the controller type from a gamepad
Gimmer_Core.ControllerType.getControllerType = function(gamepad){
    let controllerType = this.TYPE_OTHER;
    if(gamepad.id.search(/054c|sony|PLAYSTATION/i) > -1){
        controllerType = this.TYPE_SONY;
    }
    else if(gamepad.id.search(/xbox|360|028e|045e|02d1/i) > -1){
        controllerType = this.TYPE_MICROSOFT;
    }
    return controllerType;
}

//Extend escape codes
Gimmer_Core.ControllerType._Window_Base_obtainEscapeCode = Window_Base.prototype.obtainEscapeCode;
Window_Base.prototype.obtainEscapeCode = function(textState) {
    var send = (Imported.YEP_MessageCore) ? !this._checkWordWrapMode : true;
    textState.index++;
    if(textState.text.slice(textState.index, textState.index+2).match(/ok/)) {
        textState.index += 2;
        return (send) ? "gimmer_ok" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+5).match(/shift/)) {
        textState.index += 5;
        return (send) ? "gimmer_shift" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+4).match(/menu/)) {
        textState.index += 4;
        return (send) ? "gimmer_menu" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+6).match(/system/)) {
        textState.index += 6;
        return (send) ? "gimmer_system" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+6).match(/cancel/)) {
        textState.index += 6;
        return (send) ? "gimmer_cancel" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+8).match(/pagedown/)) {
        textState.index += 8;
        return (send) ? "gimmer_pagedown" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+6).match(/pageup/)) {
        textState.index += 6;
        return (send) ? "gimmer_pageup" : "";
    }
    else if(textState.text.slice(textState.index, textState.index+10).match(/directions/)) {
        textState.index += 10;
        return (send) ? "gimmer_directions" : "";
    }
    else {
        textState.index--;
        return Gimmer_Core.ControllerType._Window_Base_obtainEscapeCode.call(this, textState);
    }
};

//Extend escape characters to find buttons
Gimmer_Core.ControllerType._Window_Base_processEscapeCharacter = Window_Base.prototype.processEscapeCharacter;
Window_Base.prototype.processEscapeCharacter = function(code, textState) {
    switch (code) {
        case 'gimmer_ok':
        case 'gimmer_cancel':
        case 'gimmer_shift':
        case 'gimmer_menu':
        case 'gimmer_pageup':
        case 'gimmer_pagedown':
        case 'gimmer_directions':
        case 'gimmer_system':
            this.processDrawButtonIcon(this.determineIconForButton(code), textState);
            break;
        default:
            Gimmer_Core.ControllerType._Window_Base_processEscapeCharacter.call(this, code, textState);
            break;
    }
};

//Find what icon a specific button should have based on the current active device
Window_Base.prototype.determineIconForButton = function(code){
    code = code.replace('gimmer_',"");
    let iconUnitWidth = 1;
    let iconYMod = 0;
    let iconIndex = -1;
    let type = Gimmer_Core.ControllerType.getControllerTypeIfPresent();
    if(type === Gimmer_Core.ControllerType.TYPE_NONE){
        let keyChoice = Gimmer_Core.ControllerType.ProvidedKeyBoardMap[code]
        if(keyChoice){
            let keyData = Gimmer_Core.ControllerType.KeyboardIndexMap[keyChoice];
            if(keyData){
                iconIndex = keyData.iconIndex;
                iconUnitWidth = keyData.iconUnitWidth;
                iconYMod = keyData.iconYMod;
            }
        }
    }
    else{
        //Figure out what button they pressed by reversing gamepadMapper into
        if(code !== 'directions'){
            let buttonObj = JSON.parse(JSON.stringify(Input.gamepadMapper));
            let reverseMap = Gimmer_Core.reverseObject(buttonObj);
            let buttonId = reverseMap[code];
            if(buttonId) {
                let keyData = Gimmer_Core.ControllerType.GamePadIndexMap[buttonId.toString()];
                iconIndex = keyData.iconIndex;
                iconUnitWidth = keyData.iconUnitWidth;
            }
        }
        else{
            let keyData = Gimmer_Core.ControllerType.GamePadIndexMap[code];
            if(keyData){
                iconIndex = keyData.iconIndex;
                iconUnitWidth = keyData.iconUnitWidth;
            }
        }

        switch (type){
            case Gimmer_Core.ControllerType.TYPE_SONY:
                iconYMod = 16;
                break;
        }
    }

    iconIndex += iconYMod;

    return {'iconIndex':iconIndex, 'iconUnitWidth': iconUnitWidth};

}

//Draw the icon in any given window using textState
Window_Base.prototype.processDrawButtonIcon = function(iconInfo, textState) {
    this.drawButtonIcon(iconInfo.iconIndex, textState.x + 2, textState.y + 2, iconInfo.iconUnitWidth);
    textState.x += (iconInfo.iconUnitWidth * Window_Base._iconWidth) + 4;
};

//Draw a button icon
Window_Base.prototype.drawButtonIcon = function(iconIndex, x, y, widthModifier) {
    var bitmap = ImageManager.loadSystem('GimmerControllerIconSet');
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = iconIndex % 16 * pw;
    pw *= widthModifier;
    var sy = Math.floor(iconIndex / 16) * ph;
    this.contents.blt(bitmap, sx, sy, pw, ph, x, y);
};

//Plugin comment to get the controller type as a string, in case you want to just display some static controls or what have you
Gimmer_Core.pluginCommands['GIMMERCONTROLLERTYPE'] = function(){
    return Gimmer_Core.ControllerType.getControllerTypeIfPresent();
}