Complete Your Set - Steam Forum Trading Helper

Automatically detects missing cards from a card set, help you auto-fill New Trading Thread input areas

目前為 2018-05-30 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Complete Your Set - Steam Forum Trading Helper
// @icon         https://store.steampowered.com/favicon.ico
// @namespace    https://github.com/tkhquang
// @version      0.8
// @description  Automatically detects missing cards from a card set, help you auto-fill New Trading Thread input areas
// @author       Aleks
// @license      MIT; https://raw.githubusercontent.com/tkhquang/userscripts/master/LICENSE
// @homepage     https://greasyfork.org/en/scripts/368518-complete-your-set-steam-forum-trading-helper/
// @match        *://steamcommunity.com/*/*/gamecards/*
// @match        *://steamcommunity.com/app/*/tradingforum/*
// @match        *://steamcommunity.com/app/*/tradingforum
// @run-at       document-idle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// ==/UserScript==

var tradeTag = 2;
//1 = #Number of Set in Title
//2 = Card Name in Title
//Default is 2
var tradeMode = 0;
//0 - List both Owned and Unonwed Cards
//1 - Only List Owned Cards
//2 - Only List Unowned Cards
//Default is 0
var badgeMode = 1;
//0 - Don't check for number of cards to full set, this is more like a cards lister
//1 - Only check for game set that you have enough cards to make it full
//2 - Complete your remaining set
//Default is 1
var badgeNumSet = 0;
//0 - Don't set a target number of Card Sets
//Others - Set a target number for Card Sets - This will also set 'badgeMode = 2'
//Default is 0
var useLocalStorage = false;
//Use HTML5 Local Storage instead, set this to true if you're using Greasemonkey
//Default is false
var customBody = "\n[1:1] Trading";
var customTitle = " [1:1]";
var haveListText = "[H]\n";
var wantListText = "[W]\n";
var haveListTextTitle = "[H] ";
var wantListTextTitle = "[W] ";

//Codes

var CYSstorage = {};

var replaceOwned = new Map([
    [/\s{2,}/g, " "],
    [/\s(\d+)\ of \d+\, Series \d+\s$/, "=.=$1"],
    [/^\s\((\d+)\)\s/, "$1=.="]
]);
var replaceUnowned = new Map([
    [/\s{2,}/g, " "],
    [/\s(\d+)\ of \d+\, Series \d+\s$/, "=.=$1"],
    [/^\s/, "0=.="]
]);
function clean(str, replacements) {
    replacements.forEach(function(value, key){
        str = str.replace(key, value);
    });
    return str;
}

function getOwnedCards() {
    let ownedCards = document.querySelectorAll(".badge_card_set_card.owned");
    let owned = [];
    for (let i=0; i < ownedCards.length; i++) {
        owned[i] = clean(ownedCards[i].textContent,replaceOwned);
        owned[i] = owned[i].split("=.=");
    }
    //console.log(owned);
    return owned;
}

function getUnownedCards() {
    let unownedCards = document.querySelectorAll(".badge_card_set_card.unowned");
    let unowned = [];
    for (let i=0; i < unownedCards.length; i++) {
        unowned[i] = clean(unownedCards[i].textContent,replaceUnowned);
        unowned[i] = unowned[i].split("=.=");
    }
    //console.log(unowned);
    return unowned;
}

function sort(arr, index) {
    let sort = [];
    sort = Array(arr.length).fill().map((v,i)=>i+1);
    arr = arr.map(function(item) {
        var n = sort.indexOf(Number(item[index]));
        sort[n] = "";
        return [n, item];
    }).sort().map(function(j) {
        return j[1];
    });
    return arr;
}

var allCards = [];
function getAllCards() {
    let ulallCards = getOwnedCards().concat(getUnownedCards());
    allCards = sort(ulallCards, 2);
    getTotal();
    //console.log(allCards);
}

