您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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
// ==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" }); } }