Fallen London - Dressing Room - Chrome

Script for storing and changing into outfits.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Fallen London - Dressing Room - Chrome
// @namespace   fallenlondon/dressingroom
// @description Script for storing and changing into outfits.
// @author      Travers
// @include     http://*fallenlondon.com/Gap/Load*
// @include     http://fallenlondon.storynexus.com/Gap/Load*
// @version     1.41
// @grant       none
// ==/UserScript==
var DB_NAME = 'Dressing Room for ';
var DB_STORE_NAME = 'outfits';
var DB_VERSION = 1;
var DEBUG = false;
var outfitMode = {add: 1, change: 2, changing: 3}

var db = null;
var onMeTab = false;
var itemsOwned = Object.create(null);
var outfit;
var record;

setUpObservers();

function debugLog(msg)
{
    if (DEBUG)
    {
        console.log('Fallen London - Dressing Room: ', msg);
    }
}
function debugDir(obj)
{
    if (DEBUG)
    {
        console.dir(obj);
    }
}

function setUpObservers()
{
    var target = document.querySelector('#meTab');
    var peeper = new MutationObserver(checkMeOut);
    peeper.observe(target, {attributes: true, childList: false, characterData: false});

    target = document.querySelector('#mainContentLoading');
    peeper = new MutationObserver(checkOutMyLoad);
    peeper.observe(target, {attributes: true, childList: false, characterData: false});
}

function checkMeOut(mutants, observer)
{
    onMeTab = mutants[0].target.getAttribute(mutants[0].attributeName) == 'selected';
    
    if (!db)
    {
        openDatabase();
    }
}

function openDatabase()
{
    var username = document.getElementsByClassName('subscription-username')[0].innerHTML;
    
    if (username.length < 1) 
    { 
        debugLog('openDatabase - username error');
        return;
    }
    
    DB_NAME += username;

    var req = window.indexedDB.open(DB_NAME, DB_VERSION);
    req.onsuccess = function(evt)
    {
        db = this.result;
        db.onerror = function(evt) 
        {
            console.error('Fallen London Dressing Room - DB - error: ', evt.target.errorCode);
        }
        debugLog('openDatabase - completed');
    };
    req.onerror = function(evt)
    {
        console.error('Fallen London Dressing Room - openDatabase - error: ', evt.target.errorCode);
    };
    req.onupgradeneeded = function(evt)
    {
        debugLog('openDatabase - setting up database store');
        var store = evt.currentTarget.result.createObjectStore(DB_STORE_NAME, {keyPath: 'Name'});
    };
}