var totalCards = [];
var total = 0;
function getTotal() {
    for (let i=0; i < allCards.length; i++) {
        let curCard = allCards[i];
        totalCards.push(curCard[0]);
        total += Number(totalCards[i]);
    }
    //console.log(totalCards);
    console.log("Number of cards you've owned: " + total);
    badgeCheck();
}

var badgeNum;
function badgeCheck() {
    if (badgeNumSet !== 0) {
        badgeMode = 2;
        badgeNum = badgeNumSet;
        console.log("Target Set :"+badgeNumSet);
    }
    else {
        switch(badgeMode) {
            case 0:
                badgeNum = 0;
                break;
            case 1:
                badgeNum = Math.floor(total / allCards.length);
                console.log("Your cards are enough to craft " + badgeNum + " badge(s)");
                break;
            case 2:
                var remainSet = (total / allCards.length !== 1) ? true : false;
                if (remainSet === true) {
                    badgeNum = Math.floor(total / allCards.length + 1);
                    console.log("You need some cards to complete your remaining set\nTotal: "+badgeNum);
                }
                if (remainSet === false) {
                    badgeNum = Math.floor(total / allCards.length);
                }
                break;
        }
    }
    function tradeNeed(value) {
        let tradeCheck = false;
        for (let i=0; i < allCards.length; i++) {
            if (totalCards[i] < badgeNum) {
                tradeCheck = true;
                break;
            }
        }
        return tradeCheck === value;
    }
    if (badgeMode !==0 && tradeNeed(false)) {
        console.log("You don't need to do trading for now");
        return;
    }
    console.log("You can visit trading forum to complete your sets");
    calcTrade();
}

var haveList = [];
var wantList = [];
function calcTrade() {
    let dupCards;
    let needCards;
    for (let i=0; i < allCards.length; i++) {
        if (totalCards[i] > badgeNum) {
            let curCard = allCards[i];
            dupCards = (badgeMode === 0) ? Number(totalCards[i]) : totalCards[i] - badgeNum;
            haveList.push([
                dupCards,
                curCard[2],
                curCard[1]
            ]);
        }
        if ((totalCards[i] < badgeNum)||(badgeMode===0&&totalCards[i]==badgeNum)) {
            let curCard = allCards[i];
            needCards = (badgeMode === 0) ? Number(totalCards[i]) : badgeNum - totalCards[i];
            wantList.push([
                needCards,
                curCard[2],
                curCard[1]
            ]);
        }
    }
    //console.log(haveList); console.log(wantList);
    createText();
}

function createText() {
    for (let i=0; i < haveList.length; i++) {
        if (tradeMode !== 2 && haveList.length > 0) {
            let dup = haveList[i];
            haveListText += dup[1] + " - " + dup[2] + " - x" + dup[0] + "\n";
            haveListTextTitle += dup[tradeTag] + " (x" + dup[0] + "), ";
        }
    }
    for (let i=0; i < wantList.length; i++) {
        if (tradeMode !== 1 && wantList.length > 0) {
            let need = wantList[i];
            wantListText += need[1] + " - " + need[2] + " - x" + need[0] + "\n";
            wantListTextTitle += need[tradeTag] + " (x" + need[0] + "), ";
        }
    }
    haveListTextTitle = haveListTextTitle.replace(/\), $/, ") ");
    wantListTextTitle = wantListTextTitle.replace(/\), $/, ")");
    let CYStext = JSON.stringify([
        haveListText+"\n"+wantListText,
        haveListTextTitle + wantListTextTitle,
        window.location.pathname.split("/")[4],
        Date.now()
    ]);
    CYSstorage.storageSet(CYStext);
    createButton();
}

function inTrade() {
    if (document.querySelector(".btn_darkblue_white_innerfade.btn_medium.responsive_OnClickDismissMenu") === null) {
        console.log("CYS - Something is wrong, have you logged in?");
        return;
    }
    document.querySelector(".btn_darkblue_white_innerfade.btn_medium.responsive_OnClickDismissMenu").click();
    document.querySelector(".forumtopic_reply_textarea").textContent = CYSstorage.storageItem(0) + customBody;
    document.querySelector(".forum_topic_input").value = CYSstorage.storageItem(1) + customTitle;
    setTimeout(function(){
        CYSstorage.storageClear();
    }, 1000);
}

