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.
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.
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.
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.
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.
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}
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 = "

There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.

©2021-" + new Date().getFullYear() + ". All Rights Reserved. R74n

"; //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 = "

There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.

©2021-" + new Date().getFullYear() + ". All Rights Reserved. R74n

"; //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.
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 = "

There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.

©2021-" + new Date().getFullYear() + ". All Rights Reserved. R74n

"; //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 = "

There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.

©2021-" + new Date().getFullYear() + ". All Rights Reserved. R74n

"; //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 = "

There are " + elementCount + " elements, including " + hiddenCount + " hidden ones.

©2021-" + new Date().getFullYear() + ". All Rights Reserved. R74n

"; //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)); };