GC - Quest Reward Stat Collector

Collects reward and the items requested from quests to put into a shared spreadsheet for stats. https://docs.google.com/spreadsheets/d/17lADRhz5POPYPxKRa6ZVYlJuKuYxxev0_bxnFPbK0Bk/edit?gid=1499161972#gid=1499161972

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         GC - Quest Reward Stat Collector
// @namespace    https://greasyfork.org/en/users/1202961-twiggies
// @version      1.92
// @description  Collects reward and the items requested from quests to put into a shared spreadsheet for stats. https://docs.google.com/spreadsheets/d/17lADRhz5POPYPxKRa6ZVYlJuKuYxxev0_bxnFPbK0Bk/edit?gid=1499161972#gid=1499161972
// @author       Twiggies
// @match        https://www.grundos.cafe/winter/snowfaerie/complete/
// @match        https://www.grundos.cafe/halloween/witchtower/complete/
// @match        https://www.grundos.cafe/halloween/esophagor/complete/
// @match        https://www.grundos.cafe/island/kitchen/complete/
// @match        https://www.grundos.cafe/halloween/braintree/complete/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=grundos.cafe
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

let giveUsername = GM_getValue("sendUsername");

//This function asks if you want your username to be sent or not.
function usernamePrompt() {
    if (window.confirm("Would you like to send your username with your quest data? Press OK for Yes, or cancel for No.\nThis can be prompted again in the script extension's menu.")) {
        GM_setValue("sendUsername",true);
        giveUsername = true;
    }
    else {
        GM_setValue("sendUsername",false);
        giveUsername = false;
    }
}

//Adds the prompt for asking about username sending to the menu.
const usernameMenuCommand = GM_registerMenuCommand("Set Send Username", function() {
  usernamePrompt();
}, "u");


if (giveUsername == undefined) {
    usernamePrompt();
}

let formLink = '';
let returnButton = null;
let submitDiv = document.createElement("div");
submitDiv.innerHTML = "Submitting Quest Data...";
submitDiv.id = "submitDiv";

function taeliaRewards() {
    let rewardSpan = document.querySelector('div.center > div.flex-column.big-gap > span');
    if (rewardSpan == undefined) {
        return '';
    }
    let rewardText = rewardSpan.innerText;
    console.log(`Text: ${rewardText}`)
    //If text does not start with 'Taelia gives you a' then LEAVE.
    if (rewardText.startsWith('Taelia gives you a ') == false) {
        return '';
    }
    returnButton = document.querySelector('input.form-control[type="button"][value="Approach Taelia again..."]');
    returnButton.disabled = true;
    rewardSpan.insertAdjacentElement('afterend', submitDiv)
    //Taelia rewards should always be in the following format:
    //"Taelia gives you a Crazy Crisp Taco, Poison Snowball, and 17,983 Neopoints!!"
    //so "Taelia gives you a [Item], [SnowballItem], and [NP] Neopoints!!"
    //We need to figure out a way to split these out. Unfortunately, items can sometimes have commas in them (none of the items Taelia can reward atm does, but I want to future proof it), so we can't just split by comma.

    //I think I can work backwards instead. I know how to get the Neopoints...
    let neopoints = Number(rewardText.match(/(?! )\d*,?\d+(?= Neopoints!!)/)[0].replaceAll(',',''))
    console.log(`Neopoints: ${neopoints}`)
    //Now we get rid of the neopoints section.
    rewardText = rewardText.replace(/, and \d*,?\d+ Neopoints!!/g,'');
    console.log(`Text 2: ${rewardText}`)

    let snowBallItem = rewardText.match(/((?=, ).+ Snowball)|(, Snow \w*ball)|(, Frozen Pile of Dung)/gi)[0].trim();
    //Remove the , from the start if it's there.
    if (snowBallItem.startsWith(', ')) {
        snowBallItem = snowBallItem.slice(2).trim();
    }
    snowBallItem = encodeURIComponent(snowBallItem);
    console.log(`Snowball: ${snowBallItem}`)
    //Now get rid of the snowball section... Hoping it doesn't add a snowball that has a ', ' in it. Or a snowball that doesn't end in snowball.
    rewardText = rewardText.replace(/((?=, ).+ Snowball)|(, Snow \w*ball)|(, Frozen Pile of Dung)/gi,'')
    console.log(`Text 3: ${rewardText}`)

    //Now get the ice cream machine coupon item
    let couponItem = rewardText.match(/((?=, ).+ Ice Cream Machine Coupon)/gi);
    if (couponItem != null) {
        couponItem = couponItem[0].trim()
        //Remove the , from the start if it's there.
        if (couponItem.startsWith(', ')) {
            couponItem = couponItem.slice(2).trim();
        }
        couponItem = encodeURIComponent(couponItem);
        console.log(`Coupon: ${couponItem}`)
        //Now get rid of the coupon section...
        rewardText = rewardText.replace(/((?=, ).+ Ice Cream Machine Coupon)/gi,'')
        console.log(`Text 4: ${rewardText}`)
    }


    //Now for the last item. We just need to remove the beginning part... and we're good!
    let item1 = encodeURIComponent(rewardText.replace('Taelia gives you a ','').trim());
    console.log(`Item: ${item1}`)
    return `https://docs.google.com/forms/d/e/1FAIpQLSd426f2LiLlDYPnvGnIt-IUOB5tfvnNjNfIujx0V_sQROGtYw/formResponse?usp=pp_url&entry.1167335245=Taelia&entry.1736384931=${neopoints}&entry.1829837696=${item1}&entry.558379744=${snowBallItem}` + (couponItem != null ? `&entry.1082355197=${couponItem}` : '')
}