function checkOutMyLoad(mutants, observer)
{
    if (onMeTab)
    {
        var DR = document.getElementById('dressing-room');
        if (DR == null)
        {
            var target = document.getElementsByClassName('redesign_heading')[0];

            var newA = document.createElement('A');
            newA.className = 'standard_btn label';
            newA.style.position = 'absolute';
            newA.style.right = '1em';
            newA.style.top = '1em';
            newA.innerHTML = 'DRESSING ROOM';
            newA.addEventListener('click', function(){toggleVisibility('dressing-room');});
            target.appendChild(newA);
            
            var newDiv = document.createElement('DIV');
            newDiv.id = 'dressing-room';
            newDiv.style.zIndex = '50';
            newDiv.style.position = 'absolute';
            newDiv.style.right = '1em';
            newDiv.style.padding = '8px 12px';
            newDiv.style.border = '3px solid #736448';
            newDiv.style.color = '#000000';
            newDiv.style.background = '#b8a98c none repeat scroll 0 0';
            newDiv.style.boxShadow = '0 2px 8px #000000';
            newDiv.style.fontSize = '15px';
            newDiv.style.height = 'auto !important';
            newDiv.style.width = 'auto !important';
            newDiv.style.textTransform = 'none';
            newDiv.style.visibility = 'hidden';

            var newP = document.createElement('P');
            var newText = document.createTextNode('What to wear? ');
            newP.style.fontWeight = 'bold';
            newP.appendChild(newText);
            
            newP.appendChild(document.createElement('BR'));

            var newSelect = document.createElement('SELECT');
            newSelect.id = 'outfit-name';
            newSelect.style.fontWeight = 'bold';
            newSelect.style.width = '15em';
            newP.appendChild(newSelect);

            newText = document.createTextNode(' ');
            newP.appendChild(newText);
            
            var newButton = document.createElement('BUTTON');
            newButton.style.backgroundColor = '#ffcc00';
            newText = document.createTextNode('Change');
            newButton.style.fontWeight = 'bold';
            newButton.style.padding = '0px 5px';
            newButton.style.border = '3px solid #ffee00';
            newButton.appendChild(newText);
            newButton.addEventListener('click', function() { manageOutfit(outfitMode.change); });
            newP.appendChild(newButton);
            
            newP.appendChild(document.createTextNode(' '));

            var newButton = document.createElement('BUTTON');
            newButton.style.backgroundColor = '#f440f6';
            newText = document.createTextNode('Forget');
            newButton.style.fontWeight = 'bold';
            newButton.style.padding = '0px 5px';
            newButton.style.border = '3px solid #ff50ff';
            newButton.appendChild(newText);
            newButton.addEventListener('click', deleteOutfit);
            newP.appendChild(newButton);

            newDiv.appendChild(newP);

            newP = document.createElement('P');
            newText = document.createTextNode('What am I wearing? ');
            newP.style.fontWeight = 'bold';
            newP.appendChild(newText);
            
            newP.appendChild(document.createElement('BR'));
            
            var newInput = document.createElement('INPUT');
            newInput.type = 'text';
            newInput.id = 'new-outfit-name';
            newInput.style.fontWeight = 'bold';
            newInput.style.padding = '0px 5px';
            newInput.style.width = '15em';
            newP.appendChild(newInput);

            newText = document.createTextNode(' ');
            newP.appendChild(newText);

            newButton = document.createElement('BUTTON');
            newButton.style.backgroundColor = '#ffcc00';
            newText = document.createTextNode('Remember');
            newButton.style.fontWeight = 'bold';
            newButton.style.padding = '0px 5px';
            newButton.style.border = '3px solid #ffee00';
            newButton.appendChild(newText);
            newButton.addEventListener('click', function() { manageOutfit(outfitMode.add); });
            newP.appendChild(newButton);

            newDiv.appendChild(newP);
            
            target.appendChild(newDiv);
            
            buildOptions();
            
            target = document.getElementsByTagName('body')[0];
            newDiv = document.createElement('DIV');
            newDiv.id = 'dressing-room-changing-dialog';
            newDiv.innerHTML = 'Donning my';
            newDiv.style.zIndex = '100';
            newDiv.style.position = 'absolute';
            newDiv.style.margin = 'auto';
            newDiv.style.top = '0'; 
            newDiv.style.left = '0'; 
            newDiv.style.bottom = '0'; 
            newDiv.style.right = '0';
            newDiv.style.width = '400px';
            newDiv.style.height = '80px';
            newDiv.style.lineHeight ='80px';  
            newDiv.style.textAlign = 'center';
            newDiv.style.verticalAlign = 'middle';
            newDiv.style.padding = '5px 5px';
            newDiv.style.border = '3px solid #736448';
            newDiv.style.color = '#000000';
            newDiv.style.background = '#b8a98c none repeat scroll 0 0';
            newDiv.style.boxShadow = '0 2px 8px #000000';
            newDiv.style.fontSize = '20px';
            newDiv.style.textTransform = 'none';
            newDiv.style.visibility = 'hidden';
            target.appendChild(newDiv); 
        }
    }
}

