GC Games Optimizer

Tells you what game to play next so you can maximize your earnings from HTML5 games on GC.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         GC Games Optimizer
// @namespace    https://greasyfork.org/en/users/1175371/
// @version      0.8
// @description  Tells you what game to play next so you can maximize your earnings from HTML5 games on GC.
// @author       sanjix
// @match        https://www.grundos.cafe/games/html5/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=grundos.cafe
// @grant        none
// @license 	 MIT
// ==/UserScript==

var head = document.querySelector('head');
head.innerHTML+= `<style>
#calcOptions {
  display: flex;
  flex-flow: column;
}

.recommendation {
  margin: 1em 0;
  display: block;
  width: max-content;
}

label {
  padding: 5px;
}

#exclusions, #favorites {
  display: flex;
  flex-flow: column;
  flex-wrap: wrap;
  height: 300px;
  overflow-y: scroll;
  border: 1px solid black;
  margin: 1em;
  width: 580px;

}

#exclusions label:first-child, #favorites label:first-child {
  display: block;
  font-weight: 800;
}

.topEarners a {
  display: block;
}

.featured:before, .featured:after {
  content: '***';
}
.featured {
  background-color: #0099ff50;
}
</style>`;

var games = [
{
	'name': 'Extreme Herder',
	'ratio': 71,
	'min_score': 1,
	'item_score': 85,
	'theoretical_max_score': 12920,
	'uri': 'extremeherder',
    'isPrecise': true,
    'topEarner': true
},
{
	'name': 'Ultimate Bullseye',
	'ratio': 50,
	'min_score': 1,
	'item_score': 40,
	'theoretical_max_score': 850,
	'uri': 'bullseye',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Faerie Cloud Racers',
	'ratio': 5.1,
	'min_score': 29,
	'item_score': 625,
	'theoretical_max_score': 3205,
	'uri': 'faeriecloudracers',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Advert Attack',
	'ratio': 6.5,
	'min_score': 2,
	'item_score': 500,
	'theoretical_max_score': 911,
	'uri': 'advertattack',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Carnival of Terror',
	'ratio': 8.5,
	'min_score': 2,
	'item_score': 350,
	'theoretical_max_score': 1031,
	'uri':  'carnivalofterror',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Meepit Juice Break',
	'ratio': 4.65,
	'min_score': 1,
	'item_score': 900,
	'theoretical_max_score': 9676,
	'uri': 'meepitjuicebreak',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Meerca Chase II',
	'ratio': 4.4,
	'min_score': 3,
	'item_score': 400,
	'theoretical_max_score': 4986,
	'uri': 'meercachase',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Faerie Bubbles',
	'ratio': 5,
	'min_score': 3,
	'item_score': 400,
	'theoretical_max_score': 2727,
	'uri': 'faeriebubbles',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Jelly Blobs of Doom',
	'ratio': 5.8,
	'min_score': 11,
	'item_score': 375,
	'theoretical_max_score': 24466,
	'uri': 'jellyblobs',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Dubloon Disaster',
	'ratio': 3.45,
	'min_score': 10,
	'item_score': 540,
	'theoretical_max_score': 35165,
	'uri': 'dubloondisaster',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Volcano Run',
	'ratio': 3.5,
	'min_score': 20,
	'item_score': 1650,
	'theoretical_max_score': 17940,
	'uri': 'volcanorun',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Destruct-O-Match II',
	'ratio': 5.15,
	'min_score': 2,
	'item_score': 1150,
	'theoretical_max_score': 12022,
	'uri': 'destructomatch',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Korbats Lab',
	'ratio': 5.95,
	'min_score': 10,
	'item_score': 450,
	'theoretical_max_score': 12410,
	'uri': 'korbatslab',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Suteks Tomb',
	'ratio': 6,
	'min_score': 1,
	'item_score': 800,
	'theoretical_max_score': 222276,
	'uri': 'sutekstomb',
    'isPrecise': true,
    'topEarner': true
},
{
	'name': 'Ice Cream Machine',
	'ratio': 3.1,
	'min_score': 5,
	'item_score': 2400,
	'theoretical_max_score': 23405,
	'uri': 'icecreammachine',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Escape from Meridell Castle',
	'ratio': 27,
	'min_score': 1,
	'item_score': 65,
	'theoretical_max_score': 4059,
	'uri': 'castleescape',
    'isPrecise': true,
    'topEarner': true
},
{
	'name': 'Attack of the Revenge',
	'ratio': 8,
	'min_score': 2,
	'item_score': 250,
	'theoretical_max_score': 3636,
	'uri': 'attackoftherevenge',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Zurroball',
	'ratio': 11,
	'min_score': 1,
	'item_score': 150,
	'theoretical_max_score': 221842,
	'uri': 'zurroball',
    'isPrecise': true,
    'topEarner': true
},
{
	'name': 'Usuki Frenzy',
	'ratio': 5.5,
	'min_score': 15,
	'item_score': 350,
	'theoretical_max_score': 640,
	'uri': 'usukifrenzy',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Revel Roundup',
	'ratio': 40,
	'min_score': 2,
	'item_score': 100,
	'theoretical_max_score': 249,
	'uri': 'revelroundup',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Igloo Garage Sale - The Game',
	'ratio': 10.7,
	'min_score': 1,
	'item_score': 500,
	'theoretical_max_score': 3145,
	'uri': 'garagesale',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Splat-A-Sloth',
	'ratio': 3,
	'min_score': 176,
	'item_score': 1500,
	'theoretical_max_score': 3930,
	'uri': 'splatasloth',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'GC Staff Smasher',
	'ratio': 7,
	'min_score': 1,
	'item_score': 813,
	'theoretical_max_score': 2771,
	'uri': 'staffsmasher',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'TNT Staff Smasher',
	'ratio': 5,
	'min_score': 1,
	'item_score': 800,
	'theoretical_max_score': 3170,
	'uri': 'tntstaffsmasher',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Web of Vernax',
	'ratio': 4.5,
	'min_score': 2,
	'item_score': 850,
	'theoretical_max_score': 6141,
	'uri': 'webofvernax',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'The Buzzer Game',
	'ratio': 175,
	'min_score': 20,
	'item_score': 50,
	'theoretical_max_score': 825,
	'uri': 'buzzergame',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Hasee Bounce',
	'ratio': 65,
	'min_score': 1,
	'item_score': 50,
	'theoretical_max_score': 586,
	'uri': 'haseebounce',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Pterattack',
	'ratio': 5.2,
	'min_score': 5,
	'item_score': 700,
	'theoretical_max_score': 17645,
	'uri': 'pterattack',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Hannah and the Pirate Caves',
	'ratio': 0.44,
	'min_score': 42000,
	'item_score': 15,
	'theoretical_max_score': 458800,
	'uri': 'piratecaves',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Turmac Roll',
	'ratio': 5.5,
	'min_score': 8,
	'item_score': 600,
	'theoretical_max_score': 25795,
	'uri': 'turmacroll',
    'isPrecise': false,
    'topEarner': false
},
{
	'name': 'Kass Basher',
	'ratio': 5.5,
	'min_score': 8,
	'item_score': 850,
	'theoretical_max_score': 1766,
	'uri': 'kassbasher',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Swarm - The Bugs Strike Back',
	'ratio': 26,
	'min_score': 3,
	'item_score': 300,
	'theoretical_max_score': 4785,
	'uri': 'swarm',
    'isPrecise': false,
    'topEarner': true
},
{
	'name': 'Jubble Bubble',
	'ratio': 3,
	'min_score': 5,
	'item_score': 750,
	'theoretical_max_score': 6975,
	'uri': 'jubblebubble',
    'isPrecise': true,
    'topEarner': true
},
{
	'name': 'Magma Blaster',
	'ratio': 11.5,
	'min_score': 2,
	'item_score': 250,
	'theoretical_max_score': 1062,
	'uri': 'magmablaster',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Snowmuncher',
	'ratio': 6.5,
	'min_score': 9,
	'item_score': 950,
	'theoretical_max_score': 11064,
	'uri': 'snowmuncher',
    'isPrecise': true,
    'topEarner': false
},
{
	'name': 'Neverending Boss Battle',
	'ratio': 7.2,
	'min_score': 5,
	'item_score': 900,
	'theoretical_max_score': 39675,
	'uri': 'bossbattle',
    'isPrecise': false,
    'topEarner': false
}
];
games.sort((a,b) => {
	const nameA = a.name;
	const nameB = b.name;
	if (nameA < nameB) {
		return -1;
	}
	if (nameA > nameB) {
		return 1;
	}
	return 0;
});