function ednaRewards() {
    const npRewardSpan = document.querySelector('div#quest_grid ~span');
    const itemRewardSpan = document.querySelector('div#quest_grid ~span ~span')
    if (npRewardSpan == undefined || itemRewardSpan == undefined) {
        return '';
    }
    let npRewardText = npRewardSpan.innerText;
    console.log(`npRewardText: ${npRewardText}`)
    let itemRewardText = itemRewardSpan.innerText;
    if (npRewardText.startsWith('Yes! I have all the ingredients!') == false || itemRewardText.startsWith('The old witch gives you ') == false) {
        return '';
    }
    returnButton = document.querySelector('input.form-control[type="button"][value="Approach the witch again..."]');
    returnButton.disabled = true;
    itemRewardSpan.insertAdjacentElement('afterend', submitDiv)
    //Extract the neopoints out of the text.
    let neopoints = Number(npRewardText.match(/\d+,+\d*(?!NP!)/gi)[0].replaceAll(',',''));
    console.log(`Neopoints: ${neopoints}`)
    //Extract the items... Edna reward text can come in two forms:
    // "The old witch gives you Spooky Lime Pudding !!"
    // And if she also rewards a second item:
    //"The old witch gives you Spooky Lime Pudding and Bottled Earth Faerie!!"
    // So if she gives a second item, it'll always be a bottled faerie, I'm pretty sure. So this will be based on that since there's probably lots of items with 'and' in the name.

    //So first, let's remove the starting text that'll always be there.
    itemRewardText = itemRewardText.replace("The old witch gives you ",'');
    //And then remove the two !! at the end. Just twim two chars off the end.
    itemRewardText = itemRewardText.slice(0, -2).trim()
    console.log(`itemRewardText: ${itemRewardText}`)

    //If there is ' and Bottled [x] Faerie',  we want to split that out. If there's no extra faerie item it'll just be null.
    let faerieText = itemRewardText.match(/(?! and )Bottled .+ Faerie/g);
    console.log(`faerieText: ${faerieText}`);
    //We'll now remove the faerie text ,if it's there.
    itemRewardText = encodeURIComponent(itemRewardText.replace(/ and Bottled .+ Faerie/g,'').trim())
    console.log(`itemRewardText2: ${itemRewardText}`)
    let url = `https://docs.google.com/forms/d/e/1FAIpQLSd426f2LiLlDYPnvGnIt-IUOB5tfvnNjNfIujx0V_sQROGtYw/formResponse?usp=pp_url&entry.1167335245=Edna&entry.1736384931=${neopoints}&entry.1829837696=${itemRewardText}`
    if (faerieText != null) {
        url = url + `&entry.558379744=${encodeURIComponent(faerieText[0])}`
    }
    return url;
}

