2022-10-09 10:55:07 -04:00
var modName = "mods/mobs.js" ;
2022-11-02 13:32:23 -04:00
var explodeAtPlusMod = "mods/explodeAtPlus.js" ;
2022-12-16 21:18:33 -05:00
var runAfterAutogenMod = "mods/runAfterAutogen and onload restructure.js" ;
2022-11-12 15:36:47 -05:00
var libraryMod = "mods/code_library.js" ;
2022-10-09 10:55:07 -04:00
2022-11-12 15:36:47 -05:00
if ( enabledMods . includes ( runAfterAutogenMod ) && enabledMods . includes ( explodeAtPlusMod ) && enabledMods . includes ( libraryMod ) ) {
2022-10-09 10:55:07 -04:00
//Prerequisite Functions and Variables
2022-11-11 14:22:36 -05:00
minimumCreeperTries = 3 ;
2022-11-02 13:32:23 -04:00
maximumCreeperTries = 3 ;
2022-11-11 14:22:36 -05:00
2022-11-02 13:32:23 -04:00
minimumZombieTries = 3 ;
2022-11-11 14:22:36 -05:00
maximumZombieTries = 3 ;
minimumSkeletonTries = 3 ;
maximumSkeletonTries = 3 ;
2022-11-02 13:32:23 -04:00
2022-11-14 17:07:30 -05:00
eLists . CREEPER = [ "creeper" , "angelic_creeper" , "hell_creeper" , "bombing_creeper" , "baby_creeper" ] ;
2022-10-09 10:55:07 -04:00
headBodyObject = {
"head" : "body" ,
"creeper_head" : "creeper_body" ,
"angelic_creeper_head" : "angelic_creeper_body" ,
"hell_creeper_head" : "hell_creeper_body" ,
"bombing_creeper_head" : "bombing_creeper_body" ,
"zombie_head" : "zombie_body" ,
2022-11-11 14:22:36 -05:00
"skeleton_head" : "skeleton_body" ,
"nothing_there_phase_3_head" : "nothing_there_phase_3_body" ,
2022-10-09 10:55:07 -04:00
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
var style = document . createElement ( 'style' ) ; //Initialize CSS for creeper spawning's status indicator
style . type = 'text/css' ;
style . id = 'creeperStatusStylesheet' ;
//initial style conditional branch
if ( typeof ( settings . creeperSpawning ) === "undefined" ) { //undefined (falsy but it needs special handling)
2022-10-02 15:09:48 -04:00
style . innerHTML = '.creeperStatus { color: #E11; text-decoration: none; }' ;
2022-10-09 10:55:07 -04:00
} else {
if ( ! settings . creeperSpawning ) { //falsy: red
style . innerHTML = '.creeperStatus { color: #E11; text-decoration: none; }' ;
} else if ( settings . creeperSpawning ) { //truthy: green
style . innerHTML = '.creeperStatus { color: #1E1; text-decoration: none; }' ;
} ;
2022-10-02 15:09:48 -04:00
} ;
2022-10-09 10:55:07 -04:00
document . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( style ) ;
2022-10-02 15:09:48 -04:00
2022-11-11 14:22:36 -05:00
function coordPyth ( xA , yA , xB , yB ) { //Distance function, used for explosion trigger
2022-10-09 10:55:07 -04:00
var a = Math . abs ( xB - xA ) ;
var b = Math . abs ( yB - yA ) ;
var c = Math . sqrt ( a * * 2 + b * * 2 ) ;
return c ;
} ;
2022-10-01 23:25:34 -04:00
2022-11-11 14:22:36 -05:00
function pythSpeed ( number1 , number2 ) {
return Math . sqrt ( number1 * * 2 + number2 * * 2 ) ;
} ;
2022-10-09 10:55:07 -04:00
function rgbColorBound ( number ) { //RGB bounding function, used for safety checking color changes
return Math . min ( 255 , Math . max ( 0 , number ) ) ;
} ;
2022-10-02 00:11:28 -04:00
2022-10-09 10:55:07 -04:00
function slBound ( number ) { //SL bounding function (not hue), same use as above
return Math . min ( 100 , Math . max ( 0 , number ) ) ;
} ;
2022-10-02 00:44:42 -04:00
2022-10-09 10:55:07 -04:00
function angelicUpwardVelocity ( pixel , x , y , radius , fire , smoke , power ) { //Angelic Creeper's effect, "compatible" with velocity.js by including the modified version of its code in itself
var info = elements [ pixel . element ]
if ( enabledMods . includes ( "mods/velocity.js" ) ) {
//console.log("yeet");
// set the pixel.vx and pixel.vy depending on the angle and power
if ( ! elements [ pixel . element ] . excludeRandom ) {
//console.log("LOOKS LIKE IT'S YEETING TIME!");
var angle = Math . atan2 ( pixel . y - y , pixel . x - x ) ;
//console.log(`angle calculated (${angle})`);
pixel . vx = Math . round ( ( pixel . vx | 0 ) + Math . cos ( angle ) * ( radius * power / 10 ) ) ;
//console.log(`vx calculated (${pixel.vx}) for pixel (${pixel.x},${pixel.y})`);
pixel . vy = 0 - Math . abs ( Math . round ( ( pixel . vy | 0 ) + Math . sin ( angle ) * ( radius * power / 4 ) ) + 4 ) ; //massively increased Y velocities even for objects below
//pixel.color = "rgb(255,0,0)";
//console.log(`vy calculated (${pixel.vy}) for pixel (${pixel.x},${pixel.y})`);
} ;
//console.log(`Velocities set`);
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
//console.log(`end`);
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
//afterFunction(pixel,x,y,radius,fire,smoke,power,damage);
function hellExplosionFire ( pixel , x , y , radius , fire , smoke , power , damage ) { //Angelic Creeper's effect, "compatible" with velocity.js by including the modified version of its code in itself
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 ]
if ( info . burn ) { //Light everything on fire
pixel . burning = true ;
pixel . burnStart = pixelTicks ;
pixel . temp += 10 ; //smoke prevention
} else if ( Math . random ( ) < 0.05 ) { //5%/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 ;
2022-10-02 14:12:08 -04:00
} ;
} ;
} ;
2022-11-02 13:32:23 -04:00
//explodeAtPlus moved to separate file
2022-10-02 12:40:42 -04:00
2022-10-09 10:55:07 -04:00
if ( typeof ( settings . creeperSpawning ) === "undefined" ) { //Default creeper setting
setSetting ( "creeperSpawning" , false ) ;
} ;
2022-10-02 15:09:48 -04:00
2022-10-09 10:55:07 -04:00
function updateCreeperPreferences ( ) { //Creeper setting handler
if ( settings . creeperSpawning ) { //If the setting is on
if ( typeof ( randomEvents . creeper ) !== "function" ) { //add the event if it's missing
randomEvents . creeper = function ( ) {
2022-10-09 11:49:45 -04:00
var amount = Math . floor ( ( Math . random ( ) * maximumCreeperTries ) + minimumCreeperTries ) ; //1-3
2022-10-09 10:55:07 -04:00
//In worldgen worlds, you can expect about half of this because about half of the world is pixels in it.
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
if ( settings . creeperSpawning ) { //setting validation
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable creepers
var element = spawnCreepers [ Math . floor ( Math . random ( ) * spawnCreepers . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents . creeper ; //self-disable
//substitute event
var event = randomEvents [ Object . keys ( randomEvents ) [ Math . floor ( Math . random ( ) * Object . keys ( randomEvents ) . length ) ] ] ;
event ( ) ;
break ;
2022-10-02 15:26:59 -04:00
} ;
} ;
2022-10-02 15:09:48 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
} else if ( ! settings . creeperSpawning ) { //and if it's off
if ( randomEvents . creeper ) { delete randomEvents . creeper } ; //delete it if it exists.
2022-10-02 15:09:48 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
function toggleCreeperSpawning ( ) { //Creeper toggle handler
if ( settings . creeperSpawning != true ) { //If it's false
setSetting ( "creeperSpawning" , true ) ; //make it true and update the status display CSS
updateCreeperPreferences ( ) ; //apply
document . getElementById ( "creeperStatusStylesheet" ) . innerHTML = '.creeperStatus { color: #1E1; text-decoration: underline; }' ; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element, like with find.js (RIP).
} else { //and the inverse if it's true
setSetting ( "creeperSpawning" , false ) ;
updateCreeperPreferences ( ) ;
document . getElementById ( "creeperStatusStylesheet" ) . innerHTML = '.creeperStatus { color: #E11; text-decoration: none; }' ;
} ;
2022-10-02 15:09:48 -04:00
} ;
2022-11-02 13:32:23 -04:00
//Functions used by Nothing There
function hasPixel ( x , y , elementInput ) {
if ( isEmpty ( x , y , true ) ) { //if empty, it can't have a pixel
return false ;
} else {
if ( elementInput . includes ( "," ) ) { //CSTA
elementInput = elementInput . split ( "," ) ;
} ;
if ( Array . isArray ( elementInput ) ) { //if element list
return elementInput . includes ( pixelMap [ x ] [ y ] . element ) ;
} else { //if single element
return pixelMap [ x ] [ y ] . element === elementInput ;
} ;
} ;
} ;
function breakPixel ( pixel , changetemp = false , defaultBreakIntoDust = false ) {
var info = elements [ pixel . element ] ;
if ( typeof ( info . breakInto ) === "undefined" ) {
if ( defaultBreakIntoDust ) {
if ( Math . random ( ) < defaultBreakIntoDust ) { changePixel ( pixel , "dust" , changetemp ) } ;
} ;
return defaultBreakIntoDust ;
} ;
var breakIntoElement = info . breakInto ;
if ( Array . isArray ( breakIntoElement ) ) {
breakIntoElement = breakIntoElement [ Math . floor ( Math . random ( ) * breakIntoElement . length ) ]
} ;
2023-06-28 14:37:03 -04:00
if ( typeof ( breakIntoElement ) === "undefined" ) {
deletePixel ( pixel . x , pixel . y ) ;
return true ;
} ;
2022-11-02 13:32:23 -04:00
changePixel ( pixel , breakIntoElement , changetemp )
return true ;
} ;
defaultHardness = 0 ;
2022-11-11 14:22:36 -05:00
function arrowAltTb ( pixel , breakChanceMultiplier , changetemp = false , defaultBreakIntoDust = false ) {
var info = elements [ pixel . element ] ;
var hardness = defaultHardness ;
if ( typeof ( info . hardness ) === "number" ) {
hardness = info . hardness ;
} ;
hardness = 1 - hardness ; //invert hardness, so a hardness of 0 becomes a 100% chance and a hardness of 1 becomes a 0% chance
hardness *= breakChanceMultiplier ;
if ( Math . random ( ) < hardness ) {
return breakPixel ( pixel , changetemp = false , defaultBreakIntoDust = false ) ;
} else {
return false ;
} ;
} ;
2022-11-03 09:15:57 -04:00
function nothingThereBulletMovement ( pixel , x , y ) {
2022-11-02 13:32:23 -04:00
if ( ! tryMove ( pixel , x , y ) ) {
if ( ! isEmpty ( x , y , true ) ) {
var thisDensity = elements [ pixel . element ] . density ;
var newPixel = pixelMap [ x ] [ y ] ;
var newElement = newPixel . element ;
var newInfo = elements [ newElement ] ;
2022-11-03 09:15:57 -04:00
var newHardness = 0 ;
2022-11-02 13:32:23 -04:00
if ( nothingThereBulletExcludedElements . includes ( newElement ) ) {
return false ;
} ;
2022-11-03 09:15:57 -04:00
if ( typeof ( newInfo . hardness ) === "number" ) {
newHardness = newInfo . hardness ;
//it's inverted later
} ;
if ( typeof ( newInfo . state ) === "undefined" && newElement !== pixel . element ) { //Copy-paste of "break" code
if ( Math . random ( ) < ( ( 1 - newHardness ) * * 0.6 ) ) {
swapPixels ( pixel , newPixel ) ;
//console.log(`nothingThereBulletMovement: Breaking pixel (${newPixel.element}, ${newPixel.x}, ${newPixel.y}))`)
breakPixel ( newPixel , false , 0.3 ) ;
return true ;
} else {
deletePixel ( pixel . x , pixel . y ) ;
return false ;
} ;
2022-11-02 13:32:23 -04:00
} else {
if ( newElement == pixel . element ) {
swapPixels ( pixel , newPixel ) ;
2022-11-03 09:15:57 -04:00
return true ;
2022-11-02 13:32:23 -04:00
} else if ( newInfo . state == "gas" ) {
swapPixels ( pixel , newPixel ) ;
2022-11-03 09:15:57 -04:00
return true ;
2022-11-02 13:32:23 -04:00
} else if ( newInfo . state == "liquid" ) {
var newDensity = 1000 ;
if ( typeof ( newInfo . density ) === "number" ) {
newDensity = newInfo . density ;
//console.log(`density ${newInfo.density} for ${newElement}`);
//} else {
//console.log(`undef density for ${newElement}, 1000 default`);
} ;
//console.log(`thisDensity: ${thisDensity}`);
//console.log(`newDensity: ${newDensity}`);
var chance = thisDensity / ( thisDensity + newDensity ) ;
//console.log(`${newElement}, ${chance}`)
if ( Math . random ( ) < chance ) {
swapPixels ( pixel , newPixel ) ;
} ;
2022-11-03 09:15:57 -04:00
return true ;
2022-11-02 13:32:23 -04:00
} else if ( newInfo . state == "solid" ) {
2022-11-03 09:15:57 -04:00
if ( Math . random ( ) < ( ( 1 - newHardness ) * * 0.6 ) ) {
swapPixels ( pixel , newPixel ) ;
//console.log(`nothingThereBulletMovement: Breaking pixel (${newPixel.element}, ${newPixel.x}, ${newPixel.y}))`)
breakPixel ( newPixel , false , 0.3 ) ;
return true ;
} else {
deletePixel ( pixel . x , pixel . y ) ;
return false ;
} ;
2022-11-02 13:32:23 -04:00
} ;
} ;
} else {
return false ;
} ;
} else {
return true ;
} ;
} ;
//End NT functions
nothingThereBulletExcludedElements = [ "wall" , "nothing_there_phase_1" , "nothing_there_phase_2" , "nothing_there_phase_3_body" , "nothing_there_phase_3_head" , "nothing_there_cleaver" , "nothing_there_mace" ] ;
2022-10-02 15:09:48 -04:00
2022-10-09 10:55:07 -04:00
enemyHumanoidArray = [ "head" , "body" ] //just in case
2022-10-09 13:20:18 -04:00
spawnCreepers = [ "creeper" , "baby_creeper" , "angelic_creeper" , "bombing_creeper" , "hell_creeper" ] ;
2022-10-09 10:55:07 -04:00
if ( settings . creeperSpawning ) { //creeper spawning option
randomEvents . creeper = function ( ) {
2022-10-09 11:49:45 -04:00
var amount = Math . floor ( ( Math . random ( ) * maximumCreeperTries ) + minimumCreeperTries ) ; //1-3
2022-10-09 10:55:07 -04:00
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
if ( settings . creeperSpawning ) { //setting validation
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable creepers
var element = spawnCreepers [ Math . floor ( Math . random ( ) * spawnCreepers . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents . creeper ; //self-disable
//substitute event
var event = randomEvents [ Object . keys ( randomEvents ) [ Math . floor ( Math . random ( ) * Object . keys ( randomEvents ) . length ) ] ] ;
event ( ) ;
break ;
2022-10-02 15:26:59 -04:00
} ;
} ;
2022-10-02 15:09:48 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
standaloneSpawnCreeper = function ( amount = 1 ) {
/ * T h e a m o u n t i s t h e m a x i m u m a m o u n t o f * a t t e m p t s * . O f t e n , l e s s c r e e p e r s w i l l s p a w n d u e t o t h i n g s i n t h e w a y .
In a generated world , which uses half of the space , you can expect about half of this number to spawn . * /
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable creepers
var element = spawnCreepers [ Math . floor ( Math . random ( ) * spawnCreepers . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
2022-10-04 10:09:21 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
//Prerequisite Functions and Variables
function headHasBody ( pixel ) {
var pX = pixel . x ;
var pY = pixel . y ;
//console.log("Checking head for body");
if ( Object . keys ( headBodyObject ) . includes ( pixel . element ) ) {
//console.log("The head has a corresponding body element.");
if ( typeof ( pixelMap [ pX ] [ pY + 1 ] ) === "undefined" ) {
//console.log("The body's place is empty.");
return false ;
} else {
var bodyPixel = pixelMap [ pX ] [ pY + 1 ] ;
//console.log("The body's place is not empty.");
return ( bodyPixel . element === headBodyObject [ pixel . element ] ) ;
} ;
2022-10-06 14:15:16 -04:00
} else {
2022-10-09 10:55:07 -04:00
//console.log("The head does not have corresponding body element.");
return null ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
function bodyHasHead ( pixel ) {
var pX = pixel . x ;
var pY = pixel . y ;
//console.log("Checking body for head");
if ( Object . values ( headBodyObject ) . includes ( pixel . element ) ) {
//console.log("The body has a corresponding head element.");
if ( typeof ( pixelMap [ pX ] [ pY - 1 ] ) === "undefined" ) {
//console.log("The head's place is empty.");
return false ;
} else {
var headPixel = pixelMap [ pX ] [ pY - 1 ] ;
//console.log("The head's place is not empty.");
return ( headPixel . element === getKeyByValue ( headBodyObject , pixel . element ) ) ;
} ;
2022-10-06 14:15:16 -04:00
} else {
2022-10-09 10:55:07 -04:00
//console.log("The body does not have corresponding head element.");
return null ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
function zombifyHuman ( pixel ) {
var pX = pixel . x ;
var pY = pixel . y ;
if ( ! [ "head" , "body" ] . includes ( pixel . element ) ) {
//console.log("Not part of a human");
return false ;
2022-10-06 14:15:16 -04:00
} else {
2022-10-09 10:55:07 -04:00
if ( pixel . element === "head" ) {
//console.log("Head");
if ( headHasBody ( pixel ) ) {
//console.log("There's also a body");
var body = pixelMap [ pX ] [ pY + 1 ] ;
changePixel ( body , "zombie_body" , false ) ;
//console.log("Body turned (head path)");
} ;
changePixel ( pixel , "zombie_head" ) ;
//console.log("Head turned (head path)");
} else {
//console.log("Not head (i.e. body)");
if ( bodyHasHead ( pixel ) ) {
//console.log("There's also a head");
var head = pixelMap [ pX ] [ pY - 1 ] ;
changePixel ( head , "zombie_head" , false ) ;
//console.log("Head turned (body path)");
} ;
changePixel ( pixel , "zombie_body" ) ;
//console.log("Body turned (body path)");
} ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
function dezombifyHuman ( pixel ) {
var pX = pixel . x ;
var pY = pixel . y ;
if ( ! [ "zombie_head" , "zombie_body" ] . includes ( pixel . element ) ) {
return false ;
2022-10-06 14:15:16 -04:00
} else {
2022-10-09 10:55:07 -04:00
if ( pixel . element === "zombie_head" ) {
if ( headHasBody ( pixel ) ) {
var body = pixelMap [ pX ] [ pY + 1 ] ;
changePixel ( body , "body" , false ) ;
} ;
changePixel ( pixel , "head" ) ;
} else {
if ( bodyHasHead ( pixel ) ) {
var head = pixelMap [ pX ] [ pY - 1 ] ;
changePixel ( head , "head" , false ) ;
} ;
changePixel ( pixel , "body" ) ;
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
2022-11-11 15:22:19 -05:00
elements . spawner = {
color : "#1c3038" ,
breakInto : [ "steel" , "steel" , "smoke" , null , null , null , null , null ] ,
properties : {
spawnCounter : 0 ,
spawnTime : 160 ,
spawn : null ,
squadiusX : 4 ,
squadiusY : 4 ,
spawnTries : 4 ,
//spawnRangeMax: null, //Disabled by default for performance and because I can't think of how to make it count MPL elements towards the limit
} ,
tick : function ( pixel ) {
//validation
if ( Array . isArray ( pixel . spawn ) ) {
pixel . spawn = pixel . spawn . filter ( function ( e ) { return elementExists ( e ) } ) ;
if ( pixel . spawn . length == 0 ) {
pixel . spawn = null ;
} ;
} else {
if ( ! elementExists ( pixel . spawn ) ) {
pixel . spawn = null ;
} ;
} ;
if ( pixel . spawn === null ) {
return false ;
} ;
if ( pixel . spawnCounter <= 0 ) {
//var pixelsOfSpawnElement = 0;
var newSpawn = pixel . spawn ;
if ( Array . isArray ( newSpawn ) ) {
newSpawn = newSpawn [ Math . floor ( Math . random ( ) * newSpawn . length ) ] ;
} ;
var xForMin = - 1 * pixel . squadiusX ;
var xForMax = pixel . squadiusX + 1 ;
var yForMin = - 1 * pixel . squadiusY ;
var yForMax = pixel . squadiusY + 1 ;
/ * i f ( p i x e l . s p a w n R a n g e M a x ! = = n u l l ) {
for ( xOffset = xForMin ; xOffset < xForMax ; xOffset ++ ) {
for ( yOffset = yForMin ; yOffset < yForMax ; yOffset ++ ) {
var newX = pixel . x + xOffset ;
var newY = pixel . y + yOffset ;
if ( isEmpty ( newX , newY , true ) || outOfBounds ( newX , newY ) ) {
continue ;
} ;
newPixel = pixelMap [ newX ] [ newY ] ;
if ( newPixel . element == pixel . spawn || pixel . spawn . includes ( newPixel . element ) ) {
pixelsOfSpawnElement ++ ;
} ;
} ;
} ;
if ( pixelsOfSpawnElement > pixel . spawnRangeMax ) {
return false ;
} ;
} ; * /
for ( s = 0 ; s < pixel . spawnTries ; s ++ ) {
var randomX = pixel . x + randomIntegerBetweenTwoValues ( 0 - pixel . squadiusX , pixel . squadiusX ) ;
var randomY = pixel . y + randomIntegerBetweenTwoValues ( 0 - pixel . squadiusY , pixel . squadiusY ) ;
if ( isEmpty ( randomX , randomY , false ) ) {
createPixel ( newSpawn , randomX , randomY ) ;
} ;
} ;
pixel . spawnCounter = pixel . spawnTime ;
} else {
pixel . spawnCounter -- ;
} ;
} ,
hardness : 0.7 ,
state : "solid" ,
}
if ( enabledMods . includes ( "mods/fey_and_more.js" ) ) {
elements . spawner . breakInto . push ( "magic" ) ;
} ;
2022-10-09 10:55:07 -04:00
elements . frozen _rotten _meat = {
color : [ "#8FB588" , "#8FA888" ] ,
behavior : [
"XX|CR:plague,stench,stench%0.125 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85|XX" ,
"SP%99 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85|XX|SP%99 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85" ,
"XX|M1 AND CH:meat>rotten_meat%1 AND CH:frozen_meat>frozen_rotten_meat%0.85|XX" ,
] ,
temp : - 18 ,
tempHigh : 0 ,
stateHigh : "rotten_meat" ,
category : "food" ,
hidden : true ,
state : "solid" ,
density : 1037.5 ,
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
elements . rotten _meat . tempLow = - 18 ;
elements . rotten _meat . stateLow = "frozen_rotten_meat" ;
elements . zombie _blood = {
color : [ "#d18228" , "#9a9e2f" ] ,
behavior : behaviors . LIQUID ,
reactions : {
"vaccine" : { "elem2" : null , "chance" : 0.01 } ,
"plague" : { "elem2" : null , "chance" : 0.01 } ,
"virus" : { "elem2" : null , "chance" : 0.01 } ,
"cancer" : { "elem1" : "cancer" , "chance" : 0.02 } ,
/ * " r a t " : { " e l e m 2 " : " i n f e c t i o n " , " c h a n c e " : 0 . 0 7 5 } ,
"flea" : { "elem1" : "infection" , "chance" : 0.03 } ,
"dirt" : { "elem1" : null , "elem2" : "mud" } ,
"sand" : { "elem1" : null , "elem2" : "wet_sand" } ,
"mercury" : { "elem1" : "infection" , "elem2" : null , "chance" : 0.05 } ,
"carbon_dioxide" : { "elem2" : null , "chance" : 0.05 } ,
"alcohol" : { "elem1" : [ null , "dna" ] , "chance" : 0.02 } , * /
"oxygen" : { "elem2" : null , "chance" : 0.04 } ,
"blood" : { "elem2" : "zombie_blood" , "chance" : 0.1 } ,
} ,
viscosity : 30 ,
tempHigh : 127.55 ,
stateHigh : [ "steam" , "salt" , "oxygen" , "plague" ] ,
tempLow : 0 ,
category : "liquids" ,
state : "liquid" ,
density : 1160 ,
stain : 0.06 ,
tick : function ( pixel ) {
if ( Math . random ( ) < 0.2 ) {
var pX = pixel . x ;
var pY = pixel . y ;
for ( i = 0 ; i < adjacentCoords . length ; i ++ ) {
var coord = adjacentCoords [ i ] ;
var oX = coord [ 0 ] ;
var oY = coord [ 1 ] ;
var nX = pX + oX ;
var nY = pY + oY ;
if ( isEmpty ( nX , nY , true ) ) {
continue ;
} else {
var newPixel = pixelMap [ nX ] [ nY ] ;
var newElement = newPixel . element ;
if ( enemyHumanoidArray . includes ( newElement ) ) {
if ( Math . random ( ) < 0.1 ) { zombifyHuman ( newPixel ) } ;
} ;
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
} ,
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
var style = document . createElement ( 'style' ) ; //Initialize CSS for zombie spawning's status indicator
style . type = 'text/css' ;
style . id = 'zombieStatusStylesheet' ;
//initial style conditional branch
if ( typeof ( settings . zombieSpawning ) === "undefined" ) { //undefined (falsy but it needs special handling)
2022-10-06 14:15:16 -04:00
style . innerHTML = '.zombieStatus { color: #E11; text-decoration: none; }' ;
2022-10-09 10:55:07 -04:00
} else {
if ( ! settings . zombieSpawning ) { //falsy: red
style . innerHTML = '.zombieStatus { color: #E11; text-decoration: none; }' ;
} else if ( settings . zombieSpawning ) { //truthy: green
style . innerHTML = '.zombieStatus { color: #1E1; text-decoration: none; }' ;
} ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
document . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( style ) ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
if ( typeof ( settings . zombieSpawning ) === "undefined" ) { //Default zombie setting
setSetting ( "zombieSpawning" , false ) ;
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
function updateZombiePreferences ( ) { //Zombie setting handler
if ( settings . zombieSpawning ) { //If the setting is on
if ( typeof ( randomEvents . zombie ) !== "function" ) { //add the event if it's missing
randomEvents . zombie = function ( ) {
2022-10-09 11:49:45 -04:00
var amount = Math . floor ( ( Math . random ( ) * maximumZombieTries ) + minimumZombieTries ) ; //1-3
2022-10-09 10:55:07 -04:00
//In worldgen worlds, you can expect about half of this because about half of the world is pixels in it.
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
if ( settings . zombieSpawning ) { //setting validation
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable zombies
var element = spawnZombies [ Math . floor ( Math . random ( ) * spawnZombies . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents . zombie ; //self-disable
//substitute event
var event = randomEvents [ Object . keys ( randomEvents ) [ Math . floor ( Math . random ( ) * Object . keys ( randomEvents ) . length ) ] ] ;
event ( ) ;
break ;
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
} else if ( ! settings . zombieSpawning ) { //and if it's off
if ( randomEvents . zombie ) { delete randomEvents . zombie } ; //delete it if it exists.
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
function toggleZombieSpawning ( ) { //Zombie toggle handler
if ( settings . zombieSpawning != true ) { //If it's false
setSetting ( "zombieSpawning" , true ) ; //make it true and update the status display CSS
updateZombiePreferences ( ) ; //apply
document . getElementById ( "zombieStatusStylesheet" ) . innerHTML = '.zombieStatus { color: #1E1; text-decoration: underline; }' ; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element, like with find.js (RIP).
} else { //and the inverse if it's true
setSetting ( "zombieSpawning" , false ) ;
updateZombiePreferences ( ) ;
document . getElementById ( "zombieStatusStylesheet" ) . innerHTML = '.zombieStatus { color: #E11; text-decoration: none; }' ;
} ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
spawnZombies = [ "zombie" , "baby_zombie" ] ;
if ( settings . zombieSpawning ) { //zombie spawning option
randomEvents . zombie = function ( ) {
2022-10-09 11:49:45 -04:00
var amount = Math . floor ( ( Math . random ( ) * maximumZombieTries ) + minimumZombieTries ) ; //1-3
2022-10-09 10:55:07 -04:00
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
if ( settings . zombieSpawning ) { //setting validation
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable zombies
var element = spawnZombies [ Math . floor ( Math . random ( ) * spawnZombies . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents . zombie ; //self-disable
//substitute event
var event = randomEvents [ Object . keys ( randomEvents ) [ Math . floor ( Math . random ( ) * Object . keys ( randomEvents ) . length ) ] ] ;
event ( ) ;
break ;
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
standaloneSpawnZombie = function ( amount = 1 ) {
/ * T h e a m o u n t i s t h e m a x i m u m a m o u n t o f * a t t e m p t s * . O f t e n , l e s s z o m b i e s w i l l s p a w n d u e t o t h i n g s i n t h e w a y .
In a generated world , which uses half of the space , you can expect about half of this number to spawn . * /
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable zombies
var element = spawnZombies [ Math . floor ( Math . random ( ) * spawnZombies . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-11-11 14:22:36 -05:00
var style = document . createElement ( 'style' ) ; //Initialize CSS for skeleton spawning's status indicator
style . type = 'text/css' ;
style . id = 'skeletonStatusStylesheet' ;
//initial style conditional branch
if ( typeof ( settings . skeletonSpawning ) === "undefined" ) { //undefined (falsy but it needs special handling)
style . innerHTML = '.skeletonStatus { color: #E11; text-decoration: none; }' ;
} else {
if ( ! settings . skeletonSpawning ) { //falsy: red
style . innerHTML = '.skeletonStatus { color: #E11; text-decoration: none; }' ;
} else if ( settings . skeletonSpawning ) { //truthy: green
style . innerHTML = '.skeletonStatus { color: #1E1; text-decoration: none; }' ;
} ;
} ;
document . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( style ) ;
if ( typeof ( settings . skeletonSpawning ) === "undefined" ) { //Default skeleton setting
setSetting ( "skeletonSpawning" , false ) ;
} ;
function updateSkeletonPreferences ( ) { //Skeleton setting handler
if ( settings . skeletonSpawning ) { //If the setting is on
if ( typeof ( randomEvents . skeleton ) !== "function" ) { //add the event if it's missing
randomEvents . skeleton = function ( ) {
var amount = Math . floor ( ( Math . random ( ) * maximumSkeletonTries ) + minimumSkeletonTries ) ; //1-3
//In worldgen worlds, you can expect about half of this because about half of the world is pixels in it.
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
if ( settings . skeletonSpawning ) { //setting validation
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable skeletons
var element = spawnSkeletons [ Math . floor ( Math . random ( ) * spawnSkeletons . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents . skeleton ; //self-disable
//substitute event
var event = randomEvents [ Object . keys ( randomEvents ) [ Math . floor ( Math . random ( ) * Object . keys ( randomEvents ) . length ) ] ] ;
event ( ) ;
break ;
} ;
} ;
} ;
} ;
} else if ( ! settings . skeletonSpawning ) { //and if it's off
if ( randomEvents . skeleton ) { delete randomEvents . skeleton } ; //delete it if it exists.
} ;
} ;
function toggleSkeletonSpawning ( ) { //Skeleton toggle handler
if ( settings . skeletonSpawning != true ) { //If it's false
setSetting ( "skeletonSpawning" , true ) ; //make it true and update the status display CSS
updateSkeletonPreferences ( ) ; //apply
document . getElementById ( "skeletonStatusStylesheet" ) . innerHTML = '.skeletonStatus { color: #1E1; text-decoration: underline; }' ; //Displayed info doen't update until it's pulled up again, so I'm using CSS to dynamically change the color of an element, like with find.js (RIP).
} else { //and the inverse if it's true
setSetting ( "skeletonSpawning" , false ) ;
updateSkeletonPreferences ( ) ;
document . getElementById ( "skeletonStatusStylesheet" ) . innerHTML = '.skeletonStatus { color: #E11; text-decoration: none; }' ;
} ;
} ;
spawnSkeletons = [ "skeleton" ] ;
if ( settings . skeletonSpawning ) { //skeleton spawning option
randomEvents . skeleton = function ( ) {
var amount = Math . floor ( ( Math . random ( ) * maximumSkeletonTries ) + minimumSkeletonTries ) ; //1-3
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
if ( settings . skeletonSpawning ) { //setting validation
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable skeletons
var element = spawnSkeletons [ Math . floor ( Math . random ( ) * spawnSkeletons . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} else { //if false (this function is never supposed to fire with the setting false)
delete randomEvents . skeleton ; //self-disable
//substitute event
var event = randomEvents [ Object . keys ( randomEvents ) [ Math . floor ( Math . random ( ) * Object . keys ( randomEvents ) . length ) ] ] ;
event ( ) ;
break ;
} ;
} ;
} ;
} ;
standaloneSpawnSkeleton = function ( amount = 1 ) {
/ * T h e a m o u n t i s t h e m a x i m u m a m o u n t o f * a t t e m p t s * . O f t e n , l e s s s k e l e t o n s w i l l s p a w n d u e t o t h i n g s i n t h e w a y .
In a generated world , which uses half of the space , you can expect about half of this number to spawn . * /
for ( i = 0 ; i < amount ; i ++ ) { //dummy for to break
// random x between 1 and width-1
var x = Math . floor ( Math . random ( ) * ( width - 1 ) ) + 1 ;
// random y between 1 and height
var y = Math . floor ( Math . random ( ) * height - 1 ) + 1 ;
if ( isEmpty ( x , y ) ) {
// random element from the list of spawnable skeletons
var element = spawnSkeletons [ Math . floor ( Math . random ( ) * spawnSkeletons . length ) ] ;
// if element is an array, choose a random element from the array
if ( Array . isArray ( element ) ) {
element = element [ Math . floor ( Math . random ( ) * element . length ) ] ;
}
createPixel ( element , x , y ) ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
/ * S t a r t M a i n Z o m b i e
... ... ... ... ... ...
... ... ... # # # ... ...
... ... . # # # # # # # ... .
... ... # # # # # OOOOO . .
... . # # # # # # OOOOOOO .
... # # # # # # # # OOOOO . .
... # # # # # # # # # # # ... .
... # # # # # # # # # # # ... .
... # # # # # # # # # # # ... .
... . # # # # # # # # # # ... .
... ... # # # # # # # # ... .
... ... . # # ... # # ... .
... ... . # # ... # # ... .
... ... ... ... ... ...
* /
elements . zombie = {
color : [ "#567C44" , "#199A9A" , "#41369B" ] ,
category : "life" ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "zombie_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "zombie_head" ;
pixel . color = pixelColorPick ( pixel )
}
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "zombie_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "zombie_body" ;
pixel . color = pixelColorPick ( pixel )
}
else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
2022-11-02 13:32:23 -04:00
related : [ "zombie_body" , "zombie_head" ] ,
2022-10-09 10:55:07 -04:00
desc : "<em>I'd rather this be toggleable mid-game than require a reload.</em><br/><br/><span class=\"zombieStatus\">If this text is green or underlined, zombies (all types) can spawn.</span> <span onclick=toggleZombieSpawning() style=\"color: #ff00ff;\";>Click here</span> to toggle zombie spawning. If it's on, zombies can spawn through random events."
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
elements . zombie _body = {
color : "#27719D" ,
category : "life" ,
hidden : true ,
density : 1500 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 250 ,
stateHigh : "rotten_meat" ,
tempLow : - 30 ,
stateLow : "frozen_rotten_meat" ,
burn : 10 ,
burnTime : 250 ,
burnInto : "rotten_meat" ,
breakInto : [ "zombie_blood" , "rotten_meat" ] ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.005 } ,
"radiation" : { "elem1" : [ "ash" , "rotten_meat" , "rotten_meat" ] , "chance" : 0.4 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.025 } ,
} ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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 == "zombie_head" ) {
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 ] ) ;
}
2022-10-06 14:15:16 -04:00
}
}
}
2022-10-09 10:55:07 -04:00
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
// Turn into rotten_meat if pixelTicks-dead > 100
if ( pixelTicks - pixel . dead > 100 ) {
changePixel ( pixel , "rotten_meat" ) ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
return ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
// Find the head
if ( ! isEmpty ( pixel . x , pixel . y - 1 , true ) ) {
if ( pixelMap [ pixel . x ] [ pixel . y - 1 ] . element == "head" ) {
changePixel ( pixelMap [ pixel . x ] [ pixel . y - 1 ] , "zombie_head" ) ;
} else if ( pixelMap [ pixel . x ] [ pixel . y - 1 ] . element == "zombie_head" ) {
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 ;
} ;
} else { var head = null } ;
if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
// create zombie blood if decapitated 10% chance
if ( Math . random ( ) < 0.1 ) {
createPixel ( "zombie_blood" , pixel . x , pixel . y - 1 ) ;
// set dead to true 10% chance
if ( Math . random ( ) < 0.10 ) {
pixel . dead = pixelTicks ;
}
2022-10-06 14:15:16 -04:00
}
}
2022-10-09 10:55:07 -04:00
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 ;
} ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
// 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*");
} ; * /
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ,
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
elements . zombie _head = {
color : "#567C44" ,
category : "life" ,
hidden : true ,
density : 1500 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 250 ,
stateHigh : "rotten_meat" ,
tempLow : - 30 ,
stateLow : "frozen_rotten_meat" ,
burn : 10 ,
burnTime : 250 ,
burnInto : "rotten_meat" ,
breakInto : [ "zombie_blood" , "rotten_meat" ] ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.005 } ,
"radiation" : { "elem1" : [ "ash" , "rotten_meat" , "rotten_meat" ] , "chance" : 0.4 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.025 } ,
} ,
properties : {
dead : false ,
following : false ,
dir : 1 ,
panic : 0 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
// Turn into rotten_meat if pixelTicks-dead > 100
if ( pixelTicks - pixel . dead > 100 ) {
changePixel ( pixel , "rotten_meat" ) ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
return ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
// Find the body
if ( ! isEmpty ( pixel . x , pixel . y + 1 , true ) ) {
if ( pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "body" ) {
changePixel ( pixelMap [ pixel . x ] [ pixel . y + 1 ] , "zombie_body" ) ;
} else if ( pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "zombie_body" ) {
var body = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
if ( body . dead ) { // If body is dead, kill body
pixel . dead = body . dead ;
} ;
} else {
var body = null ;
} ;
} else { var body = null } ;
if ( body ) {
if ( body . dir !== pixel . dir ) { //hacky workaround: lock head dir to body dir
pixel . dir = body . dir ;
} ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
tryMove ( pixel , pixel . x , pixel . y + 1 ) ;
// create zombie blood if severed 10% chance
if ( isEmpty ( pixel . x , pixel . y + 1 ) && ! pixel . dead && Math . random ( ) < 0.1 ) {
createPixel ( "zombie_blood" , pixel . x , pixel . y + 1 ) ;
// set dead to true 10% chance
if ( Math . random ( ) < 0.10 ) {
pixel . dead = pixelTicks ;
}
2022-10-06 14:15:16 -04:00
}
}
2022-10-09 10:55:07 -04:00
//start of most new code
var pX = pixel . x ;
var pY = pixel . y ;
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
if ( pixelTicks % 2 == 0 ) { //reduce rate for performance
/ * v a r d i r e c t i o n A d v e r b = " l e f t " ;
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 > ( - 35 - 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-10-09 10:55:07 -04:00
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to mutilate (changePixel)
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
} ;
} else { //Remaining 2/3 chance to turn the human
zombifyHuman ( newPixel ) ;
} ;
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
} ;
} ;
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ; //can't see through humans
} ;
} ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
} 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 < 35 + 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-10-09 10:55:07 -04:00
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to mutilate (changePixel)
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
} ;
} else { //Remaining 2/3 chance to turn the human
zombifyHuman ( newPixel ) ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 2/3 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ; //can't see through humans
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
//Baby Zombie
elements . baby _zombie = {
color : "#199A9A" ,
category : "life" ,
hidden : true ,
density : 1500 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 250 ,
stateHigh : "rotten_meat" ,
tempLow : - 30 ,
stateLow : "frozen_rotten_meat" ,
burn : 10 ,
burnTime : 250 ,
burnInto : "rotten_meat" ,
breakInto : [ "zombie_blood" , "rotten_meat" ] ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.005 } ,
"radiation" : { "elem1" : [ "ash" , "rotten_meat" , "rotten_meat" ] , "chance" : 0.4 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.025 } ,
} ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
tryMove ( pixel , pixel . x , pixel . y + 1 ) ; // Fall
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
// Turn into rotten_meat if pixelTicks-dead > 100
if ( pixelTicks - pixel . dead > 100 ) {
changePixel ( pixel , "rotten_meat" ) ;
} ;
return ;
} ;
if ( Math . random ( ) < 0.15 ) { // Move 10% chance
var movesToTry = [
[ 1 * pixel . dir , 0 ] , //dash move
[ 1 * pixel . dir , - 1 ] , //slash move
] ;
// 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 ] ) ) {
2022-10-06 14:15:16 -04:00
break ;
} ;
2022-10-09 10:55:07 -04:00
} ;
} ;
// 15% chance to change direction while not chasing a human
if ( ! pixel . 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*");
} ; * /
} ;
var pX = pixel . x ;
var pY = pixel . y ;
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
if ( pixelTicks % 2 == 0 ) { //reduce rate for performance
/ * v a r d i r e c t i o n A d v e r b = " l e f t " ;
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 > ( - 35 - 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-10-09 10:55:07 -04:00
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to mutilate (changePixel)
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
} ;
} else { //Remaining 2/3 chance to turn the human
zombifyHuman ( newPixel ) ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
} 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 < 35 + 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-10-09 10:55:07 -04:00
if ( Math . random ( ) < 1 / 3 ) { //One-third chance to mutilate (changePixel)
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
} ;
} else { //Remaining 2/3 chance to turn the human
zombifyHuman ( newPixel ) ;
} ;
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "zombie_blood" , false ) ; //blood is turned in place
} else { //Remaining 3/4 chance to change to rotten flesh
changePixel ( newPixel , "rotten_meat" , false ) ;
} ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ; //can't see through humans
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
2022-11-02 13:32:23 -04:00
related : [ "zombie" ] ,
2022-10-09 10:55:07 -04:00
desc : "Baby zombies: smaller, faster, and more annoying." ,
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
/ * S t a r t M a i n C r e e p e r
# # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # #
# # # # # # # # # # #
# # # # # # OOOOO # #
# # # # OOOOOOO #
# # # OOOOO # #
# # # # # # #
# # # # # # #
# # # # # # #
# # # # # # # #
# # # # # # # # # #
# # # # # # # # # # # # # #
# # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # #
* /
elements . creeper = {
color : [ "#D2D2D2" , "#BFDFB9" , "#94CE89" , "#78D965" , "#5ED54C" , "#58C546" , "#50B143" , "#479143" , "#559552" , "#3F8738" , "#5B8B59" ] ,
category : "life" ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "creeper_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "creeper_head" ;
pixel . color = pixelColorPick ( pixel )
}
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "creeper_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "creeper_body" ;
pixel . color = pixelColorPick ( pixel )
}
else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
2022-11-02 13:32:23 -04:00
related : [ "creeper_body" , "creeper_head" ] ,
2022-11-14 16:51:55 -05:00
desc : "<em>I'd rather this be toggleable mid-game than require a reload.</em><br/><br/><span class=\"creeperStatus\">If this text is green or underlined, creepers can spawn.</span> <span onclick=toggleCreeperSpawning() style=\"color: #ff00ff;\";>Click here</span> to toggle creeper spawning. If it's on, creepers (all types) can spawn through random events.<br/>To enable automatic creeper generation, set the generateCreepers query parameter."
2022-10-09 10:55:07 -04:00
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
elements . creeper _body = {
color : [ "#D2D2D2" , "#BFDFB9" , "#94CE89" , "#78D965" , "#5ED54C" , "#58C546" , "#50B143" , "#479143" , "#559552" , "#3F8738" , "#5B8B59" ] ,
category : "life" ,
hidden : 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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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 == "creeper_head" ) {
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 == "creeper_head" ) {
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 ;
} ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
// 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 ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( head ) {
if ( typeof ( head . charge ) !== "undefined" ) {
if ( head . charge ) {
pixel . charged = true ;
} ;
2022-10-06 14:15:16 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( head . charged ) !== "undefined" ) {
if ( head . charged ) {
pixel . charged = true ;
} ;
} ;
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
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 ) ;
//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");
} ;
//}
} ;
} ;
} ,
} ;
elements . creeper _head = {
color : [ "#5B8B59" , "#3F8738" , "#559552" , "#479143" , "#50B143" , "#58C546" ] ,
category : "life" ,
hidden : 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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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 == "creeper_body" ) {
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 ;
} ;
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
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" ;
2022-10-06 14:15:16 -04:00
if ( pixel . dir > 0 ) {
directionAdverb = "right" ;
2022-10-09 10:55:07 -04:00
} ;
2022-10-06 14:15:16 -04:00
//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}`)
2022-10-09 10:55:07 -04:00
for ( j = ( - 1 ) ; j > ( - 16 - 1 ) ; j -- ) {
2022-10-06 14:15:16 -04:00
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 ) ) {
2022-10-09 10:55:07 -04:00
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
2022-10-06 14:15:16 -04:00
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})`)
2022-10-09 10:55:07 -04:00
if ( ! newPixel . dead ) {
2022-10-06 14:15:16 -04:00
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
2022-10-09 10:55:07 -04:00
//Start "hissing" if a human is close enough
2022-11-11 14:22:36 -05:00
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"
2022-10-09 10:55:07 -04:00
pixel . hissing = true ;
if ( ! pixel . hissStart ) {
pixel . hissStart = pixelTicks ;
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
} 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}`)
2022-10-09 10:55:07 -04:00
for ( j = 1 ; j < 16 + 1 ; j ++ ) {
2022-10-06 14:15:16 -04:00
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 ) ) {
2022-10-09 10:55:07 -04:00
//console.log(`Skipping pixel (${nX},${nY}) (empty)`)
2022-10-06 14:15:16 -04:00
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})`)
2022-10-09 10:55:07 -04:00
if ( ! newPixel . dead ) {
2022-10-06 14:15:16 -04:00
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
2022-10-09 10:55:07 -04:00
//Start "hissing" if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 3.15 ) {
2022-10-09 10:55:07 -04:00
pixel . hissing = true ;
if ( ! pixel . hissStart ) {
pixel . hissStart = pixelTicks ;
2022-10-06 14:15:16 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
break ;
2022-10-06 14:15:16 -04:00
} ;
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
2022-10-09 10:55:07 -04:00
break ;
2022-10-06 14:15:16 -04:00
} ;
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
//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");
} ;
//}
2022-10-06 14:15:16 -04:00
2022-10-09 10:55:07 -04:00
if ( pixelTicks - pixel . hissStart > 30 ) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAt ( body . x , body . y , explosionRadius ) ;
//console.log("Yes, Rico, kaboom.");
} ;
} ;
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
2022-10-02 12:40:42 -04:00
2022-10-09 10:55:07 -04:00
/ * E n d M a i n C r e e p e r
# # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # #
# # # # # # # # # X # X # # # # # #
# # # # # # # # # XXX # # # # # #
# # # # # # # # # # X # # # # # # #
# # # # # # # # # # X # # # # # # #
# # # # # # X # # # # #
# # # # # # #
# # # # # # # #
# # # # # # # # # #
# # # # # # # # # # # # # #
# # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # #
* /
2022-10-09 13:20:18 -04:00
//Baby Creeper
elements . baby _creeper = {
color : [ "#D2D2D2" , "#BFDFB9" , "#94CE89" , "#78D965" , "#5ED54C" , "#58C546" , "#50B143" , "#479143" , "#559552" , "#3F8738" , "#5B8B59" ] ,
category : "life" ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 13:20:18 -04:00
tick : function ( pixel ) {
tryMove ( pixel , pixel . x , pixel . y + 1 ) ; // Fall
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
}
if ( Math . random ( ) < 0.15 ) { // Move 15% chance (should be 12.5 but 15 looks better)
var movesToTry = [
[ 1 * pixel . dir , 0 ] , //dash move
[ 1 * pixel . dir , - 1 ] , //slash move
] ;
// 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 ] ) ) {
break ;
} ;
} ;
} ;
// 15% chance to change direction while not chasing a human
if ( ! pixel . 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 ( typeof ( pixel . charged ) === "undefined" ) {
pixel . charged = false ;
} ;
if ( pixel . charge ) {
pixel . charged = true ;
} ;
var pX = pixel . x ;
var pY = pixel . y ;
if ( pixel . charged ) {
var explosionRadius = 6 ;
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 = 4 ; //should be half of the original creeper's radius
} ;
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 > 15 ) {
//console.log("Kaboom?");
explodeAt ( pixel . x , pixel . y , explosionRadius ) ;
//console.log("Yes, Rico, kaboom.");
} ;
} ;
//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 ) {
//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 + ( 2 * ticksHissing ) ) ;
green = rgbColorBound ( green + ( 2 * ticksHissing ) ) ;
blue = rgbColorBound ( blue + ( 2 * 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 + ( 2 * 1.176 ) ) ;
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
} ;
//}
if ( pixelTicks - pixel . hissStart > 15 ) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAt ( pixel . x , pixel . y , explosionRadius ) ;
//console.log("Yes, Rico, kaboom.");
} ;
} ;
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
//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
2022-11-11 14:22:36 -05:00
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"
2022-10-09 13:20:18 -04:00
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
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 3.15 ) {
2022-10-09 13:20:18 -04:00
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 ;
} ;
} ;
} ;
} ;
} ;
} ,
2022-11-02 13:32:23 -04:00
related : [ "creeper" ] ,
2022-10-09 13:20:18 -04:00
} ;
2022-10-09 10:55:07 -04:00
//Angelic Creeper
elements . angelic _creeper = { //let's get this one out of the way first
color : [ "#f5ef56" , "#fcbddf" , "#de8aa8" , "#e35d95" , "#eb4974" , "#ed3ea7" , "#d645a3" , "#a84556" , "#9e4f6c" , "#91315b" , "#8c4963" ] ,
category : "life" ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "angelic_creeper_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "angelic_creeper_head" ;
pixel . color = pixelColorPick ( pixel )
2022-10-02 12:40:42 -04:00
}
2022-10-09 10:55:07 -04:00
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "angelic_creeper_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "angelic_creeper_body" ;
pixel . color = pixelColorPick ( pixel )
2022-10-02 12:40:42 -04:00
}
2022-10-09 10:55:07 -04:00
else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
2022-11-02 13:32:23 -04:00
related : [ "angelic_creeper_body" , "angelic_creeper_head" ] ,
2022-10-09 10:55:07 -04:00
desc : 'A creeper type from <em>Extra Creeper Types</em> <a href="https://www.curseforge.com/minecraft/mc-mods/extra-creeper-types">(CF)</a>. It sends things upward.'
} ;
2022-10-02 12:40:42 -04:00
2022-10-09 10:55:07 -04:00
elements . angelic _creeper _body = {
color : [ "#d2d2d2" , "#fcbddf" , "#de8aa8" , "#e35d95" , "#eb4974" , "#ed3ea7" , "#d645a3" , "#a84556" , "#9e4f6c" , "#91315b" , "#8c4963" ] ,
category : "life" ,
hidden : 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" , "blood" , "gunpowder" , "gunpowder" , "feather" ] ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
if ( ! pixel . hissing ) { //If not hissing (it floats when hissing)
if ( Math . random ( ) < 0.2 ) { //20% chance to fall
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 == "angelic_creeper_head" ) {
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 ] ) ;
} ;
} ;
} ;
} ;
} ;
} else {
if ( ( pixelTicks - pixel . start ) % 3 == 0 ) {
if ( ! isEmpty ( pixel . x , pixel . y - 1 , true ) ) { // Find head
var headPixel = pixelMap [ pixel . x ] [ pixel . y - 1 ] ;
if ( headPixel . element == "angelic_creeper_head" ) { //Validate head
if ( tryMove ( headPixel , pixel . x , pixel . y - 2 ) ) { // Float
if ( isEmpty ( pixel . x , pixel . y - 1 ) ) { //If the head didn't swap with something
movePixel ( pixel , pixel . x , pixel . y - 1 ) ; //Pull body up
} else { //If it did swap
swapPixels ( pixel , pixelMap [ pixel . x ] [ pixel . y - 1 ] ) ; //Pull body up through other pixel
} ;
} ;
} ;
} ;
} ;
} ;
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
2022-10-02 12:40:42 -04:00
}
2022-10-09 10:55:07 -04:00
// Find the head
if ( ! isEmpty ( pixel . x , pixel . y - 1 , true ) && pixelMap [ pixel . x ] [ pixel . y - 1 ] . element == "angelic_creeper_head" ) {
var head = pixelMap [ pixel . x ] [ pixel . y - 1 ] ;
if ( head . dead ) { // If head is dead, kill body
pixel . dead = head . dead ;
2022-10-02 12:40:42 -04:00
}
}
2022-10-09 10:55:07 -04:00
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 ;
} ;
2022-10-02 12:40:42 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
// 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*");
} ; * /
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixel . charge ) {
pixel . charged = true ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( head ) {
if ( typeof ( head . charge ) !== "undefined" ) {
if ( head . charge ) {
pixel . charged = true ;
} ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( head . charged ) !== "undefined" ) {
if ( head . charged ) {
pixel . charged = true ;
2022-10-02 12:40:42 -04:00
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( pixel . charged ) === "undefined" ) {
pixel . charged = false ;
} ;
2022-10-02 12:40:42 -04:00
2022-10-09 10:55:07 -04:00
if ( pixel . charged ) {
var explosionRadius = 10 ;
if ( ! pixel . didChargeBlueTinted ) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel . color ;
2022-10-02 12:40:42 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
red = rgbColorBound ( red + 51 ) ;
green = rgbColorBound ( green + 51 ) ;
blue = rgbColorBound ( blue + 102 ) ;
2022-10-02 12:40:42 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
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 ) ;
2022-10-02 12:40:42 -04:00
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
} ;
2022-10-09 10:55:07 -04:00
pixel . didChargeBlueTinted = true ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
} else {
var explosionRadius = 7 ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixel . burning ) {
pixel . hissing = true ;
if ( ! pixel . hissStart ) {
pixel . hissStart = pixelTicks ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( ! pixel . burnStart ) { //I don't like errors.
pixel . burnStart = pixel . ticks ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixelTicks - pixel . burnStart > 30 ) {
//console.log("GOTTA YEET YEET YEET!");
explodeAtPlus ( pixel . x , pixel . y , explosionRadius , "fire" , "smoke" , null , angelicUpwardVelocity ) ; //Special effect: Flings you upwards (extended to all movable tiles because it's easier).
//It also floats when hissing, but that will come soon.
//console.log("Yes, Rico, kaboom.");
2022-10-02 12:40:42 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
//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
2022-10-02 12:40:42 -04:00
//console.log("ss-- oof");
pixel . hissing = false ;
break ;
} ;
2022-10-09 10:55:07 -04:00
if ( head . hissing ) {
//console.log("Ssssssss");
if ( ! head . hissStart ) {
//console.log("t-30 ticks or whatever it was");
head . hissStart = pixelTicks ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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");
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
//}
2022-10-02 12:40:42 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
} ,
} ,
2022-11-12 15:36:47 -05:00
2022-10-09 10:55:07 -04:00
elements . angelic _creeper _head = {
color : [ "#f5ef56" , "#f0ea4f" , "#f0ea60" ] ,
category : "life" ,
hidden : 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" , "blood" , "blood" , "blood" , "feather" ] ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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
}
2022-10-02 12:40:42 -04:00
}
2022-10-09 10:55:07 -04:00
// Find the body
if ( ! isEmpty ( pixel . x , pixel . y + 1 , true ) && pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "angelic_creeper_body" ) {
var body = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
if ( body . dead ) { // If body is dead, kill head
pixel . dead = body . dead ;
2022-10-02 12:40:42 -04:00
}
}
2022-10-09 10:55:07 -04:00
else { var body = null }
if ( body ) {
if ( body . dir !== pixel . dir ) { //hacky workaround: lock head dir to body dir
pixel . dir = body . dir ;
2022-10-02 12:40:42 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
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 ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( body ) {
if ( typeof ( body . charge ) !== "undefined" ) {
if ( body . charge ) {
pixel . charged = true ;
} ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( body . charged ) !== "undefined" ) {
if ( body . charged ) {
pixel . charged = true ;
2022-10-02 12:40:42 -04:00
} ;
} ;
2022-10-03 15:28:33 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( pixel . charged ) === "undefined" ) {
pixel . charged = false ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixel . charged ) {
var explosionRadius = 10 ;
if ( ! pixel . didChargeBlueTinted ) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel . color ;
2022-10-02 12:40:42 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
red = rgbColorBound ( red + 51 ) ;
green = rgbColorBound ( green + 51 ) ;
blue = rgbColorBound ( blue + 102 ) ;
2022-10-02 12:40:42 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
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 ) ;
2022-10-02 12:40:42 -04:00
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
} ;
2022-10-09 10:55:07 -04:00
pixel . didChargeBlueTinted = true ;
} ;
} else {
var explosionRadius = 7 ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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" ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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
2022-11-11 14:22:36 -05:00
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"
2022-10-09 10:55:07 -04:00
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
} ;
} ;
2022-10-02 12:40:42 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
} 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
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 3.15 ) {
2022-10-09 10:55:07 -04:00
pixel . hissing = true ;
if ( ! pixel . hissStart ) {
pixel . hissStart = pixelTicks ;
} ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
break ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ;
2022-10-02 12:40:42 -04:00
} ;
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
//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 ;
2022-10-02 12:40:42 -04:00
break ;
} ;
2022-10-09 10:55:07 -04:00
if ( ! pixel . hissStart ) {
//console.log("t-30 ticks or whatever it was");
pixel . hissStart = pixelTicks ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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("GOTTA YEET YEET YEET!");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAtPlus ( body . x , body . y , explosionRadius , "fire" , "smoke" , null , angelicUpwardVelocity ) ;
//console.log("Yes, Rico, kaboom.");
} ;
} ;
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
//Bombing Creeper
elements . bombing _creeper = {
color : [ "#5b8b59" , "#3f8738" , "#559552" , "#479143" , "#50b143" , "#58c546" , "#e83c3c" , "#c92a2a" , "#f53d3d" , "#ad3131" ] ,
category : "life" ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "bombing_creeper_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "bombing_creeper_head" ;
pixel . color = pixelColorPick ( pixel )
}
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "bombing_creeper_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "bombing_creeper_body" ;
pixel . color = pixelColorPick ( pixel )
}
else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
2022-11-02 13:32:23 -04:00
related : [ "bombing_creeper_body" , "bombing_creeper_head" ] ,
2022-10-09 10:55:07 -04:00
desc : 'A creeper type from <em>Extra Creeper Types</em> <a href="https://www.curseforge.com/minecraft/mc-mods/extra-creeper-types">(CF)</a>. It spawns more explosives when it explodes.'
} ;
elements . bombing _creeper _body = {
color : [ "#e83c3c" , "#c92a2a" , "#f53d3d" , "#ad3131" ] ,
category : "life" ,
hidden : 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" , "dynamite" , "gunpowder" ] ,
breakInto : [ "blood" , "dynamite" , "dynamite" ] ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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 == "bombing_creeper_head" ) {
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 == "bombing_creeper_head" ) {
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 ] ) ;
2022-10-02 12:40:42 -04:00
break ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
// 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*");
} ; * /
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixel . charge ) {
pixel . charged = true ;
} ;
if ( head ) {
if ( typeof ( head . charge ) !== "undefined" ) {
if ( head . charge ) {
pixel . charged = true ;
} ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( head . charged ) !== "undefined" ) {
if ( head . charged ) {
pixel . charged = true ;
} ;
2022-10-02 12:40:42 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
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 ;
2022-10-02 12:40:42 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
red = rgbColorBound ( red + 51 ) ;
green = rgbColorBound ( green + 51 ) ;
blue = rgbColorBound ( blue + 102 ) ;
2022-10-02 12:40:42 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
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 ) ;
2022-10-02 12:40:42 -04:00
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
} ;
2022-10-09 10:55:07 -04:00
pixel . didChargeBlueTinted = true ;
} ;
} else {
var explosionRadius = 7 ;
} ;
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 , "fire,dynamite" ) ; //Effect: Places (originally 5) primed TNT when it explodes (i.e. cluster bomb creeper)
//Dynamite is the closest thing we have to powder TNT (i.e. good enough)
2022-10-02 12:40:42 -04:00
//console.log("Yes, Rico, kaboom.");
} ;
} ;
2022-10-02 12:35:07 -04:00
2022-10-09 10:55:07 -04:00
//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 ;
} ;
2022-10-02 12:35:07 -04:00
2022-10-09 10:55:07 -04:00
//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");
} ;
//}
} ;
} ;
} ,
} ;
2022-10-01 23:25:34 -04:00
2022-10-09 10:55:07 -04:00
elements . bombing _creeper _head = {
color : [ "#5B8B59" , "#3F8738" , "#559552" , "#479143" , "#50B143" , "#58C546" ] ,
category : "life" ,
hidden : 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" , "dynamite" , "gunpowder" ] ,
breakInto : [ "blood" , "dynamite" ] ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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
2022-10-01 23:25:34 -04:00
}
}
2022-10-09 10:55:07 -04:00
// Find the body
if ( ! isEmpty ( pixel . x , pixel . y + 1 , true ) && pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "bombing_creeper_body" ) {
var body = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
if ( body . dead ) { // If body is dead, kill head
pixel . dead = body . dead ;
2022-10-01 23:25:34 -04:00
}
}
2022-10-09 10:55:07 -04:00
else { var body = null }
if ( body ) {
if ( body . dir !== pixel . dir ) { //hacky workaround: lock head dir to body dir
pixel . dir = body . dir ;
2022-10-01 23:25:34 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
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 ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( body ) {
if ( typeof ( body . charge ) !== "undefined" ) {
if ( body . charge ) {
pixel . charged = true ;
} ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( body . charged ) !== "undefined" ) {
if ( body . charged ) {
pixel . charged = true ;
2022-10-02 00:44:42 -04:00
} ;
2022-10-02 00:11:28 -04:00
} ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( pixel . charged ) === "undefined" ) {
pixel . charged = false ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-02 00:11:28 -04:00
2022-10-09 10:55:07 -04:00
if ( pixel . charged ) {
var explosionRadius = 10 ;
if ( ! pixel . didChargeBlueTinted ) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel . color ;
2022-10-02 00:44:42 -04:00
if ( color . startsWith ( "rgb" ) ) {
2022-10-02 00:11:28 -04:00
//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 ) ) ;
2022-10-09 10:55:07 -04:00
red = rgbColorBound ( red + 51 ) ;
green = rgbColorBound ( green + 51 ) ;
blue = rgbColorBound ( blue + 102 ) ;
2022-10-02 00:11:28 -04:00
color = ` rgb( ${ red } , ${ green } , ${ blue } ) ` ;
pixel . color = color ;
//console.log("color set");
2022-10-02 00:44:42 -04:00
} 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 ) ) ;
2022-10-09 10:55:07 -04:00
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 ) ;
2022-10-02 00:44:42 -04:00
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
2022-10-02 00:11:28 -04:00
} ;
2022-10-09 10:55:07 -04:00
pixel . didChargeBlueTinted = true ;
} ;
} else {
var explosionRadius = 7 ;
2022-10-02 00:11:28 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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" ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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
2022-11-11 14:22:36 -05:00
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"
2022-10-09 10:55:07 -04:00
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
} ;
} ;
2022-10-02 00:44:42 -04:00
} ;
2022-10-02 00:11:28 -04:00
} ;
2022-10-09 10:55:07 -04:00
} 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
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 3.15 ) {
2022-10-09 10:55:07 -04:00
pixel . hissing = true ;
if ( ! pixel . hissStart ) {
pixel . hissStart = pixelTicks ;
} ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
break ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ;
2022-10-01 23:25:34 -04:00
} ;
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
//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 ;
2022-10-01 23:25:34 -04:00
break ;
} ;
2022-10-09 10:55:07 -04:00
if ( ! pixel . hissStart ) {
//console.log("t-30 ticks or whatever it was");
pixel . hissStart = pixelTicks ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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 radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAt ( body . x , body . y , explosionRadius , "fire,dynamite" ) ;
//console.log("Yes, Rico, kaboom.");
} ;
} ;
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
//Hell Creeper
elements . hell _creeper = {
color : [ "#D2D2D2" , "#ff141e" , "#fc3232" , "#DFAFAF" , "#e84a4a" , "#ce7979" , "#d95555" , "#d53c3c" , "#c53636" , "#b13333" , "#913535" , "#954242" , "#872828" , "#8b4949" , "#2b0304" ] ,
category : "life" ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "hell_creeper_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "hell_creeper_head" ;
pixel . color = pixelColorPick ( pixel )
}
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "hell_creeper_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "hell_creeper_body" ;
pixel . color = pixelColorPick ( pixel )
}
else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
2022-11-02 13:32:23 -04:00
related : [ "hell_creeper_body" , "hell_creeper_head" ] ,
2022-10-09 10:55:07 -04:00
desc : 'A creeper type from <em>Extra Creeper Types</em> <a href="https://www.curseforge.com/minecraft/mc-mods/extra-creeper-types">(CF)</a>. It has a small explosion radius, but spawns a lot of fire around its explosion.'
} ;
elements . hell _creeper _body = {
color : [ "#D2D2D2" , "#ff141e" , "#fc3232" , "#DFAFAF" , "#e84a4a" , "#ce7979" , "#d95555" , "#d53c3c" , "#c53636" , "#b13333" , "#913535" , "#954242" , "#872828" , "#8b4949" , "#2b0304" ] ,
category : "life" ,
hidden : true ,
density : 1500 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 2000 , //they are immune to lava, and minecraft's lava is presumably mafic, so at least 1200*C
stateHigh : "ash" ,
breakInto : [ "blood" , "gunpowder" , "fire" ] ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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 == "hell_creeper_head" ) {
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 == "hell_creeper_head" ) {
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 ] ) ;
2022-10-01 23:25:34 -04:00
break ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
// 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*");
} ; * /
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixel . charge ) {
pixel . charged = true ;
} ;
if ( head ) {
if ( typeof ( head . charge ) !== "undefined" ) {
if ( head . charge ) {
pixel . charged = true ;
} ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( head . charged ) !== "undefined" ) {
if ( head . charged ) {
pixel . charged = true ;
} ;
2022-10-01 23:25:34 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
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 ;
2022-10-02 00:44:42 -04:00
if ( color . startsWith ( "rgb" ) ) {
2022-10-02 00:11:28 -04:00
//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 ) ) ;
2022-10-09 10:55:07 -04:00
red = rgbColorBound ( red + 51 ) ;
green = rgbColorBound ( green + 51 ) ;
blue = rgbColorBound ( blue + 102 ) ;
2022-10-02 00:11:28 -04:00
color = ` rgb( ${ red } , ${ green } , ${ blue } ) ` ;
pixel . color = color ;
//console.log("color set");
2022-10-02 00:44:42 -04:00
} 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 ) ) ;
2022-10-09 10:55:07 -04:00
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 ) ;
2022-10-02 00:44:42 -04:00
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
2022-10-02 00:11:28 -04:00
} ;
2022-10-09 10:55:07 -04:00
pixel . didChargeBlueTinted = true ;
} ;
} else {
var explosionRadius = 7 ;
} ;
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 ) {
2022-10-01 23:25:34 -04:00
//console.log("Kaboom?");
2022-10-09 10:55:07 -04:00
explodeAtPlus ( pixel . x , pixel . y , explosionRadius , "fire" , "fire" , null , hellExplosionFire ) ;
2022-10-02 12:35:07 -04:00
//console.log("Yes, Rico, kaboom.");
} ;
} ;
2022-10-02 14:12:08 -04:00
2022-10-09 10:55:07 -04:00
//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 ;
} ;
2022-10-02 14:12:08 -04:00
2022-10-09 10:55:07 -04:00
//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");
} ;
//}
} ;
} ;
} ,
} ;
2022-10-02 14:12:08 -04:00
2022-10-09 10:55:07 -04:00
elements . hell _creeper _head = {
color : [ "#D2D2D2" , "#ff141e" , "#fc3232" , "#e84a4a" , "#b13333" , "#913535" , "#954242" , "#872828" , "#8b4949" , "#2b0304" , "#111111" , "#faae3c" , "#f5e131" ] ,
category : "life" ,
hidden : true ,
density : 1080 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 2000 ,
stateHigh : "ash" ,
tempLow : - 30 ,
stateLow : "frozen_meat" ,
breakInto : [ "blood" , "fire" ] ,
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 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-10-09 10:55:07 -04:00
tick : function ( pixel ) {
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
2022-10-02 14:12:08 -04:00
}
}
2022-10-09 10:55:07 -04:00
// Find the body
if ( ! isEmpty ( pixel . x , pixel . y + 1 , true ) && pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "hell_creeper_body" ) {
var body = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
if ( body . dead ) { // If body is dead, kill head
pixel . dead = body . dead ;
2022-10-02 14:12:08 -04:00
}
}
2022-10-09 10:55:07 -04:00
else { var body = null }
if ( body ) {
if ( body . dir !== pixel . dir ) { //hacky workaround: lock head dir to body dir
pixel . dir = body . dir ;
2022-10-02 14:12:08 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
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 ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( body ) {
if ( typeof ( body . charge ) !== "undefined" ) {
if ( body . charge ) {
pixel . charged = true ;
} ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( body . charged ) !== "undefined" ) {
if ( body . charged ) {
pixel . charged = true ;
2022-10-02 14:12:08 -04:00
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
if ( typeof ( pixel . charged ) === "undefined" ) {
pixel . charged = false ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
if ( pixel . charged ) {
var explosionRadius = 10 ;
if ( ! pixel . didChargeBlueTinted ) { //do once, on initial charge
//console.log("something something halsey lyric");
var color = pixel . color ;
2022-10-02 14:12:08 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
red = rgbColorBound ( red + 51 ) ;
green = rgbColorBound ( green + 51 ) ;
blue = rgbColorBound ( blue + 102 ) ;
2022-10-02 14:12:08 -04:00
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 ) ) ;
2022-10-09 10:55:07 -04:00
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 ) ;
2022-10-02 14:12:08 -04:00
color = ` hsl( ${ hue } , ${ saturation } %, ${ luminance } %) ` ;
pixel . color = color ;
//console.log("color set");
} ;
2022-10-09 10:55:07 -04:00
pixel . didChargeBlueTinted = true ;
} ;
} else {
var explosionRadius = 7 ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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" ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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
2022-11-11 14:22:36 -05:00
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"
2022-10-09 10:55:07 -04:00
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
} ;
} ;
2022-10-02 14:12:08 -04:00
} ;
} ;
2022-10-09 10:55:07 -04:00
} 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
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 3.15 ) {
2022-10-09 10:55:07 -04:00
pixel . hissing = true ;
if ( ! pixel . hissStart ) {
pixel . hissStart = pixelTicks ;
} ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
break ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ;
2022-10-02 14:12:08 -04:00
} ;
} ;
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
//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 ;
2022-10-02 14:12:08 -04:00
break ;
} ;
2022-10-09 10:55:07 -04:00
if ( ! pixel . hissStart ) {
//console.log("t-30 ticks or whatever it was");
pixel . hissStart = pixelTicks ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
//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");
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
//}
if ( pixelTicks - pixel . hissStart > 30 ) {
//console.log("Kaboom?");
//console.log(`Exploding with radius ${explosionRadius} (charged: ${pixel.charged})`);
explodeAtPlus ( pixel . x , pixel . y , explosionRadius , "fire" , "fire" , null , hellExplosionFire ) ;
//console.log("Yes, Rico, kaboom.");
2022-10-02 14:12:08 -04:00
} ;
} ;
} ;
2022-10-09 10:55:07 -04:00
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
2022-11-02 13:32:23 -04:00
/ * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Nothing There |
| |
| amogus |
| |
| red imposter |
| |
| |
| |
| |
| |
| |
| |
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + * /
elements . nothing _there _bullet = {
flippableX : true ,
movable : true ,
density : 10000 ,
desc : "A hypersonic bullet made of Nothing There's flesh. I don't remember if it can turn humans into red clouds." ,
color : "#a3281a" ,
related : [ "nothing_there_phase_3_body" , "nothing_there_phase_3_head" ] ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-11-02 13:32:23 -04:00
tick : function ( pixel ) {
2022-11-03 09:15:57 -04:00
if ( typeof ( pixel . flipX ) == undefined ) {
pixel . flipX = ! ! Math . floor ( Math . random ( ) * 2 ) ;
} ;
var dir = pixel . flipX ? - 1 : 1 ;
for ( i = 0 ; i < 6 ; i ++ ) {
if ( outOfBounds ( pixel . x + dir , pixel . y ) ) {
deletePixel ( pixel . x , pixel . y ) ;
break ;
2022-10-09 10:55:07 -04:00
} ;
2022-11-03 09:15:57 -04:00
if ( ! nothingThereBulletMovement ( pixel , pixel . x + dir , pixel . y ) ) {
return true ;
2022-11-02 13:32:23 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
2022-11-02 13:32:23 -04:00
} ,
} ;
2022-10-09 10:55:07 -04:00
2022-11-02 13:32:23 -04:00
elements . nothing _there _mace = {
movable : true ,
density : 10000 ,
desc : "A spiky mace attached to Nothing There, which can turn humans into red clouds." ,
color : "#fa4632" ,
properties : {
counter : 2 ,
} ,
related : [ "nothing_there_phase_3_body" , "nothing_there_phase_3_head" ] ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-11-02 13:32:23 -04:00
tick : function ( pixel ) {
if ( outOfBounds ( pixel . x , pixel . y + 1 ) ) {
deletePixel ( pixel . x , pixel . y ) ;
return false ;
} ;
if ( ! tryMove ( pixel , pixel . x , pixel . y + 1 ) ) {
var newPixel = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
var newElement = newPixel . element ;
var newInfo = elements [ newElement ] ;
if ( newElement !== pixel . element ) {
if ( newInfo . state === "gas" ) {
swapPixels ( pixel , newPixel ) ;
} else {
if ( pixel . counter > 0 ) {
explodeAtPlus ( pixel . x , pixel . y + 1 , 5 , null , null ) ;
pixel . counter -- ;
} else {
deletePixel ( pixel . x , pixel . y ) ;
return true ;
} ;
} ;
2022-10-02 14:12:08 -04:00
} ;
2022-10-09 10:55:07 -04:00
} ;
2022-11-02 13:32:23 -04:00
} ,
} ;
elements . nothing _there _cleaver = {
movable : true ,
density : 10000 ,
desc : "A very sharp blade attached to Nothing There, which can turn humans into red clouds." ,
color : "#a33c3c" ,
properties : {
2022-11-03 09:15:57 -04:00
counter : 4 ,
2022-11-02 13:32:23 -04:00
} ,
related : [ "nothing_there_phase_3_body" , "nothing_there_phase_3_head" ] ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-11-02 13:32:23 -04:00
tick : function ( pixel ) {
if ( outOfBounds ( pixel . x , pixel . y + 1 ) ) {
deletePixel ( pixel . x , pixel . y ) ;
return false ;
2022-10-09 10:55:07 -04:00
} ;
2022-11-02 13:32:23 -04:00
if ( ! tryMove ( pixel , pixel . x , pixel . y + 1 ) ) {
var newPixel = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
var newElement = newPixel . element ;
var newInfo = elements [ newElement ] ;
if ( ! nothingThereBulletExcludedElements . includes ( newElement ) ) {
if ( pixel . counter > 0 ) {
swapPixels ( pixel , newPixel ) ;
breakPixel ( newPixel , false , false ) ;
pixel . counter -- ;
} else {
deletePixel ( pixel . x , pixel . y ) ;
return true ;
} ;
} else {
deletePixel ( pixel . x , pixel . y ) ;
return false ;
} ;
} ;
} ,
} ;
testSwapArray = [ "meat" , "cooked_meat" , "rotten_meat" , "blood" , "infection" , "antibody" , "plague" , "zombie_blood" , "frozen_meat" , "frozen_rotten_meat" ] ;
elements . nothing _there _phase _1 = {
color : "#faacac" ,
category : "life" ,
density : 2000 ,
desc : "O-06-20 <span style='color: red;'>(ALEPH)</span><br/>In this phase, it looks like a dog made of misshapen human parts. It can easily turn humans into unrecognizable messes." ,
state : "solid" ,
tempHigh : 3000 ,
hardness : 0.995 ,
stateHigh : "cooked_meat" ,
burn : 1 ,
burnTime : 250000 ,
burnInto : "cooked_meat" ,
breakInto : ( enabledMods . includes ( "mods/fey_and_more.js" ) ? [ "blood" , "meat" , "magic" ] : [ "blood" , "meat" ] ) ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.00002 } ,
"radiation" : { "elem1" : [ "ash" , "meat" , "rotten_meat" , "cooked_meat" ] , "chance" : 0.00004 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.000003 } ,
} ,
related : [ "nothing_there_phase_2" , "nothing_there_phase_3_body" , "nothing_there_phase_3_head" ] ,
properties : {
dead : false ,
dir : 1 ,
following : false ,
} ,
movable : true ,
tick : function ( pixel ) {
var pixelBreakInto = elements [ pixel . element ] . breakInto ;
tryMove ( pixel , pixel . x , pixel . y + 1 ) ; // Fall
2022-10-09 10:55:07 -04:00
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
2022-11-02 13:32:23 -04:00
// Break if pixelTicks-dead > 5
if ( pixelTicks - pixel . dead > 5 ) {
changePixel ( pixel , pixelBreakInto [ Math . floor ( Math . random ( ) * pixelBreakInto . length ) ] , false ) ;
} ;
return ;
} ;
2022-10-09 10:55:07 -04:00
2022-11-02 13:32:23 -04:00
if ( Math . random ( ) < 0.1 ) { // Move 10% chance
2022-10-09 10:55:07 -04:00
var movesToTry = [
2022-11-02 13:32:23 -04:00
[ 1 * pixel . dir , 0 ] , //dash move
[ 1 * pixel . dir , - 1 ] , //cleave move
2022-10-09 10:55:07 -04:00
] ;
// 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 ] ;
2022-11-02 13:32:23 -04:00
if ( tryMove ( pixel , pixel . x + move [ 0 ] , pixel . y + move [ 1 ] ) ) {
break ;
} else { //move through given pixels
if ( ! isEmpty ( pixel . x + move [ 0 ] , pixel . y + move [ 1 ] , true ) ) {
var blockingPixel = pixelMap [ pixel . x + move [ 0 ] ] [ pixel . y + move [ 1 ] ] ;
//console.log(blockingPixel);
var blockingElement = blockingPixel . element ;
if ( testSwapArray . includes ( blockingElement ) ) {
swapPixels ( pixel , blockingPixel ) ;
break ;
} ;
2022-10-09 10:55:07 -04:00
} ;
} ;
} ;
// 15% chance to change direction while not chasing a human
2022-11-02 13:32:23 -04:00
if ( ! pixel . following ) {
2022-10-09 10:55:07 -04:00
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*");
} ; * /
} ;
2022-11-02 13:32:23 -04:00
var pX = pixel . x ;
var pY = pixel . y ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
//Human detection loop (looks ahead according to direction and sets the "following" variable to true, telling the body to lock the direction)
if ( pixelTicks % 2 == 0 && ! pixel . dead ) { //reduce rate for performance
/ * v a r d i r e c t i o n A d v e r b = " l e f t " ;
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 > ( - 35 - 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-11-02 13:32:23 -04:00
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} 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 < 35 + 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-11-02 13:32:23 -04:00
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ; //can't see through humans
} ;
} ;
} ;
} ;
} ;
} ;
if ( pixelTicks - pixel . start > 300 && ( Math . random ( ) < 0.003 ) ) {
var dir = pixel . dir ;
changePixel ( pixel , "nothing_there_phase_2" , false ) ;
pixel . dir = dir ;
} ;
//End
} ,
} ;
elements . nothing _there _phase _2 = {
behavior : behaviors . POWDER _OLD ,
color : "#d90b0b" ,
category : "life" ,
density : 4000 ,
desc : "O-06-20 <span style='color: red;'>(ALEPH)</span><br/>In this phase, it looks like a red, fibrous cocoon. It will soon hatch into its third phase." ,
state : "solid" ,
tempHigh : 3500 ,
hardness : 0.999 ,
stateHigh : "cooked_meat" ,
burn : 1 ,
burnTime : 350000 ,
burnInto : "cooked_meat" ,
breakInto : ( enabledMods . includes ( "mods/fey_and_more.js" ) ? [ "blood" , "meat" , "magic" ] : [ "blood" , "meat" ] ) ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.000001 } ,
"radiation" : { "elem1" : [ "ash" , "meat" , "rotten_meat" , "cooked_meat" ] , "chance" : 0.000001 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.000001 } ,
} ,
related : [ "nothing_there_phase_1" , "nothing_there_phase_3_body" , "nothing_there_phase_3_head" ] ,
properties : {
dead : false ,
dir : 1 ,
timer : 0 ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-11-02 13:32:23 -04:00
tick : function ( pixel ) {
var pixelBreakInto = elements [ pixel . element ] . breakInto ;
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
// Break if pixelTicks-dead > 5
if ( pixelTicks - pixel . dead > 5 ) {
changePixel ( pixel , pixelBreakInto [ Math . floor ( Math . random ( ) * pixelBreakInto . length ) ] , false ) ;
} ;
return ;
} ;
if ( pixelTicks - pixel . start > 300 ) {
var dir = pixel . dir ;
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "nothing_there_phase_3_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "nothing_there_phase_3_head" ;
pixel . color = pixelColorPick ( pixel )
pixelMap [ pixel . x ] [ pixel . y + 1 ] . dir = dir ;
}
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "nothing_there_phase_3_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "nothing_there_phase_3_body" ;
pixel . color = pixelColorPick ( pixel )
pixel . dir = dir ;
} ;
} ;
//End
} ,
} ;
elements . nothing _there _phase _3 = {
color : "#fc1e35" ,
category : "life" ,
2022-11-02 13:47:09 -04:00
desc : "Spawns Nothing There in its humanoid third phase, for when you don't want to wait for it to go through the other phases." ,
2022-11-02 13:32:23 -04:00
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
2022-11-03 09:15:57 -04:00
movable : true ,
2022-11-02 13:32:23 -04:00
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "nothing_there_phase_3_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "nothing_there_phase_3_head" ;
pixel . color = pixelColorPick ( pixel )
} else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "nothing_there_phase_3_head" , pixel . x , pixel . y - 1 ) ;
pixel . element = "nothing_there_phase_3_body" ;
pixel . color = pixelColorPick ( pixel )
} else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
related : [ "nothing_there_phase_3_body" , "nothing_there_phase_3_head" ] ,
} ;
elements . nothing _there _phase _3 _body = {
color : "#fc1e35" ,
category : "life" ,
density : 3000 ,
desc : "O-06-20 <span style='color: red;'>(ALEPH)</span><br/>In this phase, it looks like a humanoid made of misarranged flesh. It is almost indestructible and has a variety of ways to destroy your canvas and annihilate any humans inside of it.<br/>Let's hope it doesn't learn to blend in and walk among us." ,
state : "solid" ,
tempHigh : 3000 ,
hardness : 0.9975 ,
2022-11-02 13:47:09 -04:00
hidden : true ,
2022-11-02 13:32:23 -04:00
stateHigh : "cooked_meat" ,
burn : 1 ,
burnTime : 300000 ,
burnInto : "cooked_meat" ,
breakInto : ( enabledMods . includes ( "mods/fey_and_more.js" ) ? [ "blood" , "meat" , "magic" ] : [ "blood" , "meat" ] ) ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.00001 } ,
"radiation" : { "elem1" : [ "ash" , "meat" , "rotten_meat" , "cooked_meat" ] , "chance" : 0.00002 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.0000015 } ,
} ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
movable : true ,
2022-11-06 17:02:21 -05:00
related : [ "nothing_there_phase_1" , "nothing_there_phase_2" , "nothing_there_mace" , "nothing_there_cleaver" , "nothing_there_bullet" ] ,
2022-11-02 13:32:23 -04:00
tick : function ( pixel ) {
var pixelBreakInto = elements [ pixel . element ] . breakInto ;
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 == "nothing_there_phase_3_head" ) {
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 ) {
// Break if pixelTicks-dead > 5
if ( pixelTicks - pixel . dead > 5 ) {
changePixel ( pixel , pixelBreakInto [ Math . floor ( Math . random ( ) * pixelBreakInto . length ) ] , false ) ;
} ;
return ;
} ;
// Find the head
if ( ! isEmpty ( pixel . x , pixel . y - 1 , true ) ) {
if ( pixelMap [ pixel . x ] [ pixel . y - 1 ] . element == "nothing_there_phase_3_head" ) {
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 ;
} ;
} else { var head = null } ;
if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
// create blood if decapitated 30% chance
if ( Math . random ( ) < 0.3 ) {
createPixel ( "blood" , pixel . x , pixel . y - 1 ) ;
// set dead to true 10% chance
if ( Math . random ( ) < 0.1 ) {
pixel . dead = pixelTicks ;
}
}
}
else if ( head == null ) { return } //do not proceed if headless
2022-11-06 17:02:21 -05:00
else if ( Math . random ( ) < 0.08 ) { // Move 10% chance
2022-11-02 13:32:23 -04:00
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*");
} ; * /
} ;
} ,
} ;
elements . nothing _there _phase _3 _head = {
color : "#ff3046" ,
category : "life" ,
density : 3000 ,
desc : "O-06-20 <span style='color: red;'>(ALEPH)</span><br/>In this phase, it looks like a humanoid made of misarranged flesh. It is almost indestructible and has a variety of ways to destroy your canvas and annihilate any humans inside of it.<br/>Let's hope it doesn't learn to blend in and walk among us." ,
state : "solid" ,
tempHigh : 3000 ,
hardness : 0.9975 ,
2022-11-02 13:47:09 -04:00
hidden : true ,
2022-11-02 13:32:23 -04:00
stateHigh : "cooked_meat" ,
burn : 1 ,
burnTime : 300000 ,
burnInto : "cooked_meat" ,
breakInto : ( enabledMods . includes ( "mods/fey_and_more.js" ) ? [ "blood" , "meat" , "magic" ] : [ "blood" , "meat" ] ) ,
reactions : {
"cancer" : { "elem1" : "cancer" , "chance" : 0.00001 } ,
"radiation" : { "elem1" : [ "ash" , "meat" , "rotten_meat" , "cooked_meat" ] , "chance" : 0.00002 } ,
"plague" : { "elem1" : "plague" , "chance" : 0.0000015 } ,
} ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
movable : true ,
related : [ "nothing_there_phase_1" , "nothing_there_phase_2" , "nothing_there_mace" , "nothing_there_cleaver" , , "nothing_there_bullet" ] ,
tick : function ( pixel ) {
var pixelBreakInto = elements [ pixel . element ] . breakInto ;
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
// Break if pixelTicks-dead > 5
if ( pixelTicks - pixel . dead > 5 ) {
changePixel ( pixel , pixelBreakInto [ Math . floor ( Math . random ( ) * pixelBreakInto . length ) ] , false ) ;
} ;
return ;
} ;
// Find the body
if ( ! isEmpty ( pixel . x , pixel . y + 1 , true ) ) {
if ( pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "nothing_there_phase_3_body" ) {
var body = pixelMap [ pixel . x ] [ pixel . y + 1 ] ;
if ( body . dead ) { // If body is dead, kill body
pixel . dead = body . dead ;
} ;
} else {
var body = null ;
} ;
} 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 30% chance
if ( isEmpty ( pixel . x , pixel . y + 1 ) && Math . random ( ) < 0.3 ) {
createPixel ( "blood" , pixel . x , pixel . y + 1 ) ;
// set dead to true 10% chance
if ( Math . random ( ) < 0.10 ) {
pixel . dead = pixelTicks ;
}
}
}
//start of most new code
var pX = pixel . x ;
var pY = pixel . y ;
//Human detection loop
if ( pixelTicks % 2 == 0 && ! pixel . dead ) { //reduce rate for performance
/ * v a r d i r e c t i o n A d v e r b = " l e f t " ;
if ( pixel . dir > 0 ) {
directionAdverb = "right" ;
} ; * /
//console.log(`Looking ${directionAdverb}`)
if ( pixel . dir === - 1 ) {
//do action every 40 ticks
var bulletPositions = [ [ - 1 , - 1 ] , [ - 1 , 0 ] ] ;
var bulletPosition = bulletPositions [ Math . floor ( Math . random ( ) * 2 ) ] ;
var smashPosition = [ - 1 , - 1 ] ;
2022-11-03 09:15:57 -04:00
var cleavePositions = [ [ - 1 , - 1 ] , [ - 2 , - 1 ] , [ - 3 , - 1 ] ] ;
2022-11-02 13:32:23 -04:00
var start = 2 * Math . floor ( pixel . start / 2 ) ;
if ( ( pixelTicks - start ) % 40 == 0 ) {
var action = Math . floor ( Math . random ( ) * 3 ) ;
if ( action == 0 ) { //bullet
var bX = pX + bulletPosition [ 0 ] ;
var bY = pY + bulletPosition [ 1 ] ;
if ( ! outOfBounds ( bX , bY ) ) {
if ( isEmpty ( bX , bY ) ) {
createPixel ( "nothing_there_bullet" , bX , bY ) ;
pixelMap [ bX ] [ bY ] . flipX = true ;
} else {
if ( ! nothingThereBulletExcludedElements . includes ( pixelMap [ bX ] [ bY ] . element ) ) {
deletePixel ( bX , bY ) ;
createPixel ( "nothing_there_bullet" , bX , bY ) ;
pixelMap [ bX ] [ bY ] . flipX = true ;
} ;
} ;
} ;
} else if ( action == 1 ) { //smash
var sX = pX + smashPosition [ 0 ] ;
var sY = pY + smashPosition [ 1 ] ;
if ( ! outOfBounds ( sX , sY ) ) {
if ( isEmpty ( sX , sY ) ) {
createPixel ( "nothing_there_mace" , sX , sY ) ;
} else {
if ( ! nothingThereBulletExcludedElements . includes ( pixelMap [ sX ] [ sY ] . element ) ) {
deletePixel ( sX , sY ) ;
createPixel ( "nothing_there_mace" , sX , sY ) ;
} ;
} ;
} ;
} else if ( action == 2 ) { //cleave
for ( cleaverIndex = 0 ; cleaverIndex < cleavePositions . length ; cleaverIndex ++ ) {
var cX = pX + cleavePositions [ cleaverIndex ] [ 0 ] ;
var cY = pY + cleavePositions [ cleaverIndex ] [ 1 ] ;
if ( ! outOfBounds ( cX , cY ) ) {
if ( isEmpty ( cX , cY ) ) {
createPixel ( "nothing_there_cleaver" , cX , cY ) ;
} else {
if ( ! nothingThereBulletExcludedElements . includes ( pixelMap [ cX ] [ cY ] . element ) ) {
deletePixel ( cX , cY ) ;
createPixel ( "nothing_there_cleaver" , cX , cY ) ;
} ;
} ;
} ;
} ;
} ;
} ;
for ( i = - 4 ; i < 4 + 1 ; i ++ ) {
var oY = i ;
//console.log(`Starting row look at row ${pY+oY}`)
for ( j = ( - 1 ) ; j > ( - 35 - 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-11-02 13:32:23 -04:00
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} 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 ) {
//do action every 40 ticks
var bulletPositions = [ [ 1 , - 1 ] , [ 1 , 0 ] ] ;
var bulletPosition = bulletPositions [ Math . floor ( Math . random ( ) * 2 ) ] ;
var smashPosition = [ 1 , - 1 ] ;
2022-11-03 09:15:57 -04:00
var cleavePositions = [ [ 1 , - 1 ] , [ 2 , - 1 ] , [ 3 , - 1 ] ] ;
2022-11-02 13:32:23 -04:00
var start = 2 * Math . floor ( pixel . start / 2 ) ;
if ( ( pixelTicks - start ) % 40 == 0 ) {
var action = Math . floor ( Math . random ( ) * 3 ) ;
if ( action == 0 ) { //bullet
var bX = pX + bulletPosition [ 0 ] ;
var bY = pY + bulletPosition [ 1 ] ;
if ( ! outOfBounds ( bX , bY ) ) {
if ( isEmpty ( bX , bY ) ) {
createPixel ( "nothing_there_bullet" , bX , bY ) ;
2022-11-06 17:02:21 -05:00
pixelMap [ bX ] [ bY ] . flipX = false ;
2022-11-02 13:32:23 -04:00
} else {
if ( ! nothingThereBulletExcludedElements . includes ( pixelMap [ bX ] [ bY ] . element ) ) {
deletePixel ( bX , bY ) ;
createPixel ( "nothing_there_bullet" , bX , bY ) ;
2022-11-06 17:02:21 -05:00
pixelMap [ bX ] [ bY ] . flipX = false ;
2022-11-02 13:32:23 -04:00
} ;
} ;
} ;
} else if ( action == 1 ) { //smash
var sX = pX + smashPosition [ 0 ] ;
var sY = pY + smashPosition [ 1 ] ;
if ( ! outOfBounds ( sX , sY ) ) {
if ( isEmpty ( sX , sY ) ) {
createPixel ( "nothing_there_mace" , sX , sY ) ;
} else {
if ( ! nothingThereBulletExcludedElements . includes ( pixelMap [ sX ] [ sY ] . element ) ) {
deletePixel ( sX , sY ) ;
createPixel ( "nothing_there_mace" , sX , sY ) ;
} ;
} ;
} ;
} else if ( action == 2 ) { //cleave
for ( cleaverIndex = 0 ; cleaverIndex < cleavePositions . length ; cleaverIndex ++ ) {
var cX = pX + cleavePositions [ cleaverIndex ] [ 0 ] ;
var cY = pY + cleavePositions [ cleaverIndex ] [ 1 ] ;
if ( ! outOfBounds ( cX , cY ) ) {
if ( isEmpty ( cX , cY ) ) {
createPixel ( "nothing_there_cleaver" , cX , cY ) ;
} else {
if ( ! nothingThereBulletExcludedElements . includes ( pixelMap [ cX ] [ cY ] . element ) ) {
deletePixel ( cX , cY ) ;
createPixel ( "nothing_there_cleaver" , cX , cY ) ;
} ;
} ;
} ;
} ;
} ;
} ;
for ( i = - 4 ; i < 4 + 1 ; i ++ ) {
var oY = i ;
//console.log(`Starting row look at row ${pY+oY}`)
for ( j = 1 ; j < 35 + 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 ) { //If not dead
pixel . following = true ;
//console.log(`Human detected at (${nX},${nY})`)
//Infect/kill if a human is close enough
2022-11-11 14:22:36 -05:00
if ( coordPyth ( pX , pY , nX , nY ) <= 1.5 ) { //approx. sqrt(2)
2022-11-02 13:32:23 -04:00
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} else { //Mutilate if dead
if ( Math . random ( ) < 1 / 4 ) { //One-fourth chance to change to blood
changePixel ( newPixel , "blood" , false ) ;
} else { //Remaining 3/4 chance to change to meat
changePixel ( newPixel , "meat" , false ) ;
} ;
} ;
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ; //can't see through humans
} ;
} ;
} ;
} ;
} ;
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
runAfterLoad ( function ( ) {
if ( typeof ( badPixels ) === "object" ) {
badPixels . nothing _there _phase _1 = { panicIncrease : 1 , panicIncreaseChance : 1 } //insta-panic for "aleph" thing and "level 1" humans
badPixels . nothing _there _phase _2 = { panicIncrease : 1 , panicIncreaseChance : 1 }
badPixels . nothing _there _phase _3 _body = { panicIncrease : 1 , panicIncreaseChance : 1 }
badPixels . nothing _there _phase _3 _head = { panicIncrease : 1 , panicIncreaseChance : 1 }
}
} ) ;
/ * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| End Nothing There elements |
| |
| |
| |
| |
| |
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + * /
2022-11-11 14:22:36 -05:00
/ * + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Start skeleton elements +
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + * /
arrowExcludedElements = [ "wall" ] ;
arrowPlacementExcludedElements = [ "skeleton_head" , "skeleton_body" , "arrow" , "wall" ] ;
elements . rock . hardness = 0.55 ;
elements . arrow = {
cooldown : 2 ,
flippableX : true ,
movable : true ,
properties : {
flipY : false ,
speed : 5 ,
fall : 0 ,
attached : false ,
attachOffsets : [ null , null ] ,
penetrateCounter : 7 ,
} ,
density : 2471 ,
color : "#cacdcf" ,
related : [ "skeleton_body" , "skeleton_head" ] ,
movable : true ,
burn : 20 ,
//burnInto: "flint",
burnInto : "rock" ,
burnTime : 250 ,
breakInto : [ "gravel" , "gravel" , "sawdust" , "feather" ] ,
tick : function ( pixel ) {
if ( pixel . attachOffsets . includes ( null ) ) {
pixel . attached = false ;
} ;
if ( pixel . attached ) {
var attachCoords = [ pixel . x + pixel . attachOffsets [ 0 ] , pixel . y + pixel . attachOffsets [ 1 ] ] ;
var attachX = pixel . x + pixel . attachOffsets [ 0 ] ;
var attachY = pixel . y + pixel . attachOffsets [ 1 ] ;
if ( isEmpty ( attachX , attachY , true ) ) {
pixel . attached = false ;
} else {
var attachPixel = pixelMap [ attachX ] [ attachY ] ;
var attachInfo = elements [ attachPixel . element ] ;
var attachState = "solid" ;
if ( typeof ( attachInfo . state ) === "string" ) {
attachState = attachInfo . state ;
} ;
var attachBlacklistStates = [ "liquid" , "gas" ] ;
if ( attachBlacklistStates . includes ( attachState ) ) {
pixel . attached = false ;
} ;
} ;
} else { //Move if not attached
var speedForBreakMult = pythSpeed ( pixel . speed , pixel . y ) ;
var breakMult = speedForBreakMult / 5 ;
if ( typeof ( pixel . flipX ) == undefined ) {
pixel . flipX = ! ! Math . floor ( Math . random ( ) * 2 ) ;
} ;
var dir = pixel . flipX ? - 1 : 1 ;
if ( Math . random ( ) < ( 1 / ( pixel . speed * * 1.585 ) ) ) { //1/0 is Infinity in JavaScript, so this should always be true at 0 speed)
pixel . fall ++ ;
} ;
//Horizontal movement
for ( i = 0 ; i < pixel . speed ; i ++ ) {
if ( outOfBounds ( pixel . x + dir , pixel . y ) ) {
deletePixel ( pixel . x , pixel . y ) ;
break ;
} ;
if ( ! isEmpty ( pixel . x + dir , pixel . y , true ) ) {
var otherPixel = pixelMap [ pixel . x + dir ] [ pixel . y ] ;
var otherElement = otherPixel . element ;
var otherInfo = elements [ otherElement ] ;
if ( arrowExcludedElements . includes ( otherElement ) ) {
pixel . attached = true ; //attach
pixel . speed = 0 ;
pixel . fall = 0 ;
pixel . attachOffsets = [ dir , 0 ] ;
break ;
} ;
var otherDensity = ( typeof ( otherInfo . density ) === "undefined" ? 1000 : otherInfo . density ) ;
var swapChance = 1 - Math . max ( 0 , ( otherDensity / 2471 ) ) ;
if ( Math . random ( ) < swapChance && pixel . penetrateCounter > 0 ) {
swapPixels ( pixel , otherPixel ) ;
arrowAltTb ( otherPixel , breakMult ) ;
pixel . speed = Math . max ( 0 , -- pixel . speed ) ;
pixel . penetrateCounter -- ;
} else {
if ( ! arrowAltTb ( otherPixel , breakMult ) ) { //if this didn't break it
pixel . attached = true ; //attach
pixel . speed = 0 ;
pixel . fall = 0 ;
pixel . attachOffsets = [ dir , 0 ] ;
} ;
} ;
break ;
} else {
tryMove ( pixel , pixel . x + dir , pixel . y ) ;
} ;
} ;
if ( Math . random ( ) < 0.1 ) {
pixel . speed = Math . max ( 0 , -- pixel . speed ) ;
} ;
var dirY = 1 ;
//Vertical movement
if ( typeof ( pixel . flipY ) !== "undefined" ) {
if ( pixel . flipY ) {
pixel . dirY = - 1 ;
} ;
} ;
for ( j = 0 ; j < pixel . fall ; j ++ ) {
if ( outOfBounds ( pixel . x , pixel . y + dirY ) ) {
deletePixel ( pixel . x , pixel . y ) ;
break ;
} ;
if ( ! isEmpty ( pixel . x , pixel . y + dirY , true ) ) {
var otherPixel = pixelMap [ pixel . x ] [ pixel . y + dirY ] ;
var otherElement = otherPixel . element ;
var otherInfo = elements [ otherElement ] ;
if ( arrowExcludedElements . includes ( otherElement ) ) {
pixel . attached = true ; //attach
pixel . speed = 0 ;
pixel . fall = 0 ;
pixel . attachOffsets = [ 0 , dirY ] ;
break ;
} ;
var otherDensity = ( typeof ( otherInfo . density ) === "undefined" ? 1000 : otherInfo . density ) ;
var swapChance = 1 - Math . max ( 0 , ( otherDensity / 2471 ) ) ;
if ( Math . random ( ) < swapChance && pixel . penetrateCounter > 0 ) {
swapPixels ( pixel , otherPixel ) ;
arrowAltTb ( otherPixel , breakMult ) ;
pixel . speed = Math . max ( 0 , -- pixel . speed ) ;
pixel . penetrateCounter -- ;
} else {
if ( ! arrowAltTb ( otherPixel , breakMult ) ) { //if this didn't break it
pixel . attached = true ; //attach
pixel . speed = 0 ;
pixel . fall = 0 ;
pixel . attachOffsets = [ 0 , dirY ] ;
} ;
} ;
break ;
} else {
tryMove ( pixel , pixel . x , pixel . y + dirY ) ;
} ;
} ;
//End
} ;
} ,
} ;
elements . skeleton = {
color : [ "#ebebe6" , "#cfcfc8" ] ,
category : "life" ,
properties : {
dead : false ,
dir : 1 ,
panic : 0 ,
following : false ,
} ,
movable : true ,
tick : function ( pixel ) {
if ( isEmpty ( pixel . x , pixel . y + 1 ) ) {
createPixel ( "skeleton_body" , pixel . x , pixel . y + 1 ) ;
pixel . element = "skeleton_head" ;
pixel . color = pixelColorPick ( pixel )
}
else if ( isEmpty ( pixel . x , pixel . y - 1 ) ) {
createPixel ( "skeleton_head" , pixel . x , pixel . y - 1 ) ;
pixelMap [ pixel . x ] [ pixel . y - 1 ] . color = pixel . color ;
pixel . element = "skeleton_body" ;
pixel . color = pixelColorPick ( pixel )
}
else {
deletePixel ( pixel . x , pixel . y ) ;
}
} ,
related : [ "skeleton_body" , "skeleton_head" ] ,
desc : "<span class=\"skeletonStatus\">If this text is green or underlined, skeletons can spawn.</span> <span onclick=toggleSkeletonSpawning() style=\"color: #ff00ff;\";>Click here</span> to toggle skeleton spawning. If it's on, skeletons (all types) can spawn through random events."
} ;
elements . skeleton _body = {
color : "#ebebe6" ,
category : "life" ,
hidden : true ,
density : 1500 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 250 ,
stateHigh : "bone" ,
burn : 10 ,
burnTime : 250 ,
burnInto : [ "bone" , "ash" , "arrow" ] ,
hardness : 0.55 ,
breakInto : [ "bone" , "bone" , "bone" , "bone_marrow" ] ,
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 ,
chargeCounter : 20 ,
shooting : false ,
} ,
movable : true ,
tick : function ( pixel ) {
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 == "skeleton_head" ) {
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 bone if pixelTicks-dead > 500
if ( pixelTicks - pixel . dead > 200 ) {
changePixel ( pixel , "bone" ) ;
}
return
}
// Find the head
if ( ! isEmpty ( pixel . x , pixel . y - 1 , true ) && pixelMap [ pixel . x ] [ pixel . y - 1 ] . element == "skeleton_head" ) {
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 (bone marrow)
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 . shooting ) {
if ( pixel . chargeCounter <= 0 ) {
var bX = pixel . x + pixel . dir ;
var bY = pixel . y - 1 ;
var arrowFlipX = null ;
if ( pixel . dir < 0 ) {
arrowFlipX = true ;
} else if ( pixel . dir > 0 ) {
arrowFlipX = false ;
} ;
if ( ! outOfBounds ( bX , bY ) ) {
if ( isEmpty ( bX , bY ) ) {
createPixel ( "arrow" , bX , bY ) ;
pixelMap [ bX ] [ bY ] . flipX = arrowFlipX ;
} else {
if ( ! arrowExcludedElements . includes ( pixelMap [ bX ] [ bY ] . element ) && ! arrowPlacementExcludedElements . includes ( pixelMap [ bX ] [ bY ] . element ) ) {
deletePixel ( bX , bY ) ;
createPixel ( "arrow" , bX , bY ) ;
pixelMap [ bX ] [ bY ] . flipX = arrowFlipX ;
} ;
} ;
} ;
pixel . chargeCounter = 20 ;
} ;
if ( pixel . chargeCounter > 0 ) {
pixel . chargeCounter -- ;
} ;
} ;
} ,
} ;
elements . skeleton _head = {
color : [ "#ebebe6" , "#cfcfc8" ] ,
category : "life" ,
hidden : true ,
density : 1500 ,
state : "solid" ,
conduct : 25 ,
tempHigh : 250 ,
stateHigh : "bone" ,
burn : 10 ,
burnTime : 250 ,
burnInto : [ "bone" , "ash" , "arrow" ] ,
hardness : 0.55 ,
breakInto : [ "bone" , "bone" , "bone" , "bone_marrow" ] ,
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 ,
} ,
movable : true ,
tick : function ( pixel ) {
doHeat ( pixel ) ;
doBurning ( pixel ) ;
doElectricity ( pixel ) ;
if ( pixel . dead ) {
// Turn into bone if pixelTicks-dead > 500
if ( pixelTicks - pixel . dead > 200 ) {
changePixel ( pixel , "bone" ) ;
}
return
}
// Find the body
if ( ! isEmpty ( pixel . x , pixel . y + 1 , true ) && pixelMap [ pixel . x ] [ pixel . y + 1 ] . element == "skeleton_body" ) {
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 ;
//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 ;
2023-06-28 14:37:03 -04:00
if ( body ) body . shooting = true ;
2022-11-11 14:22:36 -05:00
} ;
} 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 ;
2023-06-28 14:37:03 -04:00
if ( body ) body . shooting = true ;
2022-11-11 14:22:36 -05:00
} ;
} else {
//console.log(`Stopping row look at pixel (${nX},${nY}) due to non-human pixel in the way`)
break ;
} ;
} ;
} ;
} ;
} ;
if ( Math . random ( ) < 0.01 ) { //1% chance each tick to lose interest
pixel . following = false ;
//console.log("Meh.");
} ;
} ,
} ;
/ * - - - - - - - - - - - - - - - - - - - - - - - - -
- End skeleton elements -
-- -- -- -- -- -- -- -- -- -- -- -- - * /
2022-10-09 10:55:07 -04:00
} else {
2022-11-12 15:36:47 -05:00
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 ) } ;
alert ( ` The " ${ runAfterAutogenMod } ", " ${ libraryMod } ", and " ${ explodeAtPlusMod } " mods are all required; any missing mods in this list have been automatically inserted (reload for this to take effect). ` )
localStorage . setItem ( "enabledMods" , JSON . stringify ( enabledMods ) ) ;
2022-10-04 11:31:10 -04:00
} ;