var gamesInfo = document.querySelector('.games-info');
var calculatorOptions = document.createElement('form');
calculatorOptions.action = 'javascript:void(0);';
calculatorOptions.target = '_self';
calculatorOptions.id = 'calcOptions';

var featuredLabel = document.createElement('label');
featuredLabel.setAttribute('for', 'featured');
featuredLabel.textContent = 'Featured Game:';
var featuredDropdown = document.createElement('select');
featuredDropdown.id = 'featured';
featuredDropdown.form = 'calcOptions';

var itemsLabel = document.createElement('label');
itemsLabel.setAttribute('for', 'items');
itemsLabel.textContent = 'Game for Items:';
var itemsDropdown = document.createElement('select');
itemsDropdown.form = 'calcOptions';
itemsDropdown.id = 'items';

var favoritesDiv = document.createElement('div');
favoritesDiv.id = 'favorites';
var favoritesLabel = document.createElement('label');
favoritesLabel.setAttribute('for', 'exclusions');
favoritesLabel.append('Prefer:');
favoritesDiv.appendChild(favoritesLabel);
games.forEach((game) => {
	var featuredOptions = document.createElement('option');
	featuredOptions.value = game.name;
	featuredOptions.textContent = game.name;

	var itemsOptions = document.createElement('option');
	itemsOptions.value = game.name;
	itemsOptions.textContent = game.name;
	featuredDropdown.add(featuredOptions);
	itemsDropdown.add(itemsOptions);

	var checkboxItem = document.createElement('input');
	var checkboxLabel = document.createElement('label');
	checkboxItem.setAttribute('type', 'checkbox');
	checkboxItem.setAttribute('name', 'fave');
	checkboxItem.setAttribute('muptliple', '');
	checkboxItem.setAttribute('id', 'fave-' + game.name);
	checkboxItem.setAttribute('value', game.name);

	checkboxLabel.setAttribute('for', 'fave-' + game.name);
	checkboxLabel.appendChild(checkboxItem);
	checkboxLabel.append(game.name);

	favoritesDiv.appendChild(checkboxLabel);
});