function esoRewards() {
    let itemRewardSpan = document.querySelector('div.center > div.flex-column.big-gap > span');
    if (itemRewardSpan == undefined) {
        return '';
    }
    let itemRewardText = itemRewardSpan.innerText;
    console.log(`Text: ${itemRewardText}`)
    //If text does not start with 'The Esophagor gives you ' then LEAVE.
    if (itemRewardText.startsWith('The Esophagor gives you ') == false) {
        return '';
    }
    let neopointRewardSpan = itemRewardSpan.nextElementSibling;
    let neopointRewardText = neopointRewardSpan.innerText;
    returnButton = document.querySelector('input.form-control[type="button"][value="Approach the Esophagor again..."]');
    returnButton.disabled = true;
    neopointRewardSpan.insertAdjacentElement('afterend', submitDiv)
    //Eso rewards will be in the following format:
    //Item: "The Esophagor gives you Roast Tentacle!!"
    //NP: "He also drops 9,360 NP; you pocket it quickly!"
    let neopoints = Number(neopointRewardText.match(/(?! )\d*,?\d+(?= NP;)/g)[0].replaceAll(',',''))
    console.log(`Neopoints: ${neopoints}`)
    //Get rid of the static text and clip of the !! at the end.
    itemRewardText = encodeURIComponent(itemRewardText.replace('The Esophagor gives you ','').slice(0, -2).trim());
    console.log(`Text 2: ${itemRewardText}`)

    return `https://docs.google.com/forms/d/e/1FAIpQLSd426f2LiLlDYPnvGnIt-IUOB5tfvnNjNfIujx0V_sQROGtYw/formResponse?usp=pp_url&entry.1167335245=Esophagor&entry.1736384931=${neopoints}&entry.1829837696=${itemRewardText}`
}

function kitchenRewards() {
    const rewardConfirmationSpan = document.querySelector('div#quest_grid ~span ~span')
    if (rewardConfirmationSpan == undefined) {
        return '';
    }
    //If text does not start with 'The Esophagor gives you ' then LEAVE.
    if (rewardConfirmationSpan.innerText.startsWith('The Chef waves his hands, and you may collect your prize...') == false) {
        return '';
    }
    returnButton = document.querySelector('input.form-control[type="button"][value="Approach the Chef Again"]');
    returnButton.disabled = true;
    //Look for the active pet, this is so we can check if it got a stat boost.
    const activePet = document.querySelector('#userinfo a[href*="/quickref/"]').innerText.trim();

    //Because the kitchen quest can have a few possible different formats of rewards, we'll loop through each element after the reward confirmation and do stuff based on that.
    let statBoost = '';
    let itemReward = '';
    let neopoints = '';

    let url = 'https://docs.google.com/forms/d/e/1FAIpQLSd426f2LiLlDYPnvGnIt-IUOB5tfvnNjNfIujx0V_sQROGtYw/formResponse?usp=pp_url&entry.1167335245=Kitchen'
    //Get the next element.
    let nextElement = rewardConfirmationSpan.nextElementSibling;
    while (nextElement != null && !(nextElement.tagName == "DIV" && nextElement.childElementCount == 2 && nextElement.classList.contains('half-width'))){
        //If it is a stat boost...
        if (nextElement.innerText.startsWith(`${activePet} gained `)) {
            statBoost = nextElement.innerText.match(/ of .+/g)[0].replace(' of ','').trim();
            url += '&entry.2021892051=' + statBoost
        }
        //If it is an item...
        else if (nextElement.innerText.startsWith('You get ')) {
            itemReward = encodeURIComponent(nextElement.innerText.replace('You get ','').slice(0,-2).trim());
            url += '&entry.1829837696=' + itemReward;
        }
        //If it's codestones...
        else if (nextElement.innerText.includes('a sack of codestones')) {
            url += '&entry.558379744=Codestones'
        }
        //If it's neopoints...
        else if (nextElement.innerText.startsWith('You also get ')) {
            neopoints = Number(nextElement.innerText.match(/(?! )\d*,?\d+(?= Neopoints!)/)[0].replaceAll(',',''))
            url += '&entry.1736384931=' + neopoints
        }
        nextElement = nextElement.nextElementSibling;
    }
    nextElement.insertAdjacentElement('beforebegin', submitDiv)
    return url;
}

