Krypto The SuperPet

Creates a new super pet

// ==UserScript==
// @name        Krypto The SuperPet
// @description Creates a new super pet
// @match       https://*.melvoridle.com/*
// @exclude     https://wiki.melvoridle.com/*
// @version     2.1.0
// @namespace https://greasyfork.org/users/946097
// ==/UserScript==

(() => {
	const load = () => {
		const isGameLoaded = (window.isLoaded && !window.currentlyCatchingUp) ||
		(typeof unsafeWindow !== 'undefined' && unsafeWindow.isLoaded && !unsafeWindow.currentlyCatchingUp);

		if (!isGameLoaded) {
			setTimeout(load, 50);
			return;
		}

		inject();
	}
	
	const main = () => {
		var createPetInLog = function(pet){
			const petContainer = document.getElementById('petlog-container').children[0];

			//Create the div container
			var div = document.createElement('div');
			div.id = "LR-Krypto";
			div.classList.add('monster-item', 'no-bg', 'btn-light', 'pointer-enabled', 'm-1', 'justify-vertical-center');

			//Create the image
			var img = document.createElement('img');
			img.id = "LR-kryptoPet";
			img.src = pet.media;
			img.metadata_for_pet = pet;

			img.classList.add('combat-enemy-img-sm', 'p-2');
			img.onclick = function(e){
				var metadata = document.getElementById(e.srcElement.id).metadata_for_pet;
				unlockPet(parseInt(metadata.location));
			};

			//Add the image to the container
			div.appendChild(img);

			//Add the div container to the pet container
			petContainer.appendChild(div);
		};

		var formatHelper = function(valToFormat, type, sign){
			var formattedVal = "";

			//Handle the formatting of the value itself
			if(valToFormat && type){
				if(type === "per"){
					formattedVal = valToFormat.toString() + "%"
				}
				else if(type === "ms"){
					var msToS = Math.round(valToFormat/1000*1000)/1000;
					formattedVal = msToS.toString() + " seconds";
				}
				else{
					formattedVal = valToFormat.toString();
				}
			}
			
			//Handle the sign
			if(sign){
				formattedVal = sign + formattedVal;
			}

			return formattedVal;
		};
		
		var formatter = function(valArray){
			//Start empty
			var formattedVal = "";

			//Handle the different types of values
			if(valArray){
				var val;
				var type = valArray[1];
				var sign = valArray[2];
				if(valArray[0] !== null && Array.isArray(valArray[0])){
					val = valArray[0][1];
					formattedVal = formatHelper(val, type, sign);
				}
				else if(valArray[0] !== null){
					val = valArray[0];
					formattedVal = formatHelper(val, type, sign);
				}    
			}

			return formattedVal;
		};
		
		//Format
		// [expectedValue, type, sign] - handled types (per(%), ms(ms), num())
		// for arrays <key> is the property/title, expectedValue is the value
		var mods = {
			"skills" : {
				"title" : "Skill Modifiers",
				"decreasedSkillIntervalPercent" : {
					"Runecrafting Interval" : [[Skills.Runecrafting, 100], "per", "-"],
					"Woodcutting Interval" : [[Skills.Woodcutting, 120], "per", "-"],
					"Firemaking Interval" : [[Skills.Firemaking, 100], "per", "-"],
					"Fletching Interval" : [[Skills.Fletching, 100], "per", "-"],
					"Summoning Interval" : [[Skills.Summoning, 100], "per", "-"],
					"Astrology Interval" : [[Skills.Astrology, 100], "per", "-"],
					"Smithing Interval" : [[Skills.Smithing, 100], "per", "-"],
					"Thieving Interval" : [[Skills.Thieving, 100], "per", "-"],
					"Crafting Interval" : [[Skills.Crafting, 100], "per", "-"],
					"Herblore Interval" : [[Skills.Herblore, 100], "per", "-"],
					"Fishing Interval" : [[Skills.Fishing, 120], "per", "-"],
					"Cooking Interval" : [[Skills.Cooking, 100], "per", "-"],
					"Agility Interval" : [[Skills.Agility, 100], "per", "-"],
					"Mining Interval" : [[Skills.Mining, 130], "per", "-"],
					"Magic Interval" : [[Skills.Magic, 100], "per", "-"]
				}
			},
			"player" : {
				"title" : "Player Modifiers",
				//XP
				"increasedGlobalSkillXP" : {
					"title" : "Global Skill XP",
					"values" : [100, "per", "+"]
				},
				"increasedGlobalMasteryXP" : {
					"title" : "Global Mastery XP",
					"values" : [100, "per", "+"]
				},
				//Preservation
				"increasedGlobalPreservationChance" : {
					"title" : "Global Preservation",
					"values" : [100, "per", "+"]
				},
				"increasedAmmoPreservation" : {
					"title" : "Ammo Preservation",
					"values" : [100, "per", "+"]
				},
				"increasedRunePreservation" : {
					"title" : "Rune Preservation",
					"values" : [100, "per", "+"]
				},
				"increasedChanceToPreservePrayerPoints" : {
					"title" : "Preserve Prayer Points",
					"values" : [100, "per", "+"]
				},
				"increasedSummoningChargePreservation" : {
					"title" : "Summoning Charge Preservation",
					"values" : [100, "per", "+"]
				},
				"increasedChanceToPreservePotionCharge" : {
					"title" : "Preserve Potion Charge",
					"values" : [100, "per", "+"]
				},
				//Combat
				"decreasedAttackIntervalPercent" : {
					"title" : "Player Attack Interval Reduction %",
					"values" : [100, "per", "-"]
				},
				"decreasedMonsterRespawnTimer": {
					"title" : "Monster Respawn Reduction",
					"values" : [player.getMonsterSpawnTime() - 250, "ms", "-"] // Respawn time (Recommended not to go under 100)
				},
				"increasedDamageReduction" : {
					"title" : "Damage Reduction",
					"values" : [100, "per", "-"]
				},
				"increasedMinHitBasedOnMaxHit" : {
					"title" : "Increased Min Hit Based On Max Hit",
					"values" : [75, "per", "+"]
				},
				"increasedGlobalAccuracy" : {
					"title" : "Increased Global Accuracy",
					"values" : [100, "per", "+"]
				},
				"increasedGlobalEvasion" : {
					"title" : "Increased Global Evasion",
					"values" : [100, "per", "+"]
				},
				"increasedMaxHitpoints" : {
					"title" : "Hitpoints",
					"values" : [100, "per", "+"]
				},
				"increasedDamageToAllMonsters" : {
					"title" : "Damage to all Monsters",
					"values" : [100, "per", "+"]
				},
				"increasedLifesteal" : {
					"title" : "Lifesteal",
					"values" : [100, "per", "+"]
				},
				"increasedReflectDamage" : {
					"title" : "Reflect Damage",
					"values" : [100, "per", "+"]
				},
				"increasedFoodHealingValue" : {
					"title" : "Food Healing Value",
					"values" : [100, "per", "+"]
				},
				"increasedAutoEatEfficiency"  : {
					"title" : "Auto Eat Efficiency",
					"values" : [100, "per", "+"]
				},
				"increasedSlayerAreaEffectNegationFlat" : {
					"title" : "Slayer Area Effect Negation",
					"values" : [100, "per", "+"]
				},
				//Currency
				"increasedGPGlobal" : {
					"title" : "Increased Global GP",
					"values" : [100, "per", "+"]
				},
				"increasedGPFromSales" : {
					"title" : "GP from Sales",
					"values" : [100, "per", "+"]
				},
				"increasedSlayerCoins" : {
					"title" : "Slayer Coins",
					"values" : [100, "per", "+"]
				},
				//Loot
				"increasedChanceToDoubleItemsGlobal" : {
					"title" : "Double Items Global",
					"values" : [100, "per", "+"]
				},
				"increasedOffItemChance" : {
					"title" : "Off Item Chance",
					"values" : [100, "per", "+"]
				},
				"allowLootContainerStacking" : {
					"title" : "Loot Container Stacking",
					"values" : [1, "num", "+"]
				},
				"autoLooting" : {
					"title" : "Autoloot",
					"values" : [1, "num", "+"]
				},
				"allowSignetDrops" : {
					"title" : "Signet Drops",
					"values" : [1, "num", "+"]
				},
				//Other
				"increasedThievingStealth" : {
					"title" : "Increased Stealth",
					"values" : [2500, "num", "+"]
				},
				"increasedBankSpace" : {
					"title" : "Bank Space",
					"values" : [100, "num", "+"]
				},
				"increasedChanceNoDamageMining" : {
					"title" : "Chance No Damage Mining",
					"values" : [100, "per", "+"]
				},
				"increasedChanceForElementalRune" : {
					"title" : "Chance For Elemental Rune",
					"values" : [100, "per", "+"]
				},
				"increasedTreeCutLimit" : {
					"title" : "Tree Cut Limit",
					"values" : [10, "num", "+"]
				},
				"increasedEquipmentSets" : {
					"title" : "Increased Equipment Sets",
					"values" : [2, "num", "+"]
				},
				"freeBonfires" : {
					"title" : "Free Bonfires",
					"values" : [1, "num", "+"]
				},
				"freeCompost" : {
					"title" : "Free Compost",
					"values" : [1, "num", "+"]
				},
				"itemProtection" : {
					"title" : "Item Protection",
					"values" : [1, "num", "+"]
				},
				"curseImmunity" : {
					"title" : "Curse Immunity",
					"values" : [1, "num", "+"]
				},
				"dungeonEquipmentSwapping" : {
					"title" : "Dungeon Equipment Swapping",
					"values" : [1, "num", "+"]
				},
				"autoSlayerUnlocked" : {
					"title" : "Auto Slayer Unlocked",
					"values" : [1, "num", "+"]
				},
				"bypassSlayerItems" : {
					"title" : "Bypass Slayer Items",
					"values" : [1, "num", "+"]
				}
			}
		};
		
		var createPetObjectArray = function(modLoc, property){
			var arr = [];
			if(modLoc && property){
				for(const [key,value] of Object.entries(modLoc[property])){
					if(key && value){
						arr.push(modLoc[property][key][0]);
					}
				}
			}
			return arr;
		}

		//Dynamic section creator, makes it personal to the type of mod it is
		var createSection = function(sectionProps, isArr){
			
			//metadata info to be ignored
			var reserved = ["title"];

			//Header
			var section = "";
			
			//Skills require an array of arrays, this handles it
			if(isArr){
				section = `<br><h5 class="font-w400 font-size-sm mb-1">${sectionProps.title}</h5><br>`;
				for (const [key, value] of Object.entries(sectionProps)){
					if(reserved.indexOf(key) === -1){
						for(const[innerKey, innerValue] of Object.entries(sectionProps[key])){
							section += `<h5 class="font-w400 font-size-sm mb-1 text-success">${innerKey}: ${formatter(innerValue)} </h5>`;
						}
					}
				}
			}
			
			//Else just use the standard way of doing things
			else{
				section = `<br><h5 class="font-w400 font-size-sm mb-1">${sectionProps.title}</h5><br>`;
				for (const [key, value] of Object.entries(sectionProps)) {
					if(reserved.indexOf(key) === -1){
						section += `<h5 class="font-w400 font-size-sm mb-1 text-success">${value.title}: ${formatter(value.values)} </h5>`;
						}
					}
				}

			return section;
		};

		//Creates the description for the pet unlock
		var createDescription = function(){
			//Create the heading element
			var desc = '<div class="h5 font-w400 text-info text-center m-1 mb-2">Super Pet</div>';
			desc += createSection(mods.player, false);
			desc += createSection(mods.skills, true);
			return desc;
		};
		
		//Krypto The SuperPet
		var krypto = {
			"html_img_id" : "LR-kryptoPet",  
			"name":"Krypto",
			"description":createDescription(),
			"media":"https://i.imgur.com/OuQkdW0.png",
			"acquiredBy":"Being Cool",
			"modifiers":{
				"decreasedSkillIntervalPercent" : createPetObjectArray(mods.skills, "decreasedSkillIntervalPercent"),
				"increasedSlayerAreaEffectNegationFlat" : mods.player["increasedSlayerAreaEffectNegationFlat"].values[0],
				"increasedChanceToPreservePrayerPoints" : mods.player["increasedChanceToPreservePrayerPoints"].values[0],
				"increasedChanceToPreservePotionCharge" : mods.player["increasedChanceToPreservePotionCharge"].values[0],
				"increasedSummoningChargePreservation" : mods.player["increasedSummoningChargePreservation"].values[0],
				"increasedChanceToDoubleItemsGlobal" : mods.player["increasedChanceToDoubleItemsGlobal"].values[0],
				"increasedGlobalPreservationChance" : mods.player["increasedGlobalPreservationChance"].values[0],
				"increasedChanceForElementalRune" : mods.player["increasedChanceForElementalRune"].values[0],
				"decreasedAttackIntervalPercent" : mods.player["decreasedAttackIntervalPercent"].values[0],
				"increasedChanceNoDamageMining" : mods.player["increasedChanceNoDamageMining"].values[0],
				"increasedMinHitBasedOnMaxHit" : mods.player["increasedMinHitBasedOnMaxHit"].values[0],
				"increasedDamageToAllMonsters" : mods.player["increasedDamageToAllMonsters"].values[0],
				"decreasedMonsterRespawnTimer" : mods.player["decreasedMonsterRespawnTimer"].values[0],
				"increasedAutoEatEfficiency" : mods.player["increasedAutoEatEfficiency"].values[0],
				"allowLootContainerStacking" : mods.player["allowLootContainerStacking"].values[0],
				"increasedRunePreservation" : mods.player["increasedRunePreservation"].values[0],
				"increasedAmmoPreservation" : mods.player["increasedAmmoPreservation"].values[0],
				"increasedFoodHealingValue" : mods.player["increasedFoodHealingValue"].values[0],
				"increasedThievingStealth" : mods.player["increasedThievingStealth"].values[0],
				"increasedGlobalMasteryXP" : mods.player["increasedGlobalMasteryXP"].values[0],
				"increasedDamageReduction" : mods.player["increasedDamageReduction"].values[0],
				"dungeonEquipmentSwapping" : mods.player["dungeonEquipmentSwapping"].values[0],
				"increasedGlobalAccuracy" : mods.player["increasedGlobalAccuracy"].values[0],
				"increasedGlobalSkillXP" : mods.player["increasedGlobalSkillXP"].values[0],
				"increasedGlobalEvasion" : mods.player["increasedGlobalEvasion"].values[0],
				"increasedReflectDamage" : mods.player["increasedReflectDamage"].values[0],
				"increasedOffItemChance" : mods.player["increasedOffItemChance"].values[0],
				"increasedEquipmentSets" : mods.player["increasedEquipmentSets"].values[0],
				"increasedMaxHitpoints" : mods.player["increasedMaxHitpoints"].values[0],
				"increasedTreeCutLimit" : mods.player["increasedTreeCutLimit"].values[0],
				"increasedSlayerCoins" : mods.player["increasedSlayerCoins"].values[0],
				"increasedGPFromSales" : mods.player["increasedGPFromSales"].values[0],
				"autoSlayerUnlocked" : mods.player["autoSlayerUnlocked"].values[0],
				"increasedLifesteal" : mods.player["increasedLifesteal"].values[0],
				"increasedBankSpace" : mods.player["increasedBankSpace"].values[0],
				"increasedGPGlobal" : mods.player["increasedGPGlobal"].values[0],
				"bypassSlayerItems" : mods.player["bypassSlayerItems"].values[0],
				"allowSignetDrops" : mods.player["allowSignetDrops"].values[0],
				"itemProtection" : mods.player["itemProtection"].values[0],
				"curseImmunity" : mods.player["curseImmunity"].values[0],
				"freeBonfires" : mods.player["freeBonfires"].values[0],
				"freeCompost" : mods.player["freeCompost"].values[0],
				"autoLooting" : mods.player["autoLooting"].values[0]
            },
            "activeInRaid":false
        };
		
		//Get the total amount of pets and add krypto to the end
		var curLen = JSON.stringify(PETS.length);
		krypto.location = curLen;
		PETS.push(krypto);

		//Unlock the pet
		unlockPet(parseInt(curLen));

		//Add to container
		createPetInLog(krypto);

		//Make sure player stats are updated
		updatePlayerStats();

		//Make sure equipment set change is updated
		player.updateForEquipSetChange();

		//Make sure player modifiers are updated
		updateAllPlayerModifiers();
	};
	
	const inject = () => {
		const script = document.createElement('script');
		script.textContent = `try { (${main})(); } catch (e) { console.error(e); }`;
		document.body.appendChild(script);
	}

	load();
})();