function buildOptions()
{
    if (db)
    {
        var store = db.transaction(DB_STORE_NAME).objectStore(DB_STORE_NAME);
        
        var optionsList = [];
        store.openCursor().onsuccess = function(evt)
        {
            var cursor = evt.target.result;
            if (cursor)
            {
                optionsList.push(cursor.value.Name);
                cursor.continue();
            }
            else displayOptions(optionsList);
        }
    }
}

function displayOptions(optionsList)
{
    var ONS = document.getElementById('outfit-name');

    while (ONS.firstChild)
    {
        ONS.removeChild(ONS.firstChild);
    }

    var newOption = document.createElement('OPTION');
    ONS.appendChild(newOption);
        
    optionsList.sort(function(a, b) {
        var nameA=a.toLowerCase(), nameB=b.toLowerCase();
        if (nameA < nameB) return -1;
        if (nameA > nameB) return 1;
        return 0; 
    });
        
    for (var i = 0; i < optionsList.length; i++)
    {
        newOption = document.createElement('OPTION');
        newOption.style.backgroundColor = (i % 2) ? '#cccccc' : '#aaaaaa';
        newOption.innerHTML = optionsList[i];
        ONS.appendChild(newOption);
    }
}

function toggleVisibility(elemID)
{
    var element = document.getElementById(elemID);
    element.style.visibility = element.style.visibility == 'hidden' ? 'visible' : 'hidden';
}

function addOutfit()
{
    if (outfit.Name == '')
    {
        updateOutfit();
        return;
    }
    
    var transaction = db.transaction([DB_STORE_NAME], 'readwrite');
    var store = transaction.objectStore(DB_STORE_NAME);
    var req = store.add(outfit);
    req.onsuccess = function(evt)
    {
        debugLog('addOutfit - added');
    };
    
    buildOptions();
}

function updateOutfit()
{
    outfit.Name = document.getElementById('outfit-name').value;
    
    if (outfit.Name == '')
    {
        return;
    }
    
    var store = db.transaction([DB_STORE_NAME], 'readwrite').objectStore(DB_STORE_NAME);
    
    var req = store.get(outfit.Name);
    req.onsuccess = function(evt)
    {
        record = req.result;
        for (var attrName in outfit) { record[attrName] = outfit[attrName]; }

        var reqUpdate = store.put(record);
        reqUpdate.onsuccess = function(evt)
        {
            debugLog('updateOutfit - updated');
        };
    };
}

function deleteOutfit()
{
    var outfitName = document.getElementById('outfit-name').value;
    
    if (outfitName == '')
    {
        return;
    }
    
    var transaction = db.transaction([DB_STORE_NAME], 'readwrite');
    var store = transaction.objectStore(DB_STORE_NAME);
    var req = store.delete(outfitName);
    req.onsuccess = function(evt)
    {
        debugLog('deleteOutfit - deleted');
    };

    buildOptions();
}

function changeOutfit()
{
    var outfitName = document.getElementById('outfit-name').value;
    
    var transaction = db.transaction([DB_STORE_NAME], 'readonly');
    var store = transaction.objectStore(DB_STORE_NAME);
    var req = store.get(outfitName);
    req.onsuccess = function(evt)
    {
        record = req.result;
        
        debugLog('changeOutfit');
        debugDir(record);
                      
        var slots = ['Hat', 'Clothing', 'Gloves', 'Weapon', 'Boots', 'Companion', 'Affiliation', 'Transportation', 'HomeComfort'];   
        for (var i = 0; i < slots.length; i++)
        {
            var slot = slots[i];
            if (record[slot] != outfit[slot])
            {
                if (record[slot] != '-' && record[slot] in itemsOwned)
                {
                    adoptThing(record[slot], slot);
                }
                else if (outfit[slot] != '-')
                {
                    unadoptThing(outfit[slot], slot);
                    record[slot] = '-';
                } 
            }  
        }         
   
        setTimeout(function(){manageOutfit(outfitMode.changing);}, 1000);
    }
}