function brainTreeRewards() {
    const wholeElement = document.querySelector('div.flex-column.big-gap')
    if (wholeElement == undefined || wholeElement.innerText.startsWith('Thank you, you are correct!') == false) {
        return '';
    }
    returnButton = document.querySelector('input.form-control[type="button"][value="Return to Haunted Woods"]');
    returnButton.disabled = true;
    let itemElement = wholeElement.children[3];

    itemElement.insertAdjacentElement('afterend', submitDiv)
    let itemReward = itemElement.innerText.slice(0,-2);
    return `https://docs.google.com/forms/d/e/1FAIpQLSd426f2LiLlDYPnvGnIt-IUOB5tfvnNjNfIujx0V_sQROGtYw/formResponse?usp=pp_url&entry.1167335245=Brain+Tree&entry.1829837696=${itemReward}`
}

//Only run if no quest items are NO. So exit if there's a single NO.
let noNo = false;
const itemList = document.querySelectorAll('.quest-text strong:nth-child(2)')
//ALso get the items that were requested.
let itemsRequested = {item0:"",item1:"",item2:"",item3:""}

//Loop through each quest item to check if already got.
for (let i = 0; i < itemList.length; i++) {
    if (itemList[i].innerText === "NO") {
        noNo = true;
        break;
    }
    else {
        itemsRequested['item'+i] = itemList[i].previousElementSibling.innerText;
    }
}


//If all the items have been gotten then the quest is done, so continue.
if (noNo == false) {
    if (window.location.href == 'https://www.grundos.cafe/winter/snowfaerie/complete/') {
        formLink = taeliaRewards();
    }
    else if (window.location.href == 'https://www.grundos.cafe/halloween/witchtower/complete/') {
        formLink = ednaRewards();
    }
    else if (window.location.href == 'https://www.grundos.cafe/halloween/esophagor/complete/') {
        formLink = esoRewards();
    }
    else if (window.location.href == 'https://www.grundos.cafe/island/kitchen/complete/') {
        formLink = kitchenRewards();
    }
    else if (window.location.href == 'https://www.grundos.cafe/halloween/braintree/complete/') {
        formLink = brainTreeRewards();
    }

    if (formLink != '') {
        if (giveUsername) {
            formLink += '&entry.1732136035=' + document.querySelector('#userinfo a[href*="userlookup/?user="]').innerText.trim();
        }
        //Add the requested quest items.
        if (itemsRequested.item0 != "") {
            formLink += '&entry.669064702=' + itemsRequested.item0;
        }
        if (itemsRequested.item1 != "") {
            formLink += '&entry.1797043340=' + itemsRequested.item1;
        }
        if (itemsRequested.item2 != "") {
            formLink += '&entry.1426587972=' + itemsRequested.item2;
        }
        if (itemsRequested.item3 != "") {
            formLink += '&entry.1031263455=' + itemsRequested.item3;
        }

        let opts = {
            mode: "no-cors",
            //redirect: "follow",
            referrer: "no-referrer",
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            }
        }

        let response = fetch(formLink, opts)
        .then(response => {
            // handle the response
            console.log("Quest Data Submitted");
            submitDiv.innerHTML = '<a href="https://docs.google.com/spreadsheets/d/17lADRhz5POPYPxKRa6ZVYlJuKuYxxev0_bxnFPbK0Bk/edit?gid=1499161972#gid=1499161972" style="color:green; text-decoration: underline">Quest Data Submitted!</a>';
            returnButton.disabled = false;
        })
        .catch(error => {
            // handle the error
            console.log("Error: " + error);
            console.log(response)
            returnButton.disabled = false;
            submitDiv.innerHTML = `Failed to submit quest data: ${error}`;
            submitDiv.style.color = "red"
        });

    }
}