var exclusionsDiv = document.createElement('div');
exclusionsDiv.id = 'exclusions';
var exclusionsLabel = document.createElement('label');
exclusionsLabel.setAttribute('for', 'exclusions');
exclusionsLabel.append('Exclude:');
exclusionsDiv.appendChild(exclusionsLabel);
games.forEach((game) => {
	var featuredOptions = document.createElement('option');
	featuredOptions.value = game.name;
	featuredOptions.textContent = game.name;

	var itemsOptions = document.createElement('option');
	itemsOptions.value = game.name;
	itemsOptions.textContent = game.name;
	featuredDropdown.add(featuredOptions);
	itemsDropdown.add(itemsOptions);

	var checkboxItem = document.createElement('input');
	var checkboxLabel = document.createElement('label');
	checkboxItem.setAttribute('type', 'checkbox');
	checkboxItem.setAttribute('name', 'exclude');
	checkboxItem.setAttribute('muptliple', '');
	checkboxItem.setAttribute('id', 'excl-' + game.name);
	checkboxItem.setAttribute('value', game.name);

	checkboxLabel.setAttribute('for', 'excl-' + game.name);
	checkboxLabel.appendChild(checkboxItem);
	checkboxLabel.append(game.name);

	exclusionsDiv.appendChild(checkboxLabel);
});

calculatorOptions.appendChild(featuredLabel);
calculatorOptions.appendChild(featuredDropdown);
calculatorOptions.appendChild(itemsLabel);
calculatorOptions.appendChild(itemsDropdown);
calculatorOptions.appendChild(favoritesDiv);
calculatorOptions.appendChild(exclusionsDiv);
var submitSettings = document.createElement('button');
submitSettings.textContent = 'Update Calculator';
submitSettings.target = "_self";
calculatorOptions.appendChild(submitSettings);
// console.log('mb?');
gamesInfo.after(calculatorOptions);
let recommendation = document.createElement('a');
recommendation.classList = 'recommendation';
// console.log('plz');

function removeCommas(score) {
	return score.replace(',', '');
}