function createButton() {
    var a = document.createElement("a");
    a.className = "btn_grey_grey btn_medium";
    a.href = "https://steamcommunity.com/app/"+window.location.pathname.split("/")[4]+"/tradingforum/";
    a.innerHTML = "<span>Visit Trading Forum</span>";
    document.querySelector(".gamecards_inventorylink").appendChild(a);
}

var numChecks = [
    !(Number.isInteger(badgeNumSet)&&badgeNumSet>=0),
    [1,2].indexOf(tradeTag)==-1,
    [0,1,2].indexOf(tradeMode)==-1,
    [0,1,2].indexOf(badgeMode)==-1,
    typeof(useLocalStorage)!=="boolean"
], GMChecks = [
    typeof GM_setValue!=="undefined",
    typeof GM_getValue!=="undefined",
    typeof GM_deleteValue!=="undefined"
];
function configCheck(condi,value) {
    return condi.some(function(config) {
        return config === value;
    });
}

function getStorage(mode) {
    let storageItem,storageInv,storageClear,storageSet;
    if (!mode) {
        storageInv = function() {
            return ((GM_getValue("CYS-STORAGE"))&&(GM_getValue("CYS-STORAGE").length>0)) ? true : false;
        };
        storageItem = function(index) {
            return JSON.parse(GM_getValue("CYS-STORAGE"))[index];
        };
        storageClear = function() {
            GM_deleteValue("CYS-STORAGE");
            console.log("CYS - GM Storage Cleared");
        };
        storageSet = function(content) {
            GM_setValue("CYS-STORAGE", content);
        };
    }
    if (mode) {
        storageInv = function() {
            return ((window.localStorage.cardTrade)&&(window.localStorage.cardTrade.length>0)) ? true : false;
        };
        storageItem = function(index) {
            return JSON.parse(localStorage.cardTrade)[index];
        };
        storageClear = function() {
            window.localStorage.removeItem("cardTrade");
            console.log("CYS - Local Storage Cleared");
        };
        storageSet = function(content) {
            window.localStorage.cardTrade = content;
        };
    }
    return {storageInv,storageItem,storageClear,storageSet};
}

(function() {
    "use strict";

    if (configCheck(numChecks,true)) {
        alert("CYS - Invalid Config Settings\nPlease Check Again!");
        return;
    } else if ((!useLocalStorage)&&configCheck(GMChecks,false)) {
        useLocalStorage=true;
        console.log("CYS - GM functions are not defined - Switch to use HTML5 Local Storage instead");
    }
    CYSstorage = getStorage(useLocalStorage);
    if (/\/gamecards/.test(window.location.pathname)) {
        if (document.querySelector(".gamecards_inventorylink") === null) {
            console.log("Not your profile?");
            return;
        } else if (CYSstorage.storageInv()) {
            CYSstorage.storageClear();
        }
        getAllCards();
    }
    if (/\/tradingforum/.test(window.location.pathname)) {
        if (!CYSstorage.storageInv()) {
            console.log("CYS - No Stored Trade Info In Storage");
            return;
        } else if ((new RegExp(CYSstorage.storageItem(2))).test(window.location.pathname)) {
            let storedTime = Date.now() - CYSstorage.storageItem(3);
            console.log("CYS - Time: "+storedTime+"ms");
            if (storedTime>21600000) {
                if (window.confirm("CYS - It's been more than 6 hours since you checked your cards\n" +
                                   "It's better to check again\n"+
                                   "Press OK to go to your GameCard Page")) {
                    window.open("https://steamcommunity.com/my/gamecards/"+CYSstorage.storageItem(2),"_blank");
                    return;
                }
            }
            setTimeout(inTrade,1000);
        }
    }
})();