function whenAvailable(names, callback) {
    var interval = 10; // ms
    window.setTimeout(function() {
		let bool = true;
		for(let i = 0; i < names.length; i++)
		{
			if(!window[names[i]])
			{
				bool = false;
			}
		}
        if (bool) {
            callback();
        } else {
            whenAvailable(names, callback);
        }
    }, interval);
}
var modName = "mods/generative_mods.js";
var explodeAtPlusMod = "mods/explodeAtPlus.js";
var runAfterAutogenMod = "mods/runAfterAutogen2.js";
var libraryMod = "mods/code_library.js";
var feyAndMoreMod = "mods/fey_and_more.js";
var mobsMod = "mods/mobs.js";

if(enabledMods.includes(runAfterAutogenMod) && enabledMods.includes(explodeAtPlusMod) && enabledMods.includes(libraryMod) && enabledMods.includes(feyAndMoreMod) && enabledMods.includes(mobsMod)) {
whenAvailable(["eLists","explodeAtPlus","urlParams","runAfterAutogen","mobsLoaded"], function() {
	
	//urlParams reads
		
		//Bombs

			if(urlParams.get('generateBombs') !== null) { //if the variable exists at all
				generateBombs = true
			} else { //if it doesn't (and it returns null)
				generateBombs = false
			}

			if(urlParams.get('bombAmount') != null) { //null check
				bombAmount = urlParams.get('bombAmount')
				if(isNaN(bombAmount) || bombAmount === "" || bombAmount === null) { //NaN check
					 bombAmount = 10
				}
				bombAmount = parseInt(bombAmount)
				if(bombAmount > 50) {
					alert("Maximum amount of additional bomb/anti-bomb pairs is 50.\nOnly 50 were added.")
				} else if(bombAmount < 1) {
					alert("Minimum amount of additional bomb/anti-bomb pairs is 1.\n1 pair was added.")
				}
				bombAmount = Math.min(50,Math.max(bombAmount,1))
			} else {
				bombAmount = 10
			}

		//Clouds

			if(urlParams.get('generateClouds') !== null) { //if the variable exists at all
				generateClouds = true
			} else { //if it doesn't (and it returns null)
				generateClouds = false
			}

			if(urlParams.get('cloudIncludeRandom') !== null) { //if the variable exists at all
				cloudIncludeRandom = true
			} else { //if it doesn't (and it returns null)
				cloudIncludeRandom = false
			}

		//Creepers

			//Include generated creepers in Random tool?
			if(urlParams.get('creeperIncludeRandom') !== null) { //if the variable exists at all
				creeperIncludeRandom = true
			} else { //if it doesn't (and it returns null)
				creeperIncludeRandom = false
			}

			//Generate creepers
			if(urlParams.get('generateCreepers') !== null) { //if the variable exists at all
				generateCreepers = true
			} else { //if it doesn't (and it returns null)
				generateCreepers = false
			}

		//Fairies

			if(urlParams.get('fairyIncludeRandom') !== null) { //if the variable exists at all
				fairyIncludeRandom = true
			} else { //if it doesn't (and it returns null)
				fairyIncludeRandom = false
			}

			//Generate fairies
			if(urlParams.get('generateFairies') !== null) { //if the variable exists at all
				generateFairies = true
			} else { //if it doesn't (and it returns null)
				generateFairies = false
			}
			
			if(urlParams.get('fairyAmount') != null) { //null check
				fairyAmount = urlParams.get('fairyAmount')
				if(isNaN(fairyAmount) || fairyAmount === "" || fairyAmount === null) { //NaN check
					 fairyAmount = 10
				}
				fairyAmount = parseInt(fairyAmount)
				if(fairyAmount > 10000) {
					alert("Maximum amount of additional fairies is 10000.\nOnly 10000 fairies were added.")
				} else if(fairyAmount < 1) {
					alert("Minimum amount of additional fairies is 1.\n1 fairy was added.")
				}
				fairyAmount = Math.min(10000,Math.max(fairyAmount,1))
			} else {
				fairyAmount = 10
}

		//Spouts

			//Generate spouts
			if(urlParams.get('generateSpouts') !== null) { //if the variable exists at all
				generateSpouts = true
			} else { //if it doesn't (and it returns null)
				generateSpouts = false
			}

			if(urlParams.get('spoutIncludeRandom') !== null) { //if the variable exists at all
				spoutIncludeRandom = true
			} else { //if it doesn't (and it returns null)
				spoutIncludeRandom = false
			}

	//Requisite variables

		//Bombs

			amalgamatedBombFire = "plasma,plasma,plasma,plasma,plasma,plasma,plasma,plasma,plasma,plasma,plasma,plasma,smoke,plasma,plasma,fire,smoke,fire,smoke,plasma,metal_scrap,metal_scrap,metal_scrap,metal_scrap,metal_scrap,acid,acid,oil,oil,oil,oil,oil,oil,oil,plasma,plasma,plasma,plasma,plasma,smoke,plasma,plasma,fire,smoke,plasma,metal_scrap,metal_scrap,metal_scrap,metal_scrap,metal_scrap,metal_scrap,flash,flash,flash,flash,flash,acid_gas,acid_gas,acid_gas,acid,oil,oil,oil,oil,oil,oil,oil,oil,oil,oil,plasma,plasma,plasma,plasma,metal_scrap,metal_scrap,metal_scrap,metal_scrap,metal_scrap,acid,acid,oil,oil,oil,oil,oil,oil,oil,plasma,plasma,plasma,plasma,plasma,smoke,plasma,plasma,fire,smoke,plasma,metal_scrap,metal_scrap,metal_scrap,metal_scrap,metal_scrap,metal_scrap,electric_cluster_bomb,electric_cluster_bomb,flash,flash,flash,flash,flash,acid_gas,acid_gas,acid_gas,acid,oil,oil,oil,oil,oil,oil,oil,oil,oil,oil,plasma,plasma,plasma,plasma,plague,plague,plague,plague,plague,plague,radiation,radiation,radiation,radiation,radiation,radiation,radiation,radiation,uranium,uranium,uranium,uranium,uranium,uranium,greek_fire,greek_fire,greek_fire,greek_fire,greek_fire,antimatter,antimatter,antimatter,antimatter,antimatter,smoke_grenade,antimatter,smoke_grenade,fireball,flash,acid_gas,acid_gas,acid_gas,plague,plague,plague,plague,plague,plague,radiation,radiation,radiation,radiation,radiation,radiation,radiation,radiation,uranium,uranium,uranium,uranium,uranium,uranium,greek_fire,greek_fire,greek_fire,greek_fire,greek_fire,antimatter,antimatter,antimatter,antimatter,antimatter,smoke_grenade,antimatter,flash,acid_gas,acid_gas,acid_gas,radiation,radiation,radiation,radiation,plague,acid_gas,acid_gas,acid_gas,chlorine,chlorine,chlorine"
			eLists.BOMB = ["bomb", "tnt", "c4", "grenade", "dynamite", "gunpowder", "firework", "nuke", "h_bomb", "dirty_bomb", "emp_bomb", "sticky_bomb", "cold_bomb", "hot_bomb", "electro_bomb", "water_bomb", "antimatter_bomb", "flashbang", "smoke_grenade", "fireball", "landmine", "cluster_bomb", "cluster_nuke", "op_hottester_bomb", "anti-bomb", "electric_bomblet", "electric_cluster_bomb", "radioactive_popper", "acid_bomb", "amalgamated_bomb"]; bombChoices = eLists.BOMB;
			var excludedBombElements = ["water", "antimatter", "acid"];

		//Clouds

			eLists.CLOUD = ["cloud", "rain_cloud", "snow_cloud", "fire_cloud", "hail_cloud", "acid_cloud", "pyrocumulus"]; cloudChoices = eLists.CLOUD;
			var includedClouds = ["cloud", "rain_cloud", "snow_cloud", "fire_cloud", "hail_cloud", "acid_cloud", "pyrocumulus"];
			var excludedCloudElements = ["snow", "fire", "hail", "acid"];
			if(typeof(behaviorGenerators) === "undefined") { behaviorGenerators = {} };

		//Creepers

			var placeholderColor = "#FF00FF";
			var hslOffsets = [[0, -5, 5], [0, -20, 10], [0, 0, 10], [0, -20, 10], [0, -35, 0], [0, -20, -30], [0, 10, -10], [0, 10, 20], [0, -20, 10], [0, -10, 5]];
			var colorOfRandomCreeper = ["#7ba883", "#8aba8a", "#87b292", "#8aba8a", "#71a171", "#346434", "#4d6d72", "#a0caad", "#8aba8a", "#7dac7f"]

		//Fairies

			var excludedFairyElements = []
			var backupCategoryWhitelist = ["land","powders","weapons","food","life","corruption","states","fey","Fantastic Creatures","dyes","energy liquids","random liquids","random gases","random rocks"];
			var backupElementWhitelist = ["mercury", "chalcopyrite_ore", "chalcopyrite_dust", "copper_concentrate", "fluxed_copper_concentrate", "unignited_pyrestone", "ignited_pyrestone", "everfire_dust", "extinguished_everfire_dust", "mistake", "polusium_oxide", "vaporized_polusium_oxide", "glowstone_dust", "redstone_dust", "soul_mud", "wet_soul_sand", "nitrogen_snow", "fusion_catalyst", "coal", "coal_coke", "blast_furnace_fuel", "molten_mythril"];

		//Spouts
			eLists.SPOUT = ["spout", "udder", "torch"]; spoutChoices = eLists.SPOUT;
			var excludedSpoutElements = ["ketchup", "liquid_cloner", "fire_cloner"]
			var includedSpouts = ["ketchup_spout", "spout", "udder", "torch"]
			var backupCategoryWhitelist = ["land","powders","weapons","food","life","corruption","states","fey","Fantastic Creatures","dyes","energy liquids","random liquids","random gases","random rocks"];
			var backupElementWhitelist = ["mercury", "chalcopyrite_ore", "chalcopyrite_dust", "copper_concentrate", "fluxed_copper_concentrate", "unignited_pyrestone", "ignited_pyrestone", "everfire_dust", "extinguished_everfire_dust", "mistake", "polusium_oxide", "vaporized_polusium_oxide", "glowstone_dust", "redstone_dust", "soul_mud", "wet_soul_sand", "nitrogen_snow", "fusion_catalyst", "coal", "coal_coke", "blast_furnace_fuel", "molten_mythril"];


	//Requisite non-generating functions

		//Bombs

			function firebombFire(pixel,x,y,radius,fire,smoke,power,damage) {
				var coords = circleCoords(pixel.x,pixel.y,radius);
				for (var i = 0; i < coords.length; i++) {
					var x = coords[i].x;
					var y = coords[i].y;
					if(!isEmpty(x,y,true)) {
						var pixel = pixelMap[x][y];
						var info = elements[pixel.element];
						var cursedFireChance = 0.15 + power;
						if (info.burn) { //Light everything on fire
							pixel.burning = true;
							pixel.burnStart = pixelTicks;
							pixel.temp += 10; //smoke prevention
						} else if(Math.random() < cursedFireChance) { //(15+power)%/px cursed burning
							pixel.burning = true;
							pixel.burnStart = pixelTicks;
							pixel.temp += 10;
						};
					} else if(isEmpty(x,y)) { //if there's space for fire
						if (Array.isArray(fire)) { //this should remain "fire"
							var newfire = fire[Math.floor(Math.random() * fire.length)];
						} else {
							var newfire = fire;
						};
						createPixel(newfire,x,y); //add fire
						var firePixel = pixelMap[x][y];
						firePixel.temp = Math.max(elements[newfire].temp,firePixel.temp);
						firePixel.burning = true;
					};
				};
			};

			function hotterBomb(pixel,x,y,radius,fire,smoke,power,damage) {
				//console.log(`Radius: ${radius}\nPower: ${power}\nPixel: (${pixel.x},${pixel.y})\nDamage: ${damage}`);
				//console.log(`Expected temperature increase for pixel at (${pixel.x},${pixel.y}): ${800 * ((1 + (7 * damage)) ** 2) * ((power ** 2) * 1.5)}`);
				pixel.temp += (800 * ((1 + (7 * damage)) ** 2) * ((power ** 2) * 1.5));
			};

			function empCharge(pixel,x,y,radius,fire,smoke,power,damage) {
				var info = elements[pixel.element];
				if(info.conduct) {
					var distanceFromEdge = Math.max(0,radius - coordPyth(pixel.x,pixel.y,x,y));
					var radiusRelatedIncrease = Math.sqrt(distanceFromEdge/5);
					pixel.charge ??= 0;
					pixel.charge += (50 * radiusRelatedIncrease);
					pixel.temp += 700/bound(info.conduct,0.1,1);
				};
			};

			function starbombHeat(pixel,x,y,radius,fire,smoke,power,damage) { //Massively heats depending on distance from explosion center
				var distanceFromEdge = Math.max(0,radius - coordPyth(pixel.x,pixel.y,x,y));
				var radiusRelatedIncrease = 10 ** logN(distanceFromEdge,5);
				pixel.temp += (10000 * radiusRelatedIncrease);
				pixelTempCheck(pixel);
			};

		//Clouds

			behaviorGenerators.cloud = function(element) {
				if(element instanceof Array) { element = element.join(",") };
				return [
					["XX","XX","XX"],
					["XX",`CH:${element}%0.05`,"M1%2.5 AND BO"],
					["XX","XX","XX"]
				];
			};

			behaviorGenerators.heavy_cloud = function(element) {
				if(element instanceof Array) { element = element.join(",") };
				return [
					["XX","XX","XX"],
					["XX",`CH:${element}%0.1`,"M1%2.5 AND BO"],
					["XX",`CR:${element}%0.05`,"XX"]
				];
			};

			behaviorGenerators.heavier_cloud = function(element) {
				if(element instanceof Array) { element = element.join(",") };
				return [
					["XX","XX","XX"],
					["XX",`CH:${element}%0.2`,"M1%2.5 AND BO"],
					["XX",`CR:${element}%0.1`,"XX"]
				];
			};

			behaviorGenerators.heaviest_cloud = function(element) {
				if(element instanceof Array) { element = element.join(",") };
				return [
					["XX","XX","XX"],
					["XX",`CH:${element}%0.4`,"M1%2.5 AND BO"],
					["XX",`CR:${element}%0.2`,"XX"]
				];
			};

			behaviorGenerators.heaviester_cloud = function(element) {
				if(element instanceof Array) { element = element.join(",") };
				return [
					["XX","XX","XX"],
					["XX",`CH:${element}%0.8`,"M1%2.5 AND BO"],
					["XX",`CR:${element}%0.4`,"XX"]
				];
			};

			behaviorGenerators.heaviestest_cloud = function(element) {
				if(element instanceof Array) { element = element.join(",") };
				return [
					["XX",`CR:${element}%0.8`,"XX"],
					[`CR:${element}%0.05`,`CH:${element}%3`,`CR:${element}%0.05 AND M1%2.5 AND BO`],
					["XX",`CR:${element}%0.8`,"XX"]
				];
			};

			function placeDownwardColumn(element,xx,yy,creationChance) {
				if(element.includes(",")) { element = element.split(",") };
				var newElement = element;
				//console.log(JSON.stringify(element));
				//console.log("from " + xx + "," + yy)
				if(!outOfBounds(xx,yy)) {
					for(i = yy; i < pixelMap[xx].length; i++) {
						if(Array.isArray(element)) {
							newElement = element[Math.floor(Math.random() * element.length)];
						};
						//console.log(JSON.stringify(newElement));
						if(isEmpty(xx,i,false)) {
							if(Math.random() < creationChance) {
								createPixel(newElement,xx,i)
							}
						} else if(!isEmpty(xx,i,true)) {
							var newPixel = pixelMap[xx][i];
							var otherElement = newPixel.element;
							var newState = elements[otherElement].state ?? "solid"; //assume undefined = solid
							if(newState !== "solid") {
								continue;
							} else {
								break;
							};
						} else if(outOfBounds(xx,i)) {
							break;
						}; 
					};
				};
			};

			function singleColumn(pixel,element,chance,fillAmountDecimal) {
				if(Math.random() < chance) {
					placeDownwardColumn(element,pixel.x,pixel.y+1,fillAmountDecimal);
				}
			};

			function multiColumn(pixel,element,chance,fillAmountDecimal,columnRadius) {
				if(Math.random() < chance) {
					for(j = 0 - columnRadius; j <= columnRadius; j++) {
						placeDownwardColumn(element,pixel.x+j,pixel.y+1,fillAmountDecimal);
					};
				}
			};

		//Creepers

			autoCreeperPlacerTick = function(pixel) {
				var creeperElement = elements[pixel.element].creeperType;
				var headName,bodyName;
				if(typeof(creeperElement === "string")) { //comma separated string check
					if(creeperElement.includes(",")) { //if it is
						creeperElement = creeperElement.split(","); //to array
						creeperElement = creeperElement.filter(function(e) { //strip nonexistent elements
							return typeof(elements[e]) === "object";
						});
					};
				};
				if(Array.isArray(creeperElement)) {
					headName = `${creeperElement.join("_")}_creeper_head`; //auto head element name
					bodyName = `${creeperElement.join("_")}_creeper_body`; //auto body element name
				} else {
					headName = `${creeperElement}_creeper_head`; //auto head element name
					bodyName = `${creeperElement}_creeper_body`; //auto body element name
				};
				if (isEmpty(pixel.x, pixel.y+1)) {
					createPixel(bodyName, pixel.x, pixel.y+1);
					pixel.element = headName;
					pixel.color = pixelColorPick(pixel)
				} else if (isEmpty(pixel.x, pixel.y-1)) {
					createPixel(headName, pixel.x, pixel.y-1);
					pixel.element = bodyName;
					pixel.color = pixelColorPick(pixel)
				} else {
					deletePixel(pixel.x, pixel.y);
				};
			};

			autoCreeperBodyTick = function(pixel) {
				var creeperElement = elements[pixel.element].creeperType;
				var headName,bodyName,explodeInto;
				if(typeof(creeperElement === "string")) { //comma separated string check
					if(creeperElement.includes(",")) { //if it is
						creeperElement = creeperElement.split(","); //to array
						creeperElement = creeperElement.filter(function(e) { //strip nonexistent elements
							return typeof(elements[e]) === "object";
						});
					};
				};
				if(Array.isArray(creeperElement)) {
					headName = `${creeperElement.join("_")}_creeper_head`; //auto head element name
					bodyName = `${creeperElement.join("_")}_creeper_body`; //auto body element name
					explodeInto = creeperElement.join(","); //auto body element name
				} else {
					headName = `${creeperElement}_creeper_head`; //auto head element name
					bodyName = `${creeperElement}_creeper_body`; //auto body element name
					explodeInto = creeperElement; //auto body element name
				};
				if (tryMove(pixel, pixel.x, pixel.y+1)) { // Fall
					if (!isEmpty(pixel.x, pixel.y-2, true)) { // Drag head down
						var headPixel = pixelMap[pixel.x][pixel.y-2];
						if (headPixel.element == headName) {
							if (isEmpty(pixel.x, pixel.y-1)) {
								movePixel(pixelMap[pixel.x][pixel.y-2], pixel.x, pixel.y-1);
							}
							else {
								swapPixels(pixelMap[pixel.x][pixel.y-2], pixelMap[pixel.x][pixel.y-1]);
							}
						}
					}
				}
				doHeat(pixel);
				doBurning(pixel);
				doElectricity(pixel);
				if (pixel.dead) {
					// Turn into rotten_meat if pixelTicks-dead > 500
					if (pixelTicks-pixel.dead > 200) {
						Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
					}
					return
				}

				// Find the head
				if (!isEmpty(pixel.x, pixel.y-1, true) && pixelMap[pixel.x][pixel.y-1].element == headName) {
					var head = pixelMap[pixel.x][pixel.y-1];
					if (head.dead) { // If head is dead, kill body
						pixel.dead = head.dead;
					}
				}
				else { var head = null }

				if (isEmpty(pixel.x, pixel.y-1)) {
					// create blood if decapitated 10% chance
					if (Math.random() < 0.1) {
						createPixel("blood", pixel.x, pixel.y-1);
						// set dead to true 15% chance
						if (Math.random() < 0.15) {
							pixel.dead = pixelTicks;
						}
					}
				}
				else if (head == null) { return }
				else if (Math.random() < 0.1) { // Move 10% chance
					var movesToTry = [
						[1*pixel.dir,0],
						[1*pixel.dir,-1],
					];
					// While movesToTry is not empty, tryMove(pixel, x, y) with a random move, then remove it. if tryMove returns true, break.
					while (movesToTry.length > 0) {
						var move = movesToTry.splice(Math.floor(Math.random() * movesToTry.length), 1)[0];
						if (isEmpty(pixel.x+move[0], pixel.y+move[1]-1)) {
							if (tryMove(pixel, pixel.x+move[0], pixel.y+move[1])) {
								movePixel(head, head.x+move[0], head.y+move[1]);
								break;
							};
						};
					};
					// 15% chance to change direction while not chasing a human
					if(!head.following) {
						if (Math.random() < 0.15) {
							pixel.dir *= -1;
							//console.log("*turns around cutely to face ${pixel.dir < 0 ? 'left' : 'right'}*");
						};
					}/* else {
						//console.log("*chases cutely*");
					};*/
				};

				if(pixel.charge) {
					pixel.charged = true;
				};
				
				if(head) {
					if(typeof(head.charge) !== "undefined") {
						if(head.charge) {
							pixel.charged = true;
						};
					};
					if(typeof(head.charged) !== "undefined") {
						if(head.charged) {
							pixel.charged = true;
						};
					};
				};

				if(typeof(pixel.charged) === "undefined") {
					pixel.charged = false;
				};

				if(pixel.charged) {
					var explosionRadius = 7;
					if(!pixel.didChargeBlueTinted) { //do once, on initial charge
						//console.log("something something halsey lyric");
						var color = pixel.color;
						if(color.startsWith("rgb")) {
							//console.log("rgb detected");
							color = color.split(","); //split color for addition
							var red = parseFloat(color[0].substring(4));
							var green = parseFloat(color[1]);
							var blue = parseFloat(color[2].slice(0,-1));
							red = rgbColorBound(red + 51);
							green = rgbColorBound(green + 51);
							blue = rgbColorBound(blue + 102);
							color = `rgb(${red},${green},${blue})`;
							pixel.color = color;
							//console.log("color set");
						} else if(color.startsWith("hsl")) {
							//console.log("hsl detected");
							color = color.split(","); //split color for addition
							var hue = parseFloat(color[0].substring(4));
							var saturation = parseFloat(color[1].slice(0,-1));
							var luminance = parseFloat(color[2].slice(0,-2));
							hue = hue % 360; //piecewise hue shift
							if(hue <= 235 && hue >= 135) {
								hue = 185;
							} else if(hue < 135) {
								hue += 50;
							} else if(hue > 235 && hue < 360) {
								hue -= 50;
							};
							saturation = slBound (saturation + 10);
							luminance = slBound(luminance + 20);
							color = `hsl(${hue},${saturation}%,${luminance}%)`;
							pixel.color = color;
							//console.log("color set");
						};
						pixel.didChargeBlueTinted = true;
					};
				} else {
					var explosionRadius = 5;
				};
				
				if(pixel.burning) {
					pixel.hissing = true;
					if(!pixel.hissStart) {
						pixel.hissStart = pixelTicks;
					};
					if(!pixel.burnStart) { //I don't like errors.
						pixel.burnStart = pixel.ticks;
					};
					if(pixelTicks - pixel.burnStart > 30) {
						//console.log("Kaboom?");
						explodeAt(pixel.x,pixel.y,explosionRadius,creeperElement);
						//console.log("Yes, Rico, kaboom.");
					};
				};

				//Head hissing color handler: keeps track of head's hissing for coloring purposes
				for(i = 0; i < 1; i++) { //dummy for loop
					if(pixel.dead || !head || head.dead) { //can't hiss without a head according to the classic creeper anatomy
						//console.log("ss-- oof");
						pixel.hissing = false;
						break;
					};
					if(head.hissing) {
						//console.log("Ssssssss");
						if(!head.hissStart) {
							//console.log("t-30 ticks or whatever it was");
							head.hissStart = pixelTicks;
						};

						//Color code {
							var ticksHissing = pixelTicks - head.hissStart;
							var color = pixel.color; //do on each hissing tick
							if(color.startsWith("rgb")) {
								//console.log("rgb detected");
								color = color.split(","); //split color for addition
								var red = parseFloat(color[0].substring(4));
								var green = parseFloat(color[1]);
								var blue = parseFloat(color[2].slice(0,-1));
								red = rgbColorBound(red + ticksHissing);
								green = rgbColorBound(green + ticksHissing);
								blue = rgbColorBound(blue + ticksHissing);
								color = `rgb(${red},${green},${blue})`;
								pixel.color = color;
								//console.log("color set");
							} else if(color.startsWith("hsl")) {
								//console.log("hsl detected");
								color = color.split(","); //split color for addition
								var hue = parseFloat(color[0].substring(4));
								var saturation = parseFloat(color[1].slice(0,-1));
								var luminance = parseFloat(color[2].slice(0,-2));
								//console.log("the j");
								luminance = slBound(luminance + 1.176);
								//console.log(luminance);
								color = `hsl(${hue},${saturation}%,${luminance}%)`;
								pixel.color = color;
								//console.log("color set");
							};
						//}
					};
				};
			};

			autoCreeperHeadTick = function(pixel) {
				var creeperElement = elements[pixel.element].creeperType;
				var headName,bodyName,explodeInto;
				if(typeof(creeperElement === "string")) { //comma separated string check
					if(creeperElement.includes(",")) { //if it is
						creeperElement = creeperElement.split(","); //to array
						creeperElement = creeperElement.filter(function(e) { //strip nonexistent elements
							return typeof(elements[e]) === "object";
						});
					};
				};
				if(Array.isArray(creeperElement)) {
					headName = `${creeperElement.join("_")}_creeper_head`; //auto head element name
					bodyName = `${creeperElement.join("_")}_creeper_body`; //auto body element name
					explodeInto = creeperElement.join(","); //auto body element name
				} else {
					headName = `${creeperElement}_creeper_head`; //auto head element name
					bodyName = `${creeperElement}_creeper_body`; //auto body element name
					explodeInto = creeperElement; //auto body element name
				};
				doHeat(pixel);
				doBurning(pixel);
				doElectricity(pixel);
				if (pixel.dead) {
					// Turn into rotten_meat if pixelTicks-dead > 500
					if (pixelTicks-pixel.dead > 200) {
						Math.random() < 0.1 ? changePixel(pixel,"gunpowder") : changePixel(pixel,"rotten_meat");
						return
					}
				}

				// Find the body
				if (!isEmpty(pixel.x, pixel.y+1, true) && pixelMap[pixel.x][pixel.y+1].element == bodyName) {
					var body = pixelMap[pixel.x][pixel.y+1];
					if (body.dead) { // If body is dead, kill head
						pixel.dead = body.dead;
					}
				}
				else { var body = null }

				if(body) {
					if(body.dir !== pixel.dir) { //hacky workaround: lock head dir to body dir
						pixel.dir = body.dir;
					};
				};

				if (isEmpty(pixel.x, pixel.y+1)) {
					tryMove(pixel, pixel.x, pixel.y+1);
					// create blood if severed 10% chance
					if (isEmpty(pixel.x, pixel.y+1) && !pixel.dead && Math.random() < 0.1) {
						createPixel("blood", pixel.x, pixel.y+1);
						// set dead to true 15% chance
						if (Math.random() < 0.15) {
							pixel.dead = pixelTicks;
						}
					}
				}
				
				//start of most new code
				var pX = pixel.x;
				var pY = pixel.y;
				
				if(pixel.charge) {
					pixel.charged = true;
				};
				
				if(body) {
					if(typeof(body.charge) !== "undefined") {
						if(body.charge) {
							pixel.charged = true;
						};
					};
					if(typeof(body.charged) !== "undefined") {
						if(body.charged) {
							pixel.charged = true;
						};
					};
				};
				
				if(typeof(pixel.charged) === "undefined") {
					pixel.charged = false;
				};

				if(pixel.charged) {
					var explosionRadius = 10;
					if(!pixel.didChargeBlueTinted) { //do once, on initial charge
						//console.log("something something halsey lyric");
						var color = pixel.color;
						if(color.startsWith("rgb")) {
							//console.log("rgb detected");
							color = color.split(","); //split color for addition
							var red = parseFloat(color[0].substring(4));
							var green = parseFloat(color[1]);
							var blue = parseFloat(color[2].slice(0,-1));
							red = rgbColorBound(red + 51);
							green = rgbColorBound(green + 51);
							blue = rgbColorBound(blue + 102);
							color = `rgb(${red},${green},${blue})`;
							pixel.color = color;
							//console.log("color set");
						} else if(color.startsWith("hsl")) {
							//console.log("hsl detected");
							color = color.split(","); //split color for addition
							var hue = parseFloat(color[0].substring(4));
							var saturation = parseFloat(color[1].slice(0,-1));
							var luminance = parseFloat(color[2].slice(0,-2));
							hue = hue % 360; //piecewise hue shift
							if(hue <= 235 && hue >= 135) {
								hue = 185;
							} else if(hue < 135) {
								hue += 50;
							} else if(hue > 235 && hue < 360) {
								hue -= 50;
							};
							saturation = slBound (saturation + 10);
							luminance = slBound(luminance + 20);
							color = `hsl(${hue},${saturation}%,${luminance}%)`;
							pixel.color = color;
							//console.log("color set");
						};
						pixel.didChargeBlueTinted = true;
					};
				} else {
					var explosionRadius = 7;
				};
				
				//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
				var directionAdverb = "left";
				if(pixel.dir > 0) {
					directionAdverb = "right";
				};
				//console.log(`Looking ${directionAdverb}`)
				if(pixel.dir === -1) {
					for(i = -4; i < 4+1; i++) {
						var oY = i;
						//console.log(`Starting row look at row ${pY+oY}`)
						for(j = (-1); j > (-16 - 1); j--) {
							var oX = j;
							var nX = pX+oX;
							var nY = pY+oY;
							if(outOfBounds(nX,nY)) {
								//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
								break;
							};
							if(isEmpty(nX,nY)) {
								////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
								continue;
							};
							if(!isEmpty(nX,nY,true)) {
								var newPixel = pixelMap[nX][nY];
								var newElement = newPixel.element;
								if(enemyHumanoidArray.includes(newElement)) {
									//console.log(`Human part found at (${nX},${nY})`)
									if(!newPixel.dead) {
										pixel.following = true;
										//console.log(`Human detected at (${nX},${nY})`)
										//Start "hissing" if a human is close enough
										if(coordPyth(pX,pY,nX,nY) <= 3.15) { //probably misapplying the tolerance from the MC Wiki line: "Creepers will chase after any player, as long as it is within a 16 block (±5%) radius"
											pixel.hissing = true;
											if(!pixel.hissStart) {
												pixel.hissStart = pixelTicks;
											};
										};
									};
								} else {
									//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
									break; //can't see through humans
								};
							};
						};
					};
				} else if(pixel.dir === 1) {
					for(i = -4; i < 4+1; i++) {
						var oY = i;
						//console.log(`Starting row look at row ${pY+oY}`)
						for(j = 1; j < 16 + 1; j++) {
							var oX = j;
							var nX = pX+oX;
							var nY = pY+oY;
							if(outOfBounds(nX,nY)) {
								//console.log(`Stopping row look at pixel (${nX},${nY}) due to OoB`)
								break;
							};
							if(isEmpty(nX,nY)) {
								////console.log(`Skipping pixel (${nX},${nY}) (empty)`)
								continue;
							};
							if(!isEmpty(nX,nY,true)) {
								var newPixel = pixelMap[nX][nY];
								var newElement = newPixel.element;
								if(enemyHumanoidArray.includes(newElement)) {
									//console.log(`Human part found at (${nX},${nY})`)
									if(!newPixel.dead) {
										pixel.following = true;
										//console.log(`Human detected at (${nX},${nY})`)
										//Start "hissing" if a human is close enough
										if(coordPyth(pX,pY,nX,nY) <= 3.15) {
											pixel.hissing = true;
											if(!pixel.hissStart) {
												pixel.hissStart = pixelTicks;
											};
										};
										break;
									};
								} else {
									//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
									break;
								};
							};
						};
					};
				};
				
				//Pre-explosion handler: keeps track of time before the kaboom
				for(i = 0; i < 1; i++) { //dummy for loop
					if(pixel.hissing) {
						//console.log("Ssssssss");
						if(pixel.dead || !body || body.dead) { //can't explode without a body according to the classic creeper anatomy
							//console.log("ss-- oof");
							pixel.hissing = false;
							break;
						};
						if(!pixel.hissStart) {
							//console.log("t-30 ticks or whatever it was");
							pixel.hissStart = pixelTicks;
						};
						//Color code {
							var ticksHissing = pixelTicks - pixel.hissStart;
							var color = pixel.color; //do on each hissing tick
							if(color.startsWith("rgb")) {
								//console.log("rgb detected");
								color = color.split(","); //split color for addition
								var red = parseFloat(color[0].substring(4));
								var green = parseFloat(color[1]);
								var blue = parseFloat(color[2].slice(0,-1));
								red = rgbColorBound(red + ticksHissing);
								green = rgbColorBound(green + ticksHissing);
								blue = rgbColorBound(blue + ticksHissing);
								color = `rgb(${red},${green},${blue})`;
								pixel.color = color;
								//console.log("color set");
							} else if(color.startsWith("hsl")) {
								//console.log("hsl detected");
								color = color.split(","); //split color for addition
								var hue = parseFloat(color[0].substring(4));
								var saturation = parseFloat(color[1].slice(0,-1));
								var luminance = parseFloat(color[2].slice(0,-2));
								luminance = slBound(luminance + 1.176);
								color = `hsl(${hue},${saturation}%,${luminance}%)`;
								pixel.color = color;
								//console.log("color set");
							};
						//}

						if(pixelTicks - pixel.hissStart > 30) {
							//console.log("Kaboom?");
							//console.log(`Exploding with element ${creeperElement} and radius ${explosionRadius} (charged: ${pixel.charged})`);
							explodeAt(body.x,body.y,explosionRadius,explodeInto);
							//console.log("Yes, Rico, kaboom.");
						};
					};
				};
				
				if(Math.random() < 0.01) { //1% chance each tick to lose interest
					pixel.following = false;
					//console.log("Meh.");
				};
			};

		//Several
	
			function commonMovableCriteria(name) {
				if(typeof(elements[name]) !== "object") {
					throw new Error(`Nonexistent element ${name}`);
				};
				var info = elements[name];
				//console.log(`${name} (${JSON.stringify(elements[name])})`);
				if(typeof(info.state) === "undefined") {
					var state = null;
				} else {
					var state = info.state;
				};
				if(typeof(info.category) === "undefined") {
					var category = "other";
				} else {
					var category = info.category;
				};
				if(excludedFairyElements.includes(name) || excludedCloudElements.includes(name)) {
					return false
				};
				if(elements[name].behavior && elements[name].behavior.toString() == elements.wall.behavior.toString() && !elements[name].tick) {
					return false;
				};
				if(["liquid","gas"].includes(state)) {
					return true;
				};
				if(info.movable) {
					return true;
				};
				if(backupCategoryWhitelist.includes(category)) {
					return true;
				};
				if(backupElementWhitelist.includes(name)) {
					return true;
				};
				if(category.includes("mudstone")) {
					return true;
				};
				return false;
			};

	//runAfterLoad calls
	
		//Bombs

			runAfterLoad(function() {
			  if(enabledMods.includes("mods/fey_and_more.js")) {
				amalgamatedBombFire += ",poisonwater".repeat(8);
				amalgamatedBombFire += ",mystic_fire".repeat(4);
				amalgamatedBombFire += ",firesea".repeat(6);
				amalgamatedBombFire += ",lektre".repeat(6);
			  };
			  if(enabledMods.includes("mods/Neutronium Mod.js")) {
				amalgamatedBombFire += ",flamer".repeat(3);
				amalgamatedBombFire += ",flamebomb".repeat(3);
				amalgamatedBombFire += ",toxin".repeat(3);
			  };
			  if(enabledMods.includes("mods/randomness.js")) {
				amalgamatedBombFire += ",burning_unnamed_gas".repeat(4);
				amalgamatedBombFire += ",warp".repeat(6);
				amalgamatedBombFire += ",bomb_3".repeat(3);
				amalgamatedBombFire += ",op_hottester_bomb".repeat(3);
				eLists.BOMB.push("unnamed_bomb");
				eLists.BOMB.push("warp_bomb");
			  };
			  if(enabledMods.includes("mods/glenn_gases.js")) {
				amalgamatedBombFire += ",electric_gas".repeat(3);
				amalgamatedBombFire += ",corrosive_gas".repeat(3);
				amalgamatedBombFire += ",iocalfaeus_gas".repeat(3);
				amalgamatedBombFire += ",ignited_gas".repeat(3);
				amalgamatedBombFire += ",finine".repeat(3);
				amalgamatedBombFire += ",acidic_vapour".repeat(3);
				amalgamatedBombFire += ",nitrous_gas".repeat(3);
				amalgamatedBombFire += ",void_gas".repeat(3);
				amalgamatedBombFire += ",black_damp".repeat(3);
			  };
			  if(enabledMods.includes("mods/some_tf_liquids.js")) {
				amalgamatedBombFire += ",blazing_pyrotheum".repeat(5);
				amalgamatedBombFire += ",tectonic_petrotheum".repeat(7);
				amalgamatedBombFire += ",resonant_ender".repeat(5);
			  };
			  if(enabledMods.includes("mods/chem.js")) {
				amalgamatedBombFire += ",FOOF".repeat(8);
			  };
			  if(enabledMods.includes("mods/the_ground.js")) {
				amalgamatedBombFire += ",liquid_irradium".repeat(7);
			  };
			  if(enabledMods.includes("mods/bioooze.js")) {
				amalgamatedBombFire += ",bioooze".repeat(8);
			  };
			});
			
		//Fairies

			runAfterLoad(function() {
				if(typeof(eLists.FAIRY) === "undefined") { eLists.FAIRY = [] };
				eLists.FAIRY.push("acid_fairy");
				eLists.FAIRY.push("oil_fairy");
				eLists.FAIRY.push("honey_fairy");
				fairyChoices = eLists.FAIRY;
				for(i = 0; i < eLists.FAIRY.length; i++) {
					var fairyName = eLists.FAIRY[i];
					if(!fairyChoices.includes(fairyName)) {
						fairyChoices.push(fairyName);
					};
				};
			});

	//Non-generated elements
	
		//Bombs

			elements.anti_bomb = {
				color: "#625c71",
				behavior: [
					"M2|M1 AND EX:10|M2",
					"XX|XX|XX",
					"XX|EX:10|XX",
				],
				category: "weapons",
				state: "solid",
				density: 1300,
				excludeRandom: true,
				cooldown: defaultCooldown,
			};

			elements.firebomb = {
				color: "#ee7e3e",
				tick: function(pixel) {
					if(!isEmpty(pixel.x,pixel.y-1,true)) { //[0][1] EX (ignore bounds)
						var newPixel = pixelMap[pixel.x][pixel.y-1];
						var newElement = newPixel.element;
						var newInfo = elements[newElement];
						if(newInfo.state !== "gas" && newElement !== pixel.element) {
							explodeAtPlus(pixel.x,pixel.y,10,"fire,fire,fire,fire,fire,greek_fire","fire",null,firebombFire);
						};
					};
					if(!isEmpty(pixel.x,pixel.y+1,true)) { //[2][1] EX (don't ignore bounds, non-bound case)
						var newPixel = pixelMap[pixel.x][pixel.y+1];
						var newElement = newPixel.element;
						var newInfo = elements[newElement];
						if(newInfo.state !== "gas" && newElement !== pixel.element) {
							explodeAtPlus(pixel.x,pixel.y,10,"fire,fire,fire,fire,fire,greek_fire","fire",null,firebombFire);
						};
					};
					if(outOfBounds(pixel.x,pixel.y+1)) { //[2][1] EX (don't ignore bounds, bound case)
						explodeAtPlus(pixel.x,pixel.y,10,"fire,fire,fire,fire,fire,greek_fire","fire",null,firebombFire);
					};
					if(!tryMove(pixel,pixel.x,pixel.y+1)) { //behaviors.POWDER
						Math.random() < 0.5 ? tryMove(pixel,pixel.x-1,pixel.y+1) : tryMove(pixel,pixel.x+1,pixel.y+1);
					};
				},
				category: "weapons",
				state: "solid",
				density: 1500,
				excludeRandom: true,
				desc: "An advanced incendiary weapon. <br/>To enable automatic bomb generation, set the generateBombs query parameter.",
			};

			elements.cluster_nuke = {
				color: "#e3f636",
				behavior: [
					"CR:radiation%5|EX:90>plasma,plasma,plasma,nuke,nuke,nuke,radiation,radiation,radiation,rad_steam,rad_steam,radiation,rad_steam AND CR:radiation%5|CR:radiation%5",
					"CR:radiation%5|XX|CR:radiation%5",
					"M2 AND CR:radiation%5|M1 AND EX:90>plasma,plasma,plasma,nuke,nuke,nuke,radiation,radiation,radiation,rad_steam,rad_steam,radiation,rad_steam AND CR:radiation%5|M2 AND CR:radiation%5",
				],
				category: "weapons",
				state: "solid",
				density: 1500,
				excludeRandom: true,
				desc: "It's a nuke that drops more nukes. <br/>To enable automatic bomb generation, set the generateBombs query parameter.",
			};
			
			elements.anti_bomb = {
				color: "#525c61",
				behavior: [
					"M2|M1 AND EX:10|M2",
					"XX|XX|XX",
					"XX|EX:10|XX",
				],
				category: "weapons",
				state: "solid",
				density: 1300,
				excludeRandom: true,
			};

			elements.electric_bomblet = {
				color: "#ffffff",
				behavior: [
					"SH%50|EX:8>electric AND SH%50|SH%50",
					"SH%50|EX:9>electric%0.5|SH%50",
					"M2 AND SH%50|M1 AND SH%50 AND EX:8>electric AND SW:electric|M2 AND SH%50",
				],
				category: "weapons",
				state: "solid",
				density: 1200,
				hidden: true,
				excludeRandom: true,
				hardness: 0.3,
			};

			elements.electric_cluster_bomb = {
				color: "#ffffff",
				behavior: [
					"SH%50|EX:8>electric_bomblet AND SH%50|SH%50",
					"SH%50|XX|SH%50",
					"M2 AND SH%50|M1 AND SH%50 AND EX:8>electric_bomblet AND SW:electric|M2 AND SH%50",
				],
				category: "weapons",
				state: "solid",
				density: 1800,
				hidden: true,
				excludeRandom: true,
				hardness: 0.3,
			};

			elements.radioactive_popper = {
				color: "#d6ce72",
				behavior: [
					"XX|EX:7>radiation|XX",
					"XX|XX|XX",
					"M2|M1 AND EX:7>radiation|M2",
				],
				category: "weapons",
				state: "solid",
				density: 1200,
				hidden: true,
				excludeRandom: true,
				hardness: 0.3,
				cooldown: 3,
			};

			elements.acid_bomb = {
				color: "#7d8a63",
				behavior: [
					"XX|EX:15>acid_gas|XX",
					"XX|XX|XX",
					"M2|M1 AND EX:15>acid_gas|M2",
				],
				category: "weapons",
				state: "solid",
				density: 1400,
				excludeRandom: true,
				cooldown: defaultCooldown,
			};

			elements.amalgamated_bomb = {
				color: ["#FF0000","#FF0000","#FFFF00","#FFFF00","#00FF00","#00FF00","#0000FF","#0000FF"],
				tick: function(pixel) {
					doDefaults(pixel);
					if(!isEmpty(pixel.x,pixel.y-1,true)) { //[0][1] EX (ignore bounds)
						var newPixel = pixelMap[pixel.x][pixel.y-1];
						var newElement = newPixel.element;
						var newInfo = elements[newElement];
						if(newInfo.state !== "gas" && newElement !== pixel.element) {
							explodeAtPlus(pixel.x,pixel.y,70,amalgamatedBombFire,amalgamatedBombFire);
						};
					};
					if(!isEmpty(pixel.x,pixel.y+1,true)) { //[2][1] EX (don't ignore bounds, non-bound case)
						var newPixel = pixelMap[pixel.x][pixel.y+1];
						var newElement = newPixel.element;
						var newInfo = elements[newElement];
						if(newInfo.state !== "gas" && newElement !== pixel.element) {
							explodeAtPlus(pixel.x,pixel.y,70,amalgamatedBombFire,amalgamatedBombFire);
						};
					};
					if(outOfBounds(pixel.x,pixel.y+1)) { //[2][1] EX (don't ignore bounds, bound case)
						explodeAtPlus(pixel.x,pixel.y,70,amalgamatedBombFire,amalgamatedBombFire);
					};
					if(!tryMove(pixel,pixel.x,pixel.y+1)) { //behaviors.POWDER
						Math.random() < 0.5 ? tryMove(pixel,pixel.x-1,pixel.y+1) : tryMove(pixel,pixel.x+1,pixel.y+1);
					};
				},
				category: "weapons",
				state: "solid",
				temp: 7065,
				density: 158000,
				excludeRandom: true,
			};

			elements.op_hottester_bomb = {
				color: "#cc436e",
				properties: {
					radius: 15, //just so people can edit it per pixel to be stupidly high
				},
				tick: function(pixel) {
					doDefaults(pixel);
					if(!isEmpty(pixel.x,pixel.y-1,true)) { //[0][1] EX (ignore bounds)
						var newPixel = pixelMap[pixel.x][pixel.y-1];
						var newElement = newPixel.element;
						var newInfo = elements[newElement];
						if(newInfo.state !== "gas" && newElement !== pixel.element) {
							explodeAtPlus(pixel.x,pixel.y,pixel.radius,"plasma","plasma",hotterBomb,hotterBomb,false);
						};
					};
					if(!isEmpty(pixel.x,pixel.y+1,true)) { //[2][1] EX (don't ignore bounds, non-bound case)
						var newPixel = pixelMap[pixel.x][pixel.y+1];
						var newElement = newPixel.element;
						var newInfo = elements[newElement];
						if(newInfo.state !== "gas" && newElement !== pixel.element) {
							explodeAtPlus(pixel.x,pixel.y,pixel.radius,"plasma","plasma",hotterBomb,hotterBomb,false);
						};
					};
					if(outOfBounds(pixel.x,pixel.y+1)) { //[2][1] EX (don't ignore bounds, bound case)
						explodeAtPlus(pixel.x,pixel.y,pixel.radius,"plasma","plasma",hotterBomb,hotterBomb,false);
					};
					if(!tryMove(pixel,pixel.x,pixel.y+1)) { //behaviors.POWDER
						Math.random() < 0.5 ? tryMove(pixel,pixel.x-1,pixel.y+1) : tryMove(pixel,pixel.x+1,pixel.y+1);
					};
				},
				category: "weapons",
				state: "solid",
				temp: 7065,
				density: 1900,
				excludeRandom: true,
			};

            elements.op_electromagneticester_emp = {				
                color: "#818253",
                tick: function(pixel) { //replace EMP
					if (pixel.start===pixelTicks) {return}
					if (!tryMove(pixel,pixel.x,pixel.y+1)) {
						if (outOfBounds(pixel.x,pixel.y+1) || (pixelMap[pixel.x][pixel.y+1].element!=="emp_bomb" && elements[pixelMap[pixel.x][pixel.y+1].element].state!=="gas")) {
							for (i = 0; i < currentPixels.length; i++) {
								var newPixel = currentPixels[i];
								if (newPixel.charge) {
									delete newPixel.charge;
									newPixel.chargeCD = 50;
								}
							}
							explodeAtPlus(pixel.x,pixel.y+1,20,"electric","smoke",empCharge,null,false);
						}
					}
					doDefaults(pixel);
				},
                maxSize: 1,
                category: "weapons",
                state: "solid",
                density: 1500,
                excludeRandom: true,
                alias: "overpowered electromagnetic pulse bomb",
                cooldown: defaultCooldown
            };

			if(enabledMods.includes("mods/the_ground.js")) { //uses things from that but not worth requiring for the whole mod
				elements.star_bomb = {
					color: "#fffbb5",
					properties: {
						radius: 50, //just so people can edit it per pixel to be stupidly high
					},
					tick: function(pixel) {
						var starFire = "stellar_plasma,stellar_plasma,stellar_plasma,liquid_stellar_plasma,liquid_stellar_plasma,plasma,plasma";
						var starSmoke = "light,light,radiation";
						doDefaults(pixel);
						if(!isEmpty(pixel.x,pixel.y-1,true)) { //[0][1] EX (ignore bounds)
							var newPixel = pixelMap[pixel.x][pixel.y-1];
							newPixel.temp += 10000000; //[0][1] HT:10000000
							var newElement = newPixel.element;
							var newInfo = elements[newElement];
							if(newInfo.state !== "gas" && newElement !== pixel.element) {
								explodeAtPlus(pixel.x,pixel.y,pixel.radius,starFire,starSmoke,starbombHeat,starbombHeat,false);
							};
						};
						if(!isEmpty(pixel.x,pixel.y+1,true)) { //[2][1] EX (don't ignore bounds, non-bound case)
							var newPixel = pixelMap[pixel.x][pixel.y+1];
							newPixel.temp += 10000000;
							var newElement = newPixel.element;
							var newInfo = elements[newElement];
							if(newInfo.state !== "gas" && newElement !== pixel.element) {
								explodeAtPlus(pixel.x,pixel.y,pixel.radius,starFire,starSmoke,starbombHeat,starbombHeat,false);
							};
						};
						if(outOfBounds(pixel.x,pixel.y+1)) { //[2][1] EX (don't ignore bounds, bound case)
							explodeAtPlus(pixel.x,pixel.y,pixel.radius,starFire,starSmoke,starbombHeat,starbombHeat,false);
						};
						if(!tryMove(pixel,pixel.x,pixel.y+1)) { //behaviors.POWDER
							Math.random() < 0.5 ? tryMove(pixel,pixel.x-1,pixel.y+1) : tryMove(pixel,pixel.x+1,pixel.y+1);
						};
					},
					category: "weapons",
					state: "solid",
					density: 3.663e33,
					excludeRandom: true,
					cooldown: defaultCooldown
				};
			};

		//Fairies
	
			elements.acid_fairy = {
				name: "acid fairy",
				color: ["#e2f777","#d1ff94","#d8f7c1"],
				behavior: [
					"XX|M1|M1",
					"XX|FX%5|XX",
					"XX|CR:acid%0.5 AND CR:fairy_dust%0.005 AND M1|M1",
				],
				state: "solid",
				category: "fey",
				desc: "Like the other fairies, but with acid. <br/>To enable automatic fairy generation, set the generateFairies query parameter.",
			}

			elements.oil_fairy = {
				name: "oil fairy",
				color: ["#636360","#a6956f","#a3816d","#cfc191"],
				behavior: [
					"XX|M1|M1",
					"XX|FX%5|XX",
					"XX|CR:oil%0.5 AND CR:fairy_dust%0.005 AND M1|M1",
				],
				state: "solid",
				category: "fey",
				desc: "Like the other fairies, but with oil. <br/>To enable automatic fairy generation, set the generateFairies query parameter.",
			}

			elements.honey_fairy = {
				name: "honey fairy",
				color: ["#ffeaa6","#ffe987","#f2e7c2"],
				behavior: [
					"XX|M1|M1",
					"XX|FX%5|XX",
					"XX|CR:honey%0.5 AND CR:fairy_dust%0.005 AND M1|M1",
				],
				state: "solid",
				category: "fey",
				desc: "Like the other fairies, but with sweet honey. <br/>To enable automatic fairy generation, set the generateFairies query parameter.",
			}

	//Sequential generations

		//Bombs

			for (var i = 2; i <= bombAmount + 1; i++) {
				elements[`bomb_${i}`] = {
					name: `bomb ${i}`,
					color: "#624c41",
					behavior: [
						`XX|EX:${5*(i+1)}>fire|XX`,
						"XX|XX|XX",
						`M2|M1 AND EX:${5*(i+1)}>fire|M2`,
					],
					state: "solid",
					density: 1300 * 8**((i-1)/2),
					excludeRandom:true,
					category: "weapons",
					desc: `${5*(i+1)/10} times the radius of the regular bomb`,
					cooldown: defaultCooldown,
				};
				eLists.BOMB.push(`bomb_${i}`);
			};

			for (var i = 2; i <= bombAmount + 1; i++) {
				elements[`anti_bomb_${i}`] = {
					color: "#625c71",
					behavior: [
						`M2|M1 AND EX:${5*(i+1)}>fire|M2`,
						"XX|XX|XX",
						`XX|EX:${5*(i+1)}>fire|XX`,
					],
					state: "solid",
					density: 1300 * 8**((i-1)/2),
					excludeRandom:true,
					category: "weapons",
					desc: `${5*(i+1)/10} times the radius of the regular anti-bomb`,
					cooldown: defaultCooldown,
				};
				eLists.BOMB.push(`anti_bomb_${i}`);
			};

		//Fairies

			//For statement by charPointer
			if(enabledMods.includes("mods/fey_and_more.js")) {
				for (var i = 2; i <= fairyAmount + 1; i++) {
				  elements[`${i}-fairy`] = {
					name: `${i}-fairy`,
					color: ["#33007a","#8e009f","#09009f"],
					behavior: [
					  "XX|M1|M1",
					  "XX|FX%5|XX",
					  `XX|CR:${i-1}-fairy%1 AND CR:fairy_dust%0.005 AND M1|M1`,
					],
					reactions: {
					  "glitter": { "elem1": `${i+1}-fairy`, "elem2": null }
					},
					state: "solid",
					excludeRandom:true,
					category: "fey",
					hidden: true,
				  }
				  if (i == fairyAmount) { elements[`${i}-fairy`]["reactions"] = {}; }
				  if (i == 2) elements[`${i}-fairy`]["behavior"][2] = `XX|CR:fairy%1 AND CR:fairy_dust%0.005 AND M1|M1`;
				  eLists.FAIRY.push(`${i}-fairy`);
				}
				//post-gen
				if(!elements.rainbow.reactions) { //rainbow promotes fairy
					elements.rainbow.reactions = {};
				};
				elements.rainbow.reactions.fairy = { "elem1": "2-fairy", "elem2": null }
				//remove last fairy's reaction
				delete elements[`${fairyAmount + 1}-fairy`].reactions
			};

	//Main generator functions

		//Bombs

			generateBomb = function(bombElements,isAfterScriptLoading=false,bombNumber=1) {//it can be a single element, though
				bombNumber = Math.max(0,bombNumber);
			
				//To specify an array bomb, have the array be inside another array.
				/*For reasons related to how element colors are loaded, if this function is being run from a JS mod file, isAfterScriptLoading should be false.
				Otherwise, you'll get TypeErrors for some reason when trying to place your bomb.  If this is being run after the game has loaded (e.g. in the console),
				then isAfterScriptLoading should be true or you might also get TypeErrors (this latter case was a bit inconsistent when I tested it, but 
				the former case wasn't. **isAfterScriptLoading must be false when this function is run from a JS mod file**.*/
				if(typeof(bombElements) === "string") { //it should be an array, so string check
					//console.log("String detected");
					if(bombElements.includes(",")) { //comma-separated string?
						//console.log("Splitting string to array");
						bombElements = bombElements.split(","); //,SS to array
					} else {
						//console.log("Wrapping string in array");
						bombElements = [bombElements]; //single string to array 
					};
				};
				var returns = [];
				for(aaf = 0; aaf < bombElements.length; aaf++) {
					var elementOfBomb = bombElements[aaf];
					//console.log("1",elementOfBomb);
					var allElementsHaveColors = ((elementOfBomb instanceof Array ? elementOfBomb : [elementOfBomb]).map(function(name) { return !!(elements[name]?.color)}).reduce(function(a,b) { return a*b }) == 1)
					if(!allElementsHaveColors) { continue };
					var startColor;
					var randomExcl = 0;
					//console.log(elementOfBomb);

					var bombName;

					//console.log("2-1");
					if(typeof(elementOfBomb === "string")) { //comma separated string check
						if(elementOfBomb.includes(",")) { //if it is
							elementOfBomb = elementOfBomb.split(","); //to array
							elementOfBomb = elementOfBomb.filter(function(e) { //strip nonexistent elements
								//console.log("3 a");
								return typeof(elements[e]) === "object";
							});
						};
					};
					if(Array.isArray(elementOfBomb)) {
						bombName = `${elementOfBomb.join("_")}_bomb`; //auto placer element name
						
						//array case color concatenator (bombs are always excludeRandom)
						startColor = [];
						//console.log(elementOfBomb);
						for(ll = 0; ll < elementOfBomb.length; ll++) {
							if(typeof(elements[elementOfBomb[ll]].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
								if(elements[elementOfBomb[ll]].excludeRandom) { //it it's true
									randomExcl = 1; //the whole array bomb is excluded (from spawnRandomBomb)
									//console.log("array nyet" + elementOfBomb);
								};
							};
							startColor = startColor.concat(elements[elementOfBomb[ll]].color);
						};
					} else { //they should all be strings, so here
						bombName = `${elementOfBomb}_bomb`; //auto placer element name
						startColor = elements[elementOfBomb].color;
						if(typeof(elements[elementOfBomb].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
							if(elements[elementOfBomb].excludeRandom) { //it it's true
								//console.log("nyet " + elementOfBomb);
								randomExcl = 1; //the bomb is excluded
							} else {
								//console.log("allow " + elementOfBomb);
								randomExcl = 0;
							};
						};
					};
					//console.log("e",bombName);

						//Color gen
					if(Array.isArray(startColor)) { //Average arrays, make colors rgb()
						startColor = averageRgbPrefixedColorArray(startColor);
					} else {
						startColor = rgbHexCatcher(startColor);
					};
					
					startColor = addColors(changeLuminance(changeSaturation(startColor,0.6,"multiply","hsl_json"),0.5,"multiply","rgb"),"rgb(24,0,0)","rgb");
					
					var newColorObject = rgbStringToObject(startColor);
					
						//End color gen
					
													//The bomb
					
					//console.log(elementOfBomb);
					var firstInfo, firstTemp;
					if(Array.isArray(elementOfBomb)) {
						firstInfo = elements[elementOfBomb[0]];
						firstTemp = airTemp;
						if(typeof(firstInfo.temp) !== "undefined") {
							firstTemp = firstInfo.temp;
						};
					} else {
						firstInfo = elements[elementOfBomb];
						firstTemp = airTemp;
						if(typeof(firstInfo.temp) !== "undefined") {
							firstTemp = firstInfo.temp;
						};
					};
					
					elementOfBomb = tryJoin(elementOfBomb,",");
					descElement = tryJoin(elementOfBomb,", ");
					
					//console.log(elementOfBomb);
					
					if(bombNumber !== 1) {
						bombName += `_${bombNumber}`;
					};
					
					if(!elementExists(bombName)) {
						elements[bombName] = {
							color: startColor,
							insulate: true,
							flippableX: true,
							colorObject: newColorObject,
							behavior: [
								["XX",`EX:${5*(bombNumber+1)}>${elementOfBomb}`,"XX"],
								["XX","XX","XX"],
								["M2",`M1 AND EX:${5*(bombNumber+1)}>${elementOfBomb}`,"M2"]
							],
							category: "auto_bombs",
							desc: `Explodes into ${descElement}<br/>Radius: ${5*(bombNumber+1)}`,
							temp: firstTemp,
							excludeRandom: true,
							autoType: "bomb",
						};
						if(typeof(eLists) === "undefined") {
							eLists = {};
						};
						if(typeof(eLists.BOMB) === "undefined") {
							eLists.BOMB = [];
						};
						eLists.BOMB.push(bombName);
						if(!randomExcl) {
							if(typeof(bombChoices) === "undefined") {
								bombChoices = []
							};
							if(!bombChoices.includes(bombName)) {
								bombChoices.push(bombName);
							};
						}
						if(isAfterScriptLoading) {
							elements[bombName].flippableX = true;
							elementCount++; //increment for new bomb element
							createElementButton(bombName);
							elements[bombName].id = nextid++;
							document.getElementById("extraInfo").innerHTML = "<small><p>There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.</p><p>©2021-" + new Date().getFullYear() + ". All Rights Reserved. <a href='https://r74n.com'>R74n</a></p></small>"; //update extra info counts (and the copyright year, due to the method used)
						};
					};
					returns.push(bombName);
				};
				return returns;
			};

		//Clouds

		//Clouds

			generateCloud = function(cloudElements,cloudType=0,isAfterScriptLoading=false) {//it can be a single element, though
				//To specify an array cloud, have the array be inside another array.
				/*For reasons related to how element colors are loaded, if this function is being run from a JS mod file, isAfterScriptLoading should be false.
				Otherwise, you'll get TypeErrors for some reason when trying to place your cloud.  If this is being run after the game has loaded (e.g. in the console),
				then isAfterScriptLoading should be true or you might also get TypeErrors (this latter case was a bit inconsistent when I tested it, but 
				the former case wasn't. **isAfterScriptLoading must be false when this function is run from a JS mod file**.*/
				if(cloudType !== "*") {
					if(typeof(cloudElements) === "string") { //it should be an array, so string check
						//console.log("String detected");
						if(cloudElements.includes(",")) { //comma-separated string?
							//console.log("Splitting string to array");
							cloudElements = cloudElements.split(","); //,SS to array
						} else {
							//console.log("Wrapping string in array");
							cloudElements = [cloudElements]; //single string to array 
						};
					};
					var returns = [];
					for(aaf = 0; aaf < cloudElements.length; aaf++) {
						var elementOfCloud = cloudElements[aaf];
						var allElementsHaveColors = ((elementOfCloud instanceof Array ? elementOfCloud : [elementOfCloud]).map(function(name) { return !!(elements[name]?.color)}).reduce(function(a,b) { return a*b }) == 1)
						if(!allElementsHaveColors) { continue };
						var startColor;
						var randomExcl = 0;
						//console.log("randomExcl set")
						//console.log(elementOfCloud);

						var cloudName, cloudPrefix, cloudBehavior;

						switch(cloudType) {
							case 0:
								cloudPrefix = "";
								cloudBehavior = behaviorGenerators.cloud(elementOfCloud);
								break;
							case 1:
								cloudPrefix = "heavy_";
								cloudBehavior = behaviorGenerators.heavy_cloud(elementOfCloud);
								break;
							case 2:
								cloudPrefix = "heavier_";
								cloudBehavior = behaviorGenerators.heavier_cloud(elementOfCloud);
								break;
							case 3:
								cloudPrefix = "heaviest_";
								cloudBehavior = behaviorGenerators.heaviest_cloud(elementOfCloud);
								break;
							case 4:
								cloudPrefix = "heaviester_";
								cloudBehavior = behaviorGenerators.heaviester_cloud(elementOfCloud);
								break;
							case 5:
								cloudPrefix = "heaviestest_";
								cloudBehavior = behaviorGenerators.heaviestest_cloud(elementOfCloud);
								break;
							default:
								throw new RangeError("Cloud type must be between 0 and 5");
						};

						if(typeof(elementOfCloud === "string")) { //comma separated string check
							if(elementOfCloud.includes(",")) { //if it is
								elementOfCloud = elementOfCloud.split(","); //to array
								elementOfCloud = elementOfCloud.filter(function(e) { //strip nonexistent elements
									return typeof(elements[e]) === "object";
								});
							};
						};
						if(Array.isArray(elementOfCloud)) {
							cloudName = `${elementOfCloud.join("_")}_cloud`; //auto placer element name
							
							//array case color concatenator and excludeRandom handler
							startColor = [];
							//console.log(elementOfCloud);
							for(ll = 0; ll < elementOfCloud.length; ll++) {
								if(typeof(elements[elementOfCloud[ll]].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
									if(elements[elementOfCloud[ll]].excludeRandom) { //it it's true
										randomExcl = 1; //the whole array cloud is excluded
										//console.log("array nyet" + elementOfCloud);
									};
								};
								//console.log(elementOfCloud[ll]);
								startColor = startColor.concat(elements[elementOfCloud[ll]].color);
							};
						} else { //they should all be strings, so here
							cloudName = `${elementOfCloud}_cloud`; //auto placer element name
							startColor = elements[elementOfCloud].color;
							if(typeof(elements[elementOfCloud].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
								if(elements[elementOfCloud].excludeRandom) { //it it's true
									//console.log("nyet " + elementOfCloud);
									randomExcl = 1; //the cloud is excluded
								} else {
									//console.log("allow " + elementOfCloud);
									randomExcl = 0;
								};
							};
						};
							//Color gen
						if(Array.isArray(startColor)) { //Average arrays, make colors rgb()
							startColor = averageRgbPrefixedColorArray(startColor);
						} else {
							startColor = rgbHexCatcher(startColor);
						};
						
						startColor = changeLuminance(
							changeSaturation(
								startColor,
								(0.4 + (cloudType/10)),
								"multiply",
								"hsl_json"
							),
							(0.6 - (cloudType/10)),
							"multiply",
							"rgb"
						);
						
						var newColorObject = rgbStringToObject(startColor);
						
							//End color gen
						
														//The cloud
						
						//console.log(elementOfCloud);
						var firstInfo, firstTemp;
						if(Array.isArray(elementOfCloud)) {
							firstInfo = elements[elementOfCloud[0]];
							firstTemp = airTemp;
							if(typeof(firstInfo.temp) !== "undefined") {
								firstTemp = firstInfo.temp;
							};
						} else {
							firstInfo = elements[elementOfCloud];
							firstTemp = airTemp;
							if(typeof(firstInfo.temp) !== "undefined") {
								firstTemp = firstInfo.temp;
							};
						};
						
						elementOfCloud = tryJoin(elementOfCloud,",");
						
						//console.log(elementOfCloud);
						
						cloudName = cloudPrefix + cloudName;
						
						if(elementExists(cloudName)) {
							cloudName = "auto_" + cloudName;
						};
						
						elements[cloudName] = {
							color: startColor,
							cloudType: elementOfCloud,
							insulate: true,
							colorObject: newColorObject,
							behavior: cloudBehavior,
							category: "clouds",
							temp: firstTemp,
							state: "gas",
							density: 0.6 * (2**cloudType),
							ignoreAir: true,
							conduct: 0.01 * (2**cloudType),
							autoType: "cloud",
						};
						
						if(cloudType === 4) { //column tick for heaviester clouds
							elements[cloudName].tick = function(pixel) {
								singleColumn(pixel,elements[pixel.element].cloudType,0.01,0.3);
							};
						};

						if(cloudType === 5) { //three-column tick for heaviestest clouds
							elements[cloudName].tick = function(pixel) {
								multiColumn(pixel,elements[pixel.element].cloudType,0.02,0.4,1);
							};
						};

						eLists.CLOUD.push(cloudName);

						if(!randomExcl) {
							if(typeof(cloudChoices) === "undefined") {
								cloudChoices = []
							};
							if(!cloudChoices.includes(cloudName)) {
								cloudChoices.push(cloudName);
							};
						}
						if(cloudIncludeRandom) {
							randomExcl ? elements[cloudName].excludeRandom = true : elements[cloudName].excludeRandom = false;
						} else {
							elements[cloudName].excludeRandom = true;
						};
						if(isAfterScriptLoading) {
							elementCount++; //increment for new cloud element
							createElementButton(cloudName);
							elements[cloudName].id = nextid++;
							document.getElementById("extraInfo").innerHTML = "<small><p>There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.</p><p>©2021-" + new Date().getFullYear() + ". All Rights Reserved. <a href='https://r74n.com'>R74n</a></p></small>"; //update extra info counts (and the copyright year, due to the method used)
						};
						returns.push(cloudName);
					};
					return returns;
				} else if(cloudType === "*") {
					var trueReturns = [];
					for(cloudTypeForIndex = 0; cloudTypeForIndex <= 5; cloudTypeForIndex++) {
						trueReturns = trueReturns.concat(generateCloud(cloudElements,cloudTypeForIndex,isAfterScriptLoading));
					};
					return trueReturns;
				};
			};

		//Creepers

			generateCreeper = function(creeperElements,isAfterScriptLoading=false) {//it can be a single element, though
				//To specify an array creeper, have the array be inside another array.
				/*For reasons related to how element colors are loaded, if this function is being run from a JS mod file, isAfterScriptLoading should be false.
				Otherwise, you'll get TypeErrors for some reason when trying to place your creeper.  If this is being run after the game has loaded (e.g. in the console),
				then isAfterScriptLoading should be true or you might also get TypeErrors (this latter case was a bit inconsistent when I tested it, but 
				the former case wasn't. **isAfterScriptLoading must be false when this function is run from a JS mod file**.
				If isAfterScriptLoading is true, buttons (depending on the hiding setting) will be added to the auto creeper category, the 3 new elements per creeper will be assigned IDs, and the footer will be updated with the increased element counts.*/
				if(typeof(creeperElements) === "string") { //it should be an array, so string check
					//console.log("String detected");
					if(creeperElements.includes(",")) { //comma-separated string?
						//console.log("Splitting string to array");
						creeperElements = creeperElements.split(","); //,SS to array
					} else {
						//console.log("Wrapping string in array");
						creeperElements = [creeperElements]; //single string to array 
					};
				};
				var returns = [];
				for(aaf = 0; aaf < creeperElements.length; aaf++) {
					var elementOfCreeper = creeperElements[aaf];
					var allElementsHaveColors = ((elementOfCreeper instanceof Array ? elementOfCreeper : [elementOfCreeper]).map(function(name) { return !!(elements[name]?.color)}).reduce(function(a,b) { return a*b }) == 1)
					if(!allElementsHaveColors) { continue };
					var startColor;
					var randomExcl = 0;
					//console.log("randomExcl set")
					//console.log(elementOfCreeper);

					var headName,bodyName,placerName,descElement;

					if(typeof(elementOfCreeper === "string")) { //comma separated string check
						if(elementOfCreeper.includes(",")) { //if it is
							elementOfCreeper = elementOfCreeper.split(","); //to array
							elementOfCreeper = elementOfCreeper.filter(function(e) { //strip nonexistent elements
								return typeof(elements[e]) === "object";
							});
						};
					};
					if(Array.isArray(elementOfCreeper)) {
						headName = `${elementOfCreeper.join("_")}_creeper_head`; //auto head element name
						bodyName = `${elementOfCreeper.join("_")}_creeper_body`; //auto body element name
						placerName = `${elementOfCreeper.join("_")}_creeper`; //auto placer element name
						descElement = elementOfCreeper.join(", "); //auto explosion element list
						
						//array case color concatenator and excludeRandom handler
						startColor = [];
						//console.log(elementOfCreeper);
						for(ll = 0; ll < elementOfCreeper.length; ll++) {
							if(typeof(elements[elementOfCreeper[ll]].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
								if(elements[elementOfCreeper[ll]].excludeRandom) { //it it's true
									randomExcl = 1; //the whole array creeper is excluded
									//console.log("array nyet" + elementOfCreeper);
								};
							};
							//console.log(elementOfCreeper[ll]);
							startColor = startColor.concat(elements[elementOfCreeper[ll]].color);
						};
					} else { //they should all be strings, so here
						headName = `${elementOfCreeper}_creeper_head`; //auto head element name
						bodyName = `${elementOfCreeper}_creeper_body`; //auto body element name
						placerName = `${elementOfCreeper}_creeper`; //auto placer element name
						descElement = elementOfCreeper; //auto explosion element
						startColor = elements[elementOfCreeper].color;
						if(typeof(elements[elementOfCreeper].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
							if(elements[elementOfCreeper].excludeRandom) { //it it's true
								//console.log("nyet " + elementOfCreeper);
								randomExcl = 1; //the creeper is excluded
							} else {
								//console.log("allow " + elementOfCreeper);
								randomExcl = 0;
							};
						};
					};
						//Color gen
					if(Array.isArray(startColor)) { //Average arrays, make colors rgb()
						startColor = averageRgbPrefixedColorArray(startColor);
					} else {
						startColor = rgbHexCatcher(startColor);
					};
					var preColor = rgbStringToHSL(startColor);
					var colorsArray = [preColor, preColor, preColor, preColor, preColor, preColor, preColor, preColor, preColor, preColor]
					var colorObjectArray = [];
					for(q = 0; q < hslOffsets.length; q++) {
						colorsArray[q] = addArraysInPairs(colorsArray[q],hslOffsets[q]);
						colorsArray[q] = hslToHex(...colorsArray[q]);
						colorObjectArray[q] = hexToRGB(colorsArray[q]); //outputs hex
						if(isAfterScriptLoading) { // if it's after the hex -> RGB conversion
							var coq = colorObjectArray[q]; //pull the object
							//console.log(coq.r);
							colorsArray[q] = `rgb(${coq.r},${coq.g},${coq.b})`; //and change to the RGB from its values
						};
					};
					
						//End color gen
					
					//console.log(`${headName}; ${bodyName}; ${placerName}; ${descElement}`)

													//Placer
					elements[placerName] = {
						movable: true,
						creeperType: elementOfCreeper,
						color: colorsArray,
						colorObject: colorObjectArray,
						category: "auto creepers",
						properties: {
							dead: false,
							dir: 1,
							panic: 0,
							following: false,
						},
						tick: function(pixel) {
							autoCreeperPlacerTick(pixel);
						},
						related: [bodyName,headName,"creeper"],
						desc: `Auto-generated creeper.<br/>Explodes into ${descElement}.`,
						autoType: "creeper",
					};
					
					eLists.CREEPER.push(placerName);
					
													//Body
					elements[bodyName] = {
						movable: true,
						creeperType: elementOfCreeper,
						color: colorsArray,
						colorObject: colorObjectArray,
						category: "auto creepers",
						hidden: true,
						excludeRandom: true,
						density: 1500,
						state: "solid",
						conduct: 25,
						tempHigh: 250,
						stateHigh: "cooked_meat",
						tempLow: -30,
						stateLow: "frozen_meat",
						burn: 10,
						burnTime: 250,
						burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
						breakInto: ["blood","gunpowder"],
						reactions: {
							"cancer": { "elem1":"cancer", "chance":0.005 },
							"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
							"plague": { "elem1":"plague", "chance":0.05 },
						},
						properties: {
							dead: false,
							dir: 1,
							panic: 0,
							charged: false,
							didChargeBlueTinted: false,
						},
						tick: function(pixel) {
							autoCreeperBodyTick(pixel);
						},
						autoType: "creeper",
					};

													//Head
					elements[headName] = {
						movable: true,
						creeperType: elementOfCreeper,
						color: colorsArray,
						colorObject: colorObjectArray,
						category: "auto creepers",
						hidden: true,
						excludeRandom: true,
						density: 1080,
						state: "solid",
						conduct: 25,
						tempHigh: 250,
						stateHigh: "cooked_meat",
						tempLow: -30,
						stateLow: "frozen_meat",
						burn: 10,
						burnTime: 250,
						burnInto: ["cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","cooked_meat","gunpowder"],
						breakInto: "blood",
						reactions: {
							"cancer": { "elem1":"cancer", "chance":0.005 },
							"radiation": { "elem1":["ash","meat","rotten_meat","cooked_meat"], "chance":0.4 },
							"plague": { "elem1":"plague", "chance":0.05 },
							"oxygen": { "elem2":"carbon_dioxide", "chance":0.5 },
						},
						properties: {
							dead: false,
							following: false,
							hissing: false,
							charged: false,
							didChargeBlueTinted: false,
						},
						tick: function(pixel) {
							autoCreeperHeadTick(pixel);
						},
						autoType: "creeper",
					};
					if(isAfterScriptLoading) {
						elementCount += 3; //placer, body, head
						createElementButton(placerName)
						if(settings["unhide"] === 0) { //hide some elements: body and head would be hidden, so only update hidden count
							hiddenCount += 2;
						} else if(settings["unhide"] === 1) { //unhide all elements: b/h would not be hidden, so only create their buttons
							createElementButton(bodyName);
							createElementButton(headName);
						} else if(settings["unhide"] === 2) {
							settings.unlocked[bodyName] ? createElementButton(bodyName) : hiddenCount++; //ternary: if headName is unlocked, create button, else increase hiddenCount
							settings.unlocked[headName] ? createElementButton(headName) : hiddenCount++; //above with headName
						};
						elements[placerName].id = nextid++; //set placer's id to nextid and then increment nextid 
						elements[bodyName].id = nextid++; //repeat with body and head
						elements[headName].id = nextid++;
						headBodyObject[headName] = bodyName;
						document.getElementById("extraInfo").innerHTML = "<small><p>There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.</p><p>©2021-" + new Date().getFullYear() + ". All Rights Reserved. <a href='https://r74n.com'>R74n</a></p></small>"; //update extra info counts (and the copyright year, due to the method used)
					};
					if(creeperIncludeRandom) {
						randomExcl ? elements[placerName].excludeRandom = true : elements[placerName].excludeRandom = false;
					} else {
						elements[placerName].excludeRandom = true;
					};
					if(!randomExcl) {
						//console.log("spawn enabling " + placerName);
						spawnCreepers.push(placerName);
					} else {
						//console.log("nyetted " + placerName);
					};
					returns.push(placerName);
				};
				return returns;
			};

		//Fairies

			generateFairy = function(fairyElements,isAfterScriptLoading=false) {//it can be a single element, though
				//To specify an array fairy, have the array be inside another array.
				/*For reasons related to how element colors are loaded, if this function is being run from a JS mod file, isAfterScriptLoading should be false.
				Otherwise, you'll get TypeErrors for some reason when trying to place your fairy.  If this is being run after the game has loaded (e.g. in the console),
				then isAfterScriptLoading should be true or you might also get TypeErrors (this latter case was a bit inconsistent when I tested it, but 
				the former case wasn't. **isAfterScriptLoading must be false when this function is run from a JS mod file**.*/
				if(typeof(fairyElements) === "string") { //it should be an array, so string check
					//console.log("String detected");
					if(fairyElements.includes(",")) { //comma-separated string?
						//console.log("Splitting string to array");
						fairyElements = fairyElements.split(","); //,SS to array
					} else {
						//console.log("Wrapping string in array");
						fairyElements = [fairyElements]; //single string to array 
					};
				};
				var returns = [];
				for(aaf = 0; aaf < fairyElements.length; aaf++) {
					var elementOfFairy = fairyElements[aaf];
					var allElementsHaveColors = ((elementOfFairy instanceof Array ? elementOfFairy : [elementOfFairy]).map(function(name) { return !!(elements[name]?.color)}).reduce(function(a,b) { return a*b }) == 1)
					if(!allElementsHaveColors) { continue };
					var startColor;
					var randomExcl = 0;
					var isNocheer = 0;
					//console.log("randomExcl set")
					//console.log(elementOfFairy);

					var fairyName;

					if(typeof(elementOfFairy === "string")) { //comma separated string check
						if(elementOfFairy.includes(",")) { //if it is
							elementOfFairy = elementOfFairy.split(","); //to array
							elementOfFairy = elementOfFairy.filter(function(e) { //strip nonexistent elements
								return typeof(elements[e]) === "object";
							});
						};
					};
					if(Array.isArray(elementOfFairy)) {
						fairyName = `${elementOfFairy.join("_")}_fairy`; //auto placer element name
						
						//array case color concatenator and excludeRandom handler
						startColor = [];
						//console.log(elementOfFairy);
						for(ll = 0; ll < elementOfFairy.length; ll++) {
							if(typeof(elements[elementOfFairy[ll]].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
								if(elements[elementOfFairy[ll]].excludeRandom) { //it it's true
									randomExcl = 1; //the whole array fairy is excluded
									//console.log("array nyet" + elementOfFairy);
								};
							};
							//console.log(elementOfFairy[ll]);
							startColor = startColor.concat(elements[elementOfFairy[ll]].color);
						};

						for(ll = 0; ll < elementOfFairy.length; ll++) {
							if(typeof(elements[elementOfFairy[ll]].nocheer !== "undefined")) { //if nocheer exists (prevent TypeError)
								if(elements[elementOfFairy[ll]].nocheer) { //it it's true
									isNocheer = 1; //the whole array fairy is excluded
									//console.log("array nyet" + elementOfFairy);
								};
							};
							//console.log(elementOfFairy[ll]);
							startColor = startColor.concat(elements[elementOfFairy[ll]].color);
						};
					} else { //they should all be strings, so here
						fairyName = `${elementOfFairy}_fairy`; //auto placer element name
						startColor = elements[elementOfFairy].color;
						if(typeof(elements[elementOfFairy].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
							if(elements[elementOfFairy].excludeRandom) { //it it's true
								//console.log("nyet " + elementOfFairy);
								randomExcl = 1; //the fairy is excluded
							} else {
								//console.log("allow " + elementOfFairy);
								randomExcl = 0;
							};
						};

						if(typeof(elements[elementOfFairy].nocheer !== "undefined")) { //if nocheer exists (prevent TypeError)
							if(elements[elementOfFairy].nocheer) { //it it's true
								//console.log("nyet " + elementOfFairy);
								isNocheer = 1; //the fairy is excluded
							} else {
								//console.log("allow " + elementOfFairy);
								isNocheer = 0;
							};
						};
					};
						//Color gen
					if(Array.isArray(startColor)) { //Average arrays, make colors rgb()
						startColor = averageRgbPrefixedColorArray(startColor);
					} else {
						startColor = rgbHexCatcher(startColor);
					};
					
					//console.log(`rgbStringToObject(${startColor}) from more_fairies.js`)
					var newColorObjectArray = [];			
					var newColorArray = [];

					for(i = 0; i < elements.fairy.color.length; i++) {
						var newFairyColorlet = elements.fairy.color[i];
						var newColor = multiplyColors(startColor,newFairyColorlet);
						var newColorJSON = multiplyColors(startColor,newFairyColorlet,"json");
						newColorArray.push(newColor);
						newColorObjectArray.push(newColorJSON);
					};

						//End color gen
					
													//The fairy
					
					//console.log(elementOfFairy);
					var firstInfo, firstTemp;
					if(Array.isArray(elementOfFairy)) {
						firstInfo = elements[elementOfFairy[0]];
						firstTemp = airTemp;
						if(typeof(firstInfo.temp) !== "undefined") {
							firstTemp = firstInfo.temp;
						};
					} else {
						firstInfo = elements[elementOfFairy];
						firstTemp = airTemp;
						if(typeof(firstInfo.temp) !== "undefined") {
							firstTemp = firstInfo.temp;
						};
					};
					
					elementOfFairy = tryJoin(elementOfFairy,",");
					
					//console.log(elementOfFairy);
					
					if(!elementExists(fairyName)) {
						elements[fairyName] = {
							color: newColorArray,
							insulate: true,
							flippableX: true,
							colorObject: newColorObjectArray,
							behavior: [
								["XX","M1","M1"],
								["XX","FX%5","XX"],
								["XX",`CR:${elementOfFairy}%0.5 AND CR:fairy_dust%0.005 AND M1`,"M1"]
							],
							category: "auto_fey",
							temp: firstTemp,
							hardness: 1,
							autoType: "fairy",
						};
						if(typeof(eLists) === "undefined") {
							eLists = {};
						};
						if(typeof(eLists.FAIRY) === "undefined") {
							eLists.FAIRY = [];
						};
						eLists.FAIRY.push(fairyName);
						if(!randomExcl) {
							if(typeof(fairyChoices) === "undefined") {
								fairyChoices = []
							};
							if(!fairyChoices.includes(fairyName)) {
								fairyChoices.push(fairyName);
							};
						}
						if(isNocheer) {
							elements[fairyName].nocheer = true;
						}
						if(fairyIncludeRandom) {
							randomExcl ? elements[fairyName].excludeRandom = true : elements[fairyName].excludeRandom = false;
						} else {
							elements[fairyName].excludeRandom = true;
						};
						if(isAfterScriptLoading) {
							elements[fairyName].flippableX = true;
							elementCount++; //increment for new fairy element
							if (settings.cheerful && elements[fairyName].nocheer) {
								elements[fairyName].hidden = true;
								hiddenCount++;
							} else {						
								createElementButton(fairyName);
							};
							elements[fairyName].id = nextid++;
							document.getElementById("extraInfo").innerHTML = "<small><p>There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.</p><p>©2021-" + new Date().getFullYear() + ". All Rights Reserved. <a href='https://r74n.com'>R74n</a></p></small>"; //update extra info counts (and the copyright year, due to the method used)
						};
					};
					returns.push(fairyName);
				};
				return returns;
			};

		//Spouts

			generateSpout = function(spoutElements,isAfterScriptLoading=false) {//it can be a single element, though
				//To specify an array spout, have the array be inside another array.
				/*For reasons related to how element colors are loaded, if this function is being run from a JS mod file, isAfterScriptLoading should be false.
				Otherwise, you'll get TypeErrors for some reason when trying to place your spout.  If this is being run after the game has loaded (e.g. in the console),
				then isAfterScriptLoading should be true or you might also get TypeErrors (this latter case was a bit inconsistent when I tested it, but 
				the former case wasn't. **isAfterScriptLoading must be false when this function is run from a JS mod file**.*/
				if(typeof(spoutElements) === "string") { //it should be an array, so string check
					//console.log("String detected");
					if(spoutElements.includes(",")) { //comma-separated string?
						//console.log("Splitting string to array");
						spoutElements = spoutElements.split(","); //,SS to array
					} else {
						//console.log("Wrapping string in array");
						spoutElements = [spoutElements]; //single string to array 
					};
				};
				var returns = [];
				for(aaf = 0; aaf < spoutElements.length; aaf++) {
					var elementOfSpout = spoutElements[aaf];
					var allElementsHaveColors = ((elementOfSpout instanceof Array ? elementOfSpout : [elementOfSpout]).map(function(name) { return !!(elements[name]?.color)}).reduce(function(a,b) { return a*b }) == 1)
					if(!allElementsHaveColors) { continue };
					var startColor;
					var randomExcl = 0;
					var isNocheer = 0;
					//console.log("randomExcl set")
					//console.log(elementOfSpout);

					var spoutName;

					if(typeof(elementOfSpout === "string")) { //comma separated string check
						if(elementOfSpout.includes(",")) { //if it is
							elementOfSpout = elementOfSpout.split(","); //to array
							elementOfSpout = elementOfSpout.filter(function(e) { //strip nonexistent elements
								return typeof(elements[e]) === "object";
							});
						};
					};
					if(Array.isArray(elementOfSpout)) {
						spoutName = `${elementOfSpout.join("_")}_spout`; //auto placer element name
						
						//array case color concatenator and excludeRandom handler
						startColor = [];
						//console.log(elementOfSpout);
						for(ll = 0; ll < elementOfSpout.length; ll++) {
							if(typeof(elements[elementOfSpout[ll]].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
								if(elements[elementOfSpout[ll]].excludeRandom) { //it it's true
									randomExcl = 1; //the whole array spout is excluded
									//console.log("array nyet" + elementOfSpout);
								};
							};
							//console.log(elementOfSpout[ll]);
							startColor = startColor.concat(elements[elementOfSpout[ll]].color);
						};

						for(ll = 0; ll < elementOfSpout.length; ll++) {
							if(typeof(elements[elementOfSpout[ll]].nocheer !== "undefined")) { //if nocheer exists (prevent TypeError)
								if(elements[elementOfSpout[ll]].nocheer) { //it it's true
									isNocheer = 1; //the whole array spout is excluded
									//console.log("array nyet" + elementOfSpout);
								};
							};
							//console.log(elementOfSpout[ll]);
							startColor = startColor.concat(elements[elementOfSpout[ll]].color);
						};
					} else { //they should all be strings, so here
						spoutName = `${elementOfSpout}_spout`; //auto placer element name
						startColor = elements[elementOfSpout].color;
						if(typeof(elements[elementOfSpout].excludeRandom !== "undefined")) { //if excludeRandom exists (prevent TypeError)
							if(elements[elementOfSpout].excludeRandom) { //it it's true
								//console.log("nyet " + elementOfSpout);
								randomExcl = 1; //the spout is excluded
							} else {
								//console.log("allow " + elementOfSpout);
								randomExcl = 0;
							};
						};

						if(typeof(elements[elementOfSpout].nocheer !== "undefined")) { //if nocheer exists (prevent TypeError)
							if(elements[elementOfSpout].nocheer) { //it it's true
								//console.log("nyet " + elementOfSpout);
								isNocheer = 1; //the spout is excluded
							} else {
								//console.log("allow " + elementOfSpout);
								isNocheer = 0;
							};
						};
					};
						//Color gen
					if(Array.isArray(startColor)) { //Average arrays, make colors rgb()
						startColor = averageRgbPrefixedColorArray(startColor);
					} else {
						startColor = rgbHexCatcher(startColor);
					};
					
					var newColorObject = rgbStringToObject(startColor);
					
						//End color gen
					
													//The spout
					
					//console.log(elementOfSpout);
					var firstInfo, firstTemp;
					if(Array.isArray(elementOfSpout)) {
						firstInfo = elements[elementOfSpout[0]];
						firstTemp = airTemp;
						if(typeof(firstInfo.temp) !== "undefined") {
							firstTemp = firstInfo.temp;
						};
					} else {
						firstInfo = elements[elementOfSpout];
						firstTemp = airTemp;
						if(typeof(firstInfo.temp) !== "undefined") {
							firstTemp = firstInfo.temp;
						};
					};
					
					elementOfSpout = tryJoin(elementOfSpout,",");
					
					//console.log(elementOfSpout);
					
					elements[spoutName] = {
						color: startColor,
						insulate: true,
						colorObject: newColorObject,
						behavior: [
							["XX",`CR:${elementOfSpout}`,"XX"],
							[`CR:${elementOfSpout}`,"XX",`CR:${elementOfSpout}`],
							["XX",`CR:${elementOfSpout}`,"XX"]
						],
						category: "spouts",
						temp: firstTemp,
						hardness: 1,
						autoType: "spout",
					};
					if(!randomExcl) {
						if(typeof(spoutChoices) === "undefined") {
							spoutChoices = []
						};
						if(!spoutChoices.includes(spoutName)) {
							spoutChoices.push(spoutName);
						};
					}
					if(spoutIncludeRandom) {
						randomExcl ? elements[spoutName].excludeRandom = true : elements[spoutName].excludeRandom = false;
					} else {
						elements[spoutName].excludeRandom = true;
					};
					if(isNocheer) {
						elements[spoutName].nocheer = true;
					}
					if(isAfterScriptLoading) {
						elementCount++; //increment for new spout element
						if (settings.cheerful && elements[spoutName].nocheer) {
							elements[spoutName].hidden = true;
							hiddenCount++;
						} else {						
							createElementButton(spoutName);
						};
						elements[spoutName].id = nextid++;
						document.getElementById("extraInfo").innerHTML = "<small><p>There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.</p><p>©2021-" + new Date().getFullYear() + ". All Rights Reserved. <a href='https://r74n.com'>R74n</a></p></small>"; //update extra info counts (and the copyright year, due to the method used)
					};
					
					eLists.SPOUT.push(spoutName);
					returns.push(spoutName);
				};
				return returns;
			};
	
	//Other runAfterAutogen
	
		//Bombs

			runAfterAutogen(function() {
				if(elementExists("vaporized_rock")) {
					elements.molten_dirt.tempHigh = 3000;
					elements.molten_dirt.stateHigh = "vaporized_rock";
				};
			});

		//Modless orphaned code that I don't want meeting La Maison

			runAfterAutogen(function() {
				var solidBlacklist = ["mistake", "birthpool", "firesea"]; //exclude these since they seem to be liquid
				
				solids = Object.keys(elements).filter(function(e) {
					return elements[e].category === "solids" && !solidBlacklist.includes(e);
				});
				
				for(i = 0; i < solids.length; i++) { //A lot of elements in solids, particularly metals, are missing a "state: solid".
					var solidName = solids[i]
					elements[solidName].state = "solid";
				};
			});

	//Mass generation calls

		//Bombs

			runAfterAutogen(function() {
				if(generateBombs) {
					var tempArray = Object.keys(elements);
					tempArray.push(["rock", "sand"]);
					generateBomb(tempArray,false)
				};
			});

		//Creepers

			runAfterAutogen(function() {
				if(generateCreepers) {
					var tempArray = Object.keys(elements);
					tempArray.push(["rock", "sand"]);
					generateCreeper(tempArray,false)
				};
			});

		//Several

			runAfterAutogen(function() {
				cloudElements = [...Object.keys(elements).filter(function(e) { //same criteria as spouts
					return (commonMovableCriteria(e,excludedCloudElements));
				}),["rock","sand"]];
				fairyElements = [...Object.keys(elements).filter(function(e) { //same criteria as spouts
					return (commonMovableCriteria(e,excludedFairyElements));
				}),["rock","sand"]];
				spoutElements = [...Object.keys(elements).filter(function(e) { //same criteria as spouts
					return (commonMovableCriteria(e,excludedSpoutElements));
				}),["rock","sand"]];
				if(generateFairies) { 
					generateFairy(fairyElements,false);
				};
				if(generateClouds) { 
					generateCloud(cloudElements,"*",false);
				};
				if(generateSpouts) { 
					generateSpout(spoutElements,false);
				};
			});

	//Random spawners

		//Bombs

			elements.spawn_random_bomb = {
				color: ["#141c23","#340f3c","#4b2d3f","#35463f","#244633","#460c1b","#294725","#34290c"],
				behavior: behaviors.WALL,
				category: "special",
				excludeRandom: true,
				tick: function(pixel) {
					if(bombChoices == undefined || bombChoices.length == 0) {
						deletePixel(pixel.x,pixel.y);
						return false;
					};
					changePixel(pixel,bombChoices[Math.floor(Math.random() * bombChoices.length)])
				},
			};

		//Clouds

			elements.spawn_random_cloud = {
				color: ["#3e5f8a","#a334ec","#ea96f9","#a6ecf6","#70ebc8","#d9286b","#7eed91","#a18b30"],
				behavior: behaviors.WALL,
				category: "special",
				excludeRandom: true,
				tick: function(pixel) {
					if(cloudChoices == undefined || cloudChoices.length == 0) {
						deletePixel(pixel.x,pixel.y);
						return false;
					};
					changePixel(pixel,cloudChoices[Math.floor(Math.random() * cloudChoices.length)])
				},
			};

		//Creepers

			elements.spawn_random_creeper = {
				color: colorOfRandomCreeper,
				behavior: behaviors.WALL,
				category: "special",
				excludeRandom: false, //see below
				movable: true,
				tick: function(pixel) {
					if(spawnCreepers == undefined || spawnCreepers.length == 0) {
						deletePixel(pixel.x,pixel.y);
						return false;
					};
					changePixel(pixel,spawnCreepers[Math.floor(Math.random() * spawnCreepers.length)]) //spawnCreepers is already excludeRandom filtered
				},
			};

		//Fairies

			elements.spawn_random_fairy = {
				color: ["#3e5f8a","#a334ec","#ea96f9","#a6ecf6","#70ebc8","#d9286b","#7eed91","#a18b30"],
				behavior: behaviors.WALL,
				category: "special",
				excludeRandom: true,
				tick: function(pixel) {
					if(fairyChoices == undefined || fairyChoices.length == 0) {
						deletePixel(pixel.x,pixel.y);
						return false;
					};
					changePixel(pixel,fairyChoices[Math.floor(Math.random() * fairyChoices.length)])
				},
			};
			
		//Spouts

			elements.spawn_random_spout = {
				color: ["#3e5f8a","#a334ec","#ea96f9","#a6ecf6","#70ebc8","#d9286b","#7eed91","#a18b30"],
				behavior: behaviors.WALL,
				category: "special",
				excludeRandom: true,
				tick: function(pixel) {
					if(spoutChoices == undefined || spoutChoices.length == 0) {
						deletePixel(pixel.x,pixel.y);
						return false;
					};
					changePixel(pixel,spoutChoices[Math.floor(Math.random() * spoutChoices.length)])
				},
			};

	//Other post-generation
	
		//Fairies
	
			//FAIRYKILL
			behaviors.FAIRYKILL_OLD = behaviors.FAIRYKILL;
			behaviors.FAIRYKILL = function(pixel) {
				if (pixel.start === pixelTicks) {return}
				if (pixel.charge && elements[pixel.element].behaviorOn) {
					pixelTick(pixel)
				}
				var ignore = (elements[pixel.element].ignore == "undefined" ? [] : elements[pixel.element].ignore);
				for(i = 0; i < adjacentCoords.length; i++) {
					var coord = adjacentCoords[i];
					var offsetX = coord[0];
					var offsetY = coord[1];
					var newX = pixel.x+offsetX;
					var newY = pixel.y+offsetY;
					if(!isEmpty(newX,newY,true)) {
						var newPixel = pixelMap[newX][newY];
						var newElement = newPixel.element;
						var isIgnored = (newElement === ignore || ignore.includes(newElement))
						if(eLists.FAIRY.includes(newElement) && !isIgnored) {
							deletePixel(newX,newY);
						};
					};
				};
				doDefaults(pixel);
			};
	
			//Add ignores
			var ignoreArray = ["acid", "iron", "silver", "steel", "tungstensteel", "void", "liquid_void", "chute", "vute", "drute", "drolute", "volute", "alkahest", "acid_gas"];
			for(l = 0; l < ignoreArray.length; l++) {
				var name = ignoreArray[l];
				var fairyName = `${ignoreArray[l]}_fairy`;
				if(elementExists(name) && elementExists(fairyName)) {
					var baseInfo = elements[name];
					if(typeof(baseInfo.ignore) === "undefined") {
						baseInfo.ignore = [];
					} else if(typeof(baseInfo.ignore) === "string") {
						baseInfo.ignore = [baseInfo.ignore];
					};
					baseInfo.ignore.push(fairyName);
				};
			};
	
			//Update FAIRYKILL elements
			var fairykillElements = ["iron", "silver", "steel", "tungstensteel"];
			for(q = 0; q < fairykillElements.length; q++) {
				var name = fairykillElements[q];
				if(elementExists(name)) {
					elements[name].behavior = behaviors.FAIRYKILL;
				};
			};
});
} else {
	if(!enabledMods.includes(runAfterAutogenMod))	{ enabledMods.splice(enabledMods.indexOf(modName),0,runAfterAutogenMod) };
	if(!enabledMods.includes(explodeAtPlusMod))		{ enabledMods.splice(enabledMods.indexOf(modName),0,explodeAtPlusMod) };
	if(!enabledMods.includes(libraryMod))			{ enabledMods.splice(enabledMods.indexOf(modName),0,libraryMod) };
	if(!enabledMods.includes(feyAndMoreMod))		{ enabledMods.splice(enabledMods.indexOf(modName),0,feyAndMoreMod) };
	if(!enabledMods.includes(mobsMod))				{ enabledMods.splice(enabledMods.indexOf(modName),0,mobsMod) };
	alert(`The "${runAfterAutogenMod}", "${libraryMod}", "${explodeAtPlusMod}", "${feyAndMoreMod}", and "${mobsMod}" mods are required; any missing mods in this list have been automatically inserted (reload for this to take effect).`)
	localStorage.setItem("enabledMods", JSON.stringify(enabledMods));
};