function findNextGame(form) {
	var exclusions = form.getAll('exclude');
	var favorites = form.getAll('fave');
	var currentNP = form.get('score');
	var featured = form.get('featured');
	var npTheoMax = parseInt(removeCommas(document.querySelector('.games-info #np_earned ~ strong').textContent));
	// var isCS = formData.get('cs');
	var npToEarn = npTheoMax - currentNP;

	function isFeatured(game) {
		return game.name == form.get('featured');
	}

	function findMultiplier(game) {
		if (npTheoMax == 60000) {
			return 1;
		} else if (npTheoMax == 120000 && isFeatured(game)) {
			return 3;
		} else if (npTheoMax == 120000 || isFeatured(game)) {
			return 2;
		}
	}

	function pointsToEarn(game) {
		// console.log(Math.floor((npTheoMax - currentNP)/game.ratio));
		return Math.floor(npToEarn/(game.ratio/findMultiplier(game)));
	}

	function isPossible(game) {
		console.log(game.name, pointsToEarn(game), game.min_score);
		// console.log(pointsToEarn(game) >= game.min_score);
		return pointsToEarn(game) >= game.min_score && pointsToEarn(game);
	}

	function isAchievable(game) {
		return npToEarn % game.ratio == 0 && pointsToEarn(game) % game.min_score == 0 && game.isPrecise;
	}

	function isEasyMath() {
		console.log(npToEarn);
		return npToEarn % 5 == 0 || npToEarn % 10 == 0;
	}

	let itemsEarned = parseInt(document.querySelector('.games-info #items_earned').textContent);
	let itemsMax = parseInt(document.querySelector('.games-info #items_earned ~ strong').textContent);

	let gameCandidate;
    console.log(itemsEarned, itemsMax);
    console.log(favorites);
    console.log(exclusions);
    if (npToEarn == 0) {
        return undefined;
    } else if (itemsEarned < itemsMax) {
		return 'items';
	} else { //items already earned
		if (favorites != undefined) { //check if preferred games playable

			let faves = games.filter((game) => (favorites.includes(game.name)));
            console.log(faves);
			for (let i = 0; i < faves.length; i++) {
				if (isPossible(faves[i])) {
					if ((gameCandidate == undefined) || (pointsToEarn(faves[i]) < pointsToEarn(gameCandidate))) {
						gameCandidate = faves[i];
					}
				}
			}
		}
		if (gameCandidate != undefined) {
			return gameCandidate;
		} else if (isEasyMath()) { //check if easy math option
				return games.find((game) => game.name == 'TNT Staff Smasher');
			}


//check remaining games (minus exclusions)
		let minusExclGames = games.filter((game) => !(exclusions.includes(game.name)));

		for (let i = 0; i < minusExclGames.length; i++) {
			console.log(minusExclGames[i].name, npToEarn, minusExclGames[i].ratio);
			console.log(isPossible(minusExclGames[i]));
			console.log(npToEarn % minusExclGames[i].ratio == 0);
			if (npToEarn % minusExclGames[i].ratio == 0) {
				if (isPossible(minusExclGames[i]) && isAchievable(minusExclGames[i])) {
					return minusExclGames[i];
				}
			} else if (pointsToEarn(minusExclGames[i]) > 0 && isPossible(minusExclGames[i])) {
					if ((gameCandidate == undefined) || (pointsToEarn(minusExclGames[i]) < pointsToEarn(gameCandidate))) {
						gameCandidate = minusExclGames[i]
					}
				}
			}

			return gameCandidate;
		}
	}

calculatorOptions.addEventListener('submit', (event) => {
	event.preventDefault();
	// console.log('hello world');
	//var settings = event.formData;
    var score = parseInt(removeCommas(document.querySelector('.games-info #np_earned').textContent));
	let formData = new FormData(calculatorOptions);
	var feat = document.querySelector('#featured').selectedOptions[0].value;
	var items = document.querySelector('#items').selectedOptions[0].value;
	formData.append('featured', feat);
	formData.append('items', items);
	formData.append('score', score);

	console.log(formData);

	//current game page
	var thisGame = document.querySelector('h1').textContent;

	//check for compsci
	var npTheoMax = parseInt(removeCommas(document.querySelector('.games-info #np_earned ~ strong').textContent));
    var multiplier = 1;
	var npPracMax = 120000;
	switch (npTheoMax) {
		case 120000:
			npPracMax+= 120000;
            multiplier = 2;
            break;
		case 60000:
			npPracMax += 60000;
		break;
	}

	let next = findNextGame(formData);
	if (thisGame == feat && next == thisGame) {

        npPracMax += 60000;
        if (multiplier == 2) {
            multiplier = 3
        } else {
            multiplier = 2
        }
        console.log(multiplier);
	}
	if (next == 'items') {
		recommendation.innerHTML = `You should play ` + items + ` next! Earn your daily items!`;
		recommendation.href = `https://grundos.cafe/games/html5/` + games.find(game => game.name == items.valueOf()).uri;

	} else if (next === undefined) {
		recommendation.innerHTML = `Go for broke! You've earned as much as possible.`;
        var chooseYourFighter = document.createElement('div');
        chooseYourFighter.classList = 'topEarners';
        games.filter((game) => game.topEarner).forEach((game) => {
            chooseYourFighter.innerHTML += `<a target="_blank"` + (game.name == feat ? `class= "featured" ` : ``) + `href="https://grundos.cafe/games/html5/` + game.uri + `">` + game.name + `</a>`;
        });


	} else {
		recommendation.innerHTML = `You should play ` + next.name + ` next! Earn ` + Math.floor((npTheoMax - score)/next.ratio/multiplier) + ` point(s), then calculate again.`;
		recommendation.href = `https://grundos.cafe/games/html5/` + next.uri;

		console.log(next.name);
	}
	recommendation.target = '_blank';
	calculatorOptions.after(recommendation);
	if (chooseYourFighter) {
	    recommendation.after(chooseYourFighter);
	}

});