Crown Progress Explorer

A different but simple new way to look at your progress

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

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

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Crown Progress Explorer
// @namespace    https://greasyfork.org/users/1028985
// @version      0.0
// @description  A different but simple new way to look at your progress
// @author       CMT
// @match        https://www.mousehuntgame.com/*
// @match        https://apps.facebook.com/mousehunt/*
// @icon         https://www.google.com/s2/favicons?domain=mousehuntgame.com
// ==/UserScript==

((function () {
	'use strict';
    const mouseCats = [
        {type:"Arcane",
        mice: ["Buccaneer Mouse","Hapless Marionette"]},
        {type:"Draconic",
        mice: ["Chameleon Mouse","Dragon Mouse","Dumpling Chef Mouse"]},
        {type:"Forgotten",
        mice: ["Acolyte Mouse","Balack the Banished"]},
        {type:"Hydro",
        mice: ["Aged Mouse","Briegull Mouse","Black Widow Mouse"]},
        {type:"Law",
        mice: ["Bandit Mouse","Gate Guardian Mouse","Gold Mouse"]},
        {type:"Parental",
        mice: ["Aged Mouse"]},
        {type:"Physical",
        mice: ["Abominable Snow Mouse","Bear Mouse"]},
        {type:"Rift",
        mice: ["Fairy Mouse","Fiddler Mouse","Gate Guardian Mouse"]},
        {type:"Shadow",
        mice: ["Aquos Mouse","Bionic Mouse"]},
        {type:"Tactical",
        mice: ["Alchemist Mouse","Alnilam Mouse","Assassin Mouse"]}
    ]
    let defMouseScore =
        {Arcane: 0,
        Draconic: 0,
        Forgotten: 0,
        Hydro: 0,
        Law:0,
        Parental: 0,
        Physical : 0,
        Rift: 0,
        Shadow: 0,
        Tactical:0
    }
	let defMouseTypeList = {Arcane: [],
        Draconic: [],
        Forgotten: [],
        Hydro: [],
        Law:[],
        Parental: [],
        Physical : [],
        Rift: [],
        Shadow: [],
        Tactical:[]
    }
	let mouseTypeList, mouseScore;
	/**
	 * Add styles to the page.
	 *
	 * @param {string} styles The styles to add.
	 */
	const addStyles = (styles) => {
		// Check to see if the existing element exists.
		const existingStyles = document.getElementById('mh-mouseplace-custom-styles');

		// If so, append our new styles to the existing element.
		if (existingStyles) {
			existingStyles.innerHTML += styles;
			return;
		}

		// Otherwise, create a new element and append it to the head.
		const style = document.createElement('style');
		style.id = 'cmt-styles';
		style.innerHTML = styles;
		document.head.appendChild(style);
	};
	/**
	 * POST a request to the server and return the response.
	 *
	 * @param {string} url      The url to post to, not including the base url.
	 * @param {Object} formData The form data to post.
	 *
	 * @return {Promise} The response.
	 */
	const doRequest = async (url, formData) => {
		// If we don't have the needed params, bail.
		if ('undefined' === typeof user || ! user || 'undefined' === typeof user.unique_hash || ! user.unique_hash) { // eslint-disable-line no-undef
			return;
		}

		// Build the form for the request.
		const form = new FormData();
		form.append('sn', 'Hitgrab');
		form.append('hg_is_ajax', 1);
		form.append('uh', user.unique_hash ? user.unique_hash : ''); // eslint-disable-line no-undef

		// Add in the passed in form data.
		for (const key in formData) {
			form.append(key, formData[ key ]);
		}

		// Convert the form to a URL encoded string for the body.
		const requestBody = new URLSearchParams(form).toString();

		// Send the request.
		const response = await fetch(
			callbackurl ? callbackurl + url : 'https://www.mousehuntgame.com/' + url, // eslint-disable-line no-undef
			{
				method: 'POST',
				body: requestBody,
				headers: {
					'Content-Type': 'application/x-www-form-urlencoded',
				},
			}
		);

		// Wait for the response and return it.
		const data = await response.json();
		return data;
	};

	/**
	 *  Add a submenu item to a menu.
	 *
	 * @param {Object} options The options for the submenu item.
	 */
	const addSubmenuItem = (options) => {
		// Default to sensible values.
		const settings = Object.assign({}, {
			menu: 'kingdom',
			label: '',
			icon: '',
			href: '',
			callback: null,
			external: false,
		}, options);


		// Grab the menu item we want to add the submenu to.
		const menuTarget = document.querySelector(`.mousehuntHud-menu .${ settings.menu }`);
		if (! menuTarget) {
			return;
		}

		// If the menu already has a submenu, just add the item to it.
		if (! menuTarget.classList.contains('hasChildren')) {
			menuTarget.classList.add('hasChildren');
		}

		let submenu = menuTarget.querySelector('ul');
		if (! submenu) {
			submenu = document.createElement('ul');
			menuTarget.appendChild(submenu);
		}

		// Create the item.
		const item = document.createElement('li');

		// Add in our class.
		const menuSlug = settings.label.toLowerCase().replace(/ /g, '-');
		item.classList.add(`mh-submenu-item-${ menuSlug }`);

		if (settings.icon) {
			addStyles(`.mousehuntHud-menu .mh-submenu-item-${ menuSlug } .icon { background-image: url(${ settings.icon }); }`);
		}

		// Create the link.
		const link = document.createElement('a');
		link.href = settings.href || '#';

		if (settings.callback) {
			link.addEventListener('click', (e) => {
				e.preventDefault();
				settings.callback();
			});
		}

		// Create the icon.
		const icon = document.createElement('div');
		icon.classList.add('icon');

		// Create the label.
		const name = document.createElement('div');
		name.classList.add('name');
		name.innerText = settings.label;

		// Add the icon and label to the link.
		link.appendChild(icon);
		link.appendChild(name);

		// If it's an external link, also add the icon for it.
		if (settings.external) {
			const externalLinkIcon = document.createElement('div');
			externalLinkIcon.classList.add('external_icon');
			link.appendChild(externalLinkIcon);

			// Set the target to _blank so it opens in a new tab.
			link.target = '_blank';
			link.rel = 'noopener noreferrer';
		}

		// Add the link to the item.
		item.appendChild(link);

		// Add the item to the submenu.
		submenu.appendChild(item);
	};
	/**
	 * Get the mouse stats.
	 *
	 * @return {Object} The mouse stats.
	 */
	const getMouseStats = async () => {
		const data = await doRequest(
			'managers/ajax/mice/getstat.php',
			{
				action: 'get_hunting_stats',
			}
		);

		// Grab the data from the response.
		const mouseData = data?.hunting_stats


		// Return the data.
		return mouseData ? mouseData : [];
	};

    const calculateScore = (stats) => {
		mouseScore = JSON.parse(JSON.stringify(defMouseScore));
		mouseTypeList = JSON.parse(JSON.stringify(defMouseTypeList));
        stats.forEach((mouse) => {
            mouseCats.forEach((cat) => {
                if (cat.mice.includes(mouse.name)){
					if(mouse.num_catches >= 100){
						mouseScore[cat.type] = mouseScore[cat.type] +1
					}
					mouseTypeList[cat.type].push(mouse);
                }
            })
        })
    }

    const buildScoreMarkup = (type)=>{
        for (const cat in mouseCats){
            if (mouseCats[cat].type == type){
                const typeEl = document.createElement('a');
                typeEl.classList.add('cmt-mice-stats');
                typeEl.title = type;
                // Create the image element.
                const image = document.createElement('div');
                image.classList.add('cmt-mice-stats-image');
                image.style.backgroundImage = `url('https://www.mousehuntgame.com/images/powertypes/${type.toLowerCase()}.png')`;
                // Create the name element.
                const name = document.createElement('div');
                name.classList.add('cmt-mice-stats-name');
                name.innerText = type;
                // Create a wrapper for the name and image.
                const imageNameContainer = document.createElement('div');
                imageNameContainer.appendChild(image);
                imageNameContainer.appendChild(name);
				// Create a flat element
				const flat = document.createElement('div');
				flat.classList.add('cmt-mice-stats-catches');
                let flatnumber = mouseScore[type] + " / " + (mouseCats[cat]["mice"].length);
				flat.innerText = flatnumber;
                // Create the percentage element.
                const percentage = document.createElement('div');
                percentage.classList.add('cmt-mice-stats-catches');
                let number = (100*mouseScore[type]/(mouseCats[cat]["mice"].length)).toFixed(3);
                percentage.innerText = number + "%";
                // Add the image and name to the type element.
                typeEl.appendChild(imageNameContainer);
				typeEl.appendChild(flat);
                typeEl.appendChild(percentage);


                // console.log(100*mouseScore[type]/(mouseCats[cat]["mice"].length))
                return typeEl;

            }
        }
    }
    	/**
	 * Show the stat modal.
	 */
	const showModal = async () => {
		// First, check to make sure we have the element we want to append to.
		const target = document.querySelector('.pageFrameView-content');
		if (! target) {
			return;
		}

		// Remove the existing modal.
		const existing = document.getElementById('cmt-mice-stats');
		if (existing) {
			existing.remove();
		}

		// Create the modal.
		const modalWrapper = document.createElement('div');
		modalWrapper.id = 'cmt-mice-stats';

		// Create the wrapper.
		const modal = document.createElement('div');
		modal.classList.add('cmt-mice-stats-wrapper');

		// Create the header.
		const header = document.createElement('div');
		header.classList.add('cmt-mice-stats-header');

		// Add the title;
		const title = document.createElement('h1');
		title.innerText = 'Mouse Catch Stats';
		header.appendChild(title);

		// Create a close button icon.
		const closeIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
		closeIcon.classList.add('cmt-mice-stats-close');
		closeIcon.setAttribute('viewBox', '0 0 24 24');
		closeIcon.setAttribute('width', '18');
		closeIcon.setAttribute('height', '18');
		closeIcon.setAttribute('fill', 'none');
		closeIcon.setAttribute('stroke', 'currentColor');
		closeIcon.setAttribute('stroke-width', '1.5');

		// Create the path.
		const closePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
		closePath.setAttribute('d', 'M18 6L6 18M6 6l12 12');
		closeIcon.appendChild(closePath);

		// Close the modal when the icon is clicked.
		closeIcon.addEventListener('click', () => {
			modalWrapper.remove();
		});

		// Append the button.
		header.appendChild(closeIcon);

		// Add the header to the modal.
		modal.appendChild(header);
//-----
		// Make the mouse stats table.
		const mouseBody = document.createElement('div');
		mouseBody.classList.add('cmt-mice-stats-body');
		// TODO: add column headers
		const mouseHeaders = document.createElement('div');
		mouseHeaders.classList.add('cmt-mice-stats');
		const mouseImageHeader = document.createElement('div');
		const mouseNameHeader = document.createElement('div');
		const mouseFlatHeader = document.createElement('div');
		const mousePercentHeader = document.createElement('div');
		mouseImageHeader.innerText = "____";
		mouseNameHeader.innerText = "Name";
		mouseFlatHeader.innerText = "Flat score";
		mousePercentHeader.innerText = "percentage score";
		mouseHeaders.appendChild(mouseImageHeader);
		mouseHeaders.appendChild(mouseNameHeader);
		mouseHeaders.appendChild(mouseFlatHeader);
		mouseHeaders.appendChild(mousePercentHeader);
		modal.appendChild(mouseHeaders);
		// Get the mouse stats.
		const mouseStats = await getMouseStats();

		// Loop through the stats and add them to the modal.
		calculateScore(mouseStats);
        for (const score in mouseScore){
			let result = buildScoreMarkup(score);
			result.addEventListener('click', () => {
				generateTypeDetails(score);
			});
			mouseBody.appendChild(result);

        }

		// Add the mouse stats to the modal.
		modal.appendChild(mouseBody);

		// Add the modal to the wrapper.
		modalWrapper.appendChild(modal);

		// Add the wrapper to the body.
		target.appendChild(modalWrapper);
	};
	const generateTypeDetails = async (score) => {
		// First, check to make sure we have the element we want to append to.
		const target = document.querySelector('.pageFrameView-content');
		if (! target) {
			return;
		}
		// Remove the existing modal.
		const existing = document.getElementById('cmt-type-details');
		if (existing) {
			existing.remove();
		}
		// Create the modal.
		const modalWrapper = document.createElement('div');
		modalWrapper.id = 'cmt-type-details';


		// Create the wrapper.
		const modal = document.createElement('div');
		modal.classList.add('cmt-type-details-wrapper');

		// Create the header.
		const header = document.createElement('div');
		header.classList.add('cmt-mice-stats-header');

		// Add the title;
		const title = document.createElement('h1');
		title.innerText = score + ' details';
		header.appendChild(title);

		// Create a close button icon.
		const closeIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
		closeIcon.classList.add('cmt-mice-stats-close');
		closeIcon.setAttribute('viewBox', '0 0 24 24');
		closeIcon.setAttribute('width', '18');
		closeIcon.setAttribute('height', '18');
		closeIcon.setAttribute('fill', 'none');
		closeIcon.setAttribute('stroke', 'currentColor');
		closeIcon.setAttribute('stroke-width', '1.5');

		// Create the path.
		const closePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
		closePath.setAttribute('d', 'M18 6L6 18M6 6l12 12');
		closeIcon.appendChild(closePath);

		// Close the modal when the icon is clicked.
		closeIcon.addEventListener('click', () => {
			modalWrapper.remove();
		});

		// Append the button.
		header.appendChild(closeIcon);

		// Add the header to the modal.
		modal.appendChild(header);

		const mouseBody = document.createElement('div');
		mouseBody.classList.add('cmt-type-details-body');

		for (let mouse in mouseTypeList[score]){
			const mouseEl = document.createElement('a');
			mouseEl.classList.add('cmt-mice-stats');

			//Create the image element
			const image = document.createElement('div');
			image.classList.add('cmt-mice-stats-image');
			image.style.backgroundImage = `url('${ mouseTypeList[score][mouse].thumb }')`;

			// Create the name element.
			const name = document.createElement('div');
			name.classList.add('cmt-mice-stats-name');
			name.innerText = mouseTypeList[score][mouse].name;

			// Create a wrapper for the name and image.
			const imageNameContainer = document.createElement('div');
			imageNameContainer.appendChild(image);
			imageNameContainer.appendChild(name);

			// Create the catches element.
			const catches = document.createElement('div');
			catches.classList.add('cmt-mice-stats-catches');
			catches.innerText = mouseTypeList[score][mouse].num_catches;

			// Add the image and name to the mouse element.
			mouseEl.appendChild(imageNameContainer);
			mouseEl.appendChild(catches);
			mouseBody.appendChild(mouseEl)

		}
		modal.appendChild(mouseBody);

		// Add the modal to the wrapper.
		modalWrapper.appendChild(modal);
		// TODO: add it somewhere properly 
		// Add the wrapper to the body.
		target.appendChild(modalWrapper);

		console.log(mouseTypeList[score]);
	}

    addStyles(`#cmt-mice-stats, #cmt-type-details {
        position: absolute;
        top: 10px;
        left: -275px;
    }

    .cmt-mice-stats-wrapper, .cmt-type-details-wrapper {
		z-index: 5000;
        position: fixed;
        width: 450px;
        background: #f6f3eb;
        border: 1px solid #534022;
        box-shadow: 1px 1px 1px 0px #9d917f;
    }

    .cmt-mice-stats-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 1px solid #ceb7a6;
        background-color: #926944;
        padding: 10px;
        color: #f6f3eb;
    }

    .cmt-mice-stats-header h1 {
        color: #f6f3eb;
    }

    .cmt-mice-stats-close:hover {
        background-color: #ceb7a6;
        border-radius: 50%;
        cursor: pointer;
    }

    .cmt-mice-stats-body {
        max-height: 90vh;
        overflow-y: scroll;
        overflow-x: hidden;
    }

    .cmt-mice-stats-wrapper .cmt-mice-stats:nth-child(odd) {
        background-color: #e8e3d7;
    }

    .cmt-mice-stats, .cmt-type-details {
        display: flex;
        justify-content: space-between;
        padding: 2px 0;
        align-items: center;
        padding: 10px 10px;
        color: #000;
    }

    .cmt-mice-stats:hover, .cmt-type-details:hover,
    .cmt-mice-stats-wrapper .cmt-mice-stats:nth-child(odd):hover {
        outline: 1px solid #ccc;
        background-color: #eee;
        text-decoration: none;
    }

    .cmt-mice-stats-image {
        position: relative;
        width: 40px;
        height: 40px;
        display: inline-block;
        vertical-align: middle;
        background-size: contain;
        background-repeat: no-repeat;
        border-radius: 2px;
        box-shadow: 1px 1px 1px #999;
    }

    .cmt-mice-stats-crown {
        position: absolute;
        right: -5px;
        bottom: -5px;
        width: 20px;
        height: 20px;
        background-repeat: no-repeat;
        background-position: 50% 50%;
        background-color: #fff;
        border: 1px solid #333;
        background-size: 80%;
        border-radius: 50%;
    }

    .cmt-mice-stats-name {
        display: inline-block;
        vertical-align: middle;
        padding-left: 10px;
    }

    .cmt-mice-stats-catches {
        padding-right: 5px;
    }`);

    addSubmenuItem({
        menu: 'mice',
        label: 'Mouse Catch Stats',
        icon: 'https://www.mousehuntgame.com/images/ui/hud/menu/prize_shoppe.png',
        callback: showModal
    });
})());