function changingOutfit()
{
    var slots = ['Hat', 'Clothing', 'Gloves', 'Weapon', 'Boots', 'Companion', 'Affiliation', 'Transportation', 'HomeComfort'];  
    for (var i = 0; i < slots.length; i++)
    {
        var slot = slots[i];
        if (record[slot] != outfit[slot])
        {
            setTimeout(function(){manageOutfit(outfitMode.changing);}, 1500);
            debugLog(slot + ' : ' + record[slot] + ' != ' + outfit[slot]);
            return;
        }
    }

    toggleVisibility('dressing-room-changing-dialog');
}

function waitForElement(selector, time, mode) 
{
    if(document.querySelector(selector) != null) 
    {
        manageOutfit2(mode, selector);        
    }
    else 
    {
        setTimeout(function() {waitForElement(selector, time, mode);}, time);
    }
}

function manageOutfit(mode)
{
    if (mode == outfitMode.change)
    {
        var dlg = document.getElementById('dressing-room-changing-dialog');
        var outfitName = document.getElementById('outfit-name').value;
        dlg.innerHTML = 'Donning <strong>' + outfitName + '</strong>';
        toggleVisibility('dressing-room-changing-dialog');
    }
    
    var expandedPage = document.getElementById('InvCat-Affiliation');

    outfit = getCurrentItems(expandedPage);
    
    outfit.Name = document.getElementById('new-outfit-name').value;
    document.getElementById('new-outfit-name').value = '';
    
    swapYouFrames();
    
    if (expandedPage)
    {           
        waitForElement('#InvCat-Hat', 1000, mode);
    }
    else 
    {
        waitForElement('#InvCat-Affiliation', 1000, mode);
    }       
}

function manageOutfit2(mode, selector)
{   
    var expandedPage = selector == '#InvCat-Affiliation' ? true : false;
    var outfit2 = getCurrentItems(expandedPage);

    for (var attrName in outfit2) { outfit[attrName] = outfit2[attrName]; } 
            
    swapYouFrames();  
    
    if (mode == outfitMode.add)
    {
        addOutfit();
    }
    else if (mode == outfitMode.change)
    {
        changeOutfit();
    }
    else if (mode == outfitMode.changing)
    {
        changingOutfit();
    }
}

function getCurrentItems(expandedPage)
{
    if (expandedPage)
    {
        return {
            Affiliation: getItemNum('Affiliation'),
            Transportation: getItemNum('Transportation'),
            HomeComfort: getItemNum('HomeComfort')
        };
    }

    return {
        Hat: getItemNum('Hat'),
        Clothing: getItemNum('Clothing'),
        Gloves: getItemNum('Gloves'),
        Weapon: getItemNum('Weapon'),
        Boots: getItemNum('Boots'),
        Companion: getItemNum('Companion')
    };   
}

function getItemNum(category)
{
    var inventoryDiv = document.getElementById('InvCat-' + category);
    targetItemNum = '-';
    
    if (inventoryDiv)
    {
        var aList = inventoryDiv.getElementsByTagName('A');
        for (var j = 0; j < aList.length; j++)
        {
            if (aList[j].hasAttribute('onclick'))
            {
                var onClickEventString = aList[j].getAttribute('onclick');
                if (onClickEventString.startsWith('unadoptThing') || onClickEventString.startsWith('adoptThing'))
                {
                    var num = onClickEventString.slice(onClickEventString.indexOf('(') + 1, onClickEventString.indexOf(','));
                    if (!isNaN(Number(num)))
                    {
                        itemsOwned[num] = true;
                        if (onClickEventString.startsWith('unadoptThing'))
                        {
                            targetItemNum = num;
                        }
                    }
                    else
                    {
                        debugLog('Fallen London - Dressing Room: getItemNum - result was not a number: ' + num);
                    }
                }
            }
        }
    }
    return targetItemNum;
}