Downloads containing HH18Smoke.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Holiday Hare '18Featured Download SmokeNC Single player 8.9 Download file

File preview

#pragma require "HH18E1.j2a"


/*Custom enemies for Holiday Hare 18, by SmokeNC.
I didn't make any of the sprite animation myself and the credits go 
to their rightul owners. They were mainly taken from the 
Sprites Resource and Sprites-Inc*/




namespace SMOKE {
  void POLARBEAR(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[15]].load(0, "HH18E1.j2a");
	  jjAnimSets[ANIM::CUSTOM[23]].load(5, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::PolarBear();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[15], 0);
    jjObjectPresets[eventID].counter = 120;
    jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }

  void SANTAGHOST(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[16]].load(1, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::SantaGhost();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[16], 0);
    jjObjectPresets[eventID].special = 135;
    jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }

  void MECHABEAR(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[18]].load(3, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::MechaBear();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[18], 0);
    jjObjectPresets[eventID].counter = 95;
    jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }

  void ICEGOLEM(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[17]].load(8, "HH18E1.j2a");
	for(int i=0;i<4;i++)
	{
	 jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[17]].firstAnim].firstFrame+i].hotSpotY-=18;
    }
	jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[17]].firstAnim+1].firstFrame].hotSpotY-=18;
	jjObjectPresets[eventID].scriptedCollisions = true;
	jjObjectPresets[eventID].playerHandling=HANDLING::SPECIAL;
	jjObjectPresets[eventID].behavior = SMOKE::IceGolem();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[17], 0);
    jjObjectPresets[eventID].counter = 120;
	jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }

  void FROZENALIEN(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[21]].load(6, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::FrozeAlien();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[21], 0);
    jjObjectPresets[eventID].counter = 135;
    jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }

  void FROZENSHADE(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[23]].load(5, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::FrozenShade();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[23], 0);
    jjObjectPresets[eventID].counter = 120;
    jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }
  void ICEDRAGON(OBJECT::Object eventID1, OBJECT::Object eventID2) {
    jjAnimSets[ANIM::CUSTOM[22]].load(7, "HH18E1.j2a");
    jjObjectPresets[eventID1].behavior = SMOKE::IceDrag();
    jjObjectPresets[eventID2].behavior = SMOKE::IceDragBody();
    jjObjectPresets[eventID2].determineCurAnim(ANIM::CUSTOM[22], 0);
    jjObjectPresets[eventID2].energy = 20;
  }
   
    void CRYSTALKNIGHT(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[24]].load(9, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::CrystalKnight();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[24], 0);
    jjObjectPresets[eventID].counter = 110;
    jjObjectPresets[eventID].energy = hp;
	jjObjectPresets[eventID].deactivates = false;
  }
   void PENGUINATOR(OBJECT::Object eventID, int hp) {
    jjAnimSets[ANIM::CUSTOM[25]].load(2, "HH18E1.j2a");
    jjObjectPresets[eventID].behavior = SMOKE::Penguinator();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[25], 0);
    jjObjectPresets[eventID].counter = 115;
	jjObjectPresets[eventID].deactivates = false;
	jjObjectPresets[eventID].energy = hp;
  }
  
  
  class Penguinator: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      //the bear is initialized with walking phase
      if (obj.counter == 139) //stand still
      {
        obj.xSpeed = +0.001 * int(x) / abs(x);
        obj.frameID = 0;
      }
      if (obj.counter == 140) //attack phase
      {
        obj.special++;
        obj.determineCurAnim(ANIM::CUSTOM[25], 1); //attack animation

        if (obj.freeze == 0 && obj.special == 3 * 7) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          // bull2.xAcc = 0;
          // bull2.xSpeed = obj.direction * 4;
          if (bull2.xSpeed * obj.direction < 0)
            bull2.xSpeed *= -1;
          if (bull2.xAcc * obj.direction < 0)
            bull2.xAcc *= -1;
          // bull2.yAcc=-0.1;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
          jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);

        }
        if (obj.freeze == 0 && obj.special == 4 * 7) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          // bull2.xAcc = 0;
          // bull2.xSpeed = obj.direction * 4;
          if (bull2.xSpeed * obj.direction < 0)
            bull2.xSpeed *= -1;
          if (bull2.xAcc * obj.direction < 0)
            bull2.xAcc *= -1;
          // bull2.yAcc=-0.1;
          bull2.playerHandling = HANDLING::ENEMYBULLET;

        }

        if (obj.freeze == 0 && obj.special == 5 * 7) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          // bull2.xAcc = 0;
          // bull2.xSpeed = obj.direction * 4;
          if (bull2.xSpeed * obj.direction < 0)
            bull2.xSpeed *= -1;
          if (bull2.xAcc * obj.direction < 0)
            bull2.xAcc *= -1;
          // bull2.yAcc=-0.1;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
        }
if(jjDifficulty>=1)
{
        if (obj.freeze == 0 && obj.special == 6 * 7) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          // bull2.xAcc = 0;
          // bull2.xSpeed = obj.direction * 4;
          if (bull2.xSpeed * obj.direction < 0)
            bull2.xSpeed *= -1;
          if (bull2.xAcc * obj.direction < 0)
            bull2.xAcc *= -1;
          // bull2.yAcc=-0.1;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
        }
		}
		if(jjDifficulty>1)
		{
		 if (obj.freeze == 0 && obj.special == 7 * 7) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          // bull2.xAcc = 0;
          // bull2.xSpeed = obj.direction * 4;
          if (bull2.xSpeed * obj.direction < 0)
            bull2.xSpeed *= -1;
          if (bull2.xAcc * obj.direction < 0)
            bull2.xAcc *= -1;
          // bull2.yAcc=-0.1;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
        }
}
        if (obj.special == 8 * 7 + 1) //end attack phase; start walking phase 
        {

          obj.special = 0;
          obj.counter = 0;
          obj.xSpeed = 1 * obj.direction;
          obj.determineCurAnim(ANIM::CUSTOM[25], 0); //walking animation
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
        }

      }

      if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
      {
        if (y < 26)
          obj.counter++;
       // else obj.counter = 120;
      }
      //obj.yPos=obj.yOrg;
      obj.putOnGround();
      obj.behave(BEHAVIOR::WALKINGENEMY, false);
      if (obj.state == STATE::FREEZE)
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::FROZEN);
      else {

        if (obj.justHit == 0) {
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL);
        } else
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15);
      }
    }
  }
  
  
  
  class PolarBear: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {

      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      //the bear is initialized with walking phase
      if (obj.counter == 139) //stand still
      {
        obj.xSpeed = +0.01 * int(x) / abs(x);
        obj.frameID = 0;
      }
      if (obj.counter == 140) //attack phase
      {
        obj.special++;
        obj.determineCurAnim(ANIM::CUSTOM[15], 1); //attack animation

        if (obj.freeze == 0 && obj.special == 2 * 7 + 4) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 18, obj.yPos);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          bull2.determineCurAnim(ANIM::CUSTOM[15], 2);
          bull2.xAcc = 0;
          bull2.xSpeed = obj.direction * 4.5;
          bull2.yAcc = 0;
          bull2.ySpeed = 0;
          bull2.counterEnd = 50;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
          bull2.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
          int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 18, obj.yPos - 5);
          jjOBJ @ bull3 = jjObjects[bulletID3];
          bull3.determineCurAnim(ANIM::CUSTOM[15], 2);
          bull3.xAcc = 0;
          bull3.xSpeed = obj.direction * 4.5;
          bull3.yAcc = 0;
          bull3.ySpeed = -4;
          bull3.counterEnd = 50;
          bull3.playerHandling = HANDLING::ENEMYBULLET;
          bull3.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
          jjSample(obj.xPos, obj.yPos, SOUND::INTRO_SWISH3);

        }

        if (obj.special == 4 * 7 + 1) //end attack phase; start walking phase 
        {

          obj.special = 0;
          obj.counter = 0;
          obj.xSpeed = 1 * obj.direction;
          obj.determineCurAnim(ANIM::CUSTOM[15], 0); //walking animation

        }

      }

      if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
      {
        if (y < 26)
          obj.counter++;
        else obj.counter = 120;
      }
      obj.behave(BEHAVIOR::WALKINGENEMY, true);

    }
  }
  class GhostBullet : jjBEHAVIORINTERFACE 
  {
  void onBehave(jjOBJ @ obj) {
  if(obj.counter==69)
  {
  obj.xOrg=jjLocalPlayers[0].xPos;
  obj.yOrg=jjLocalPlayers[0].yPos;
  }
  obj.special++;
   if (obj.special == 150||obj.state==STATE::KILL)
	{
     // obj.state = STATE::KILL;
	 obj.points=0;
	 obj.particlePixelExplosion(72);
	 obj.delete();
	 return;
	  }
    obj.behave(BEHAVIOR::RAPIER, true);
    if (obj.state == 13)
      obj.state = 8;
   
    obj.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
    if (jjLocalPlayers[0].health == 0)
      obj.delete();
  }
  
  bool onObjectHit(jjOBJ@ obj,jjOBJ@ bullet,jjPLAYER@ player,int force)
  {
 if (bullet is null) {
  player.hurt();
      }
      return true;
  }

   }
  class SantaGhost: jjBEHAVIORINTERFACE {
  bool attack=false;
  int counter=0;
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
	   if (x * x + y * y <= 640 * 640)
		{
		 if(obj.freeze==0 && jjPlayers[playerID].direction*obj.direction>0)
	  {
	  obj.xPos+=sin(2 * float(jjGameTicks) / 90) * (12/8)*jjPlayers[playerID].direction;
	  obj.yPos+=cos(4 * float(jjGameTicks) / 90) * (12/8)*jjPlayers[playerID].direction;
	  }
		  }
      if(attack==false && obj.freeze==0)
	  {
	   obj.determineCurAnim(ANIM::CUSTOM[16], 0);
        //obj.counter++;
        if (x * x + y * y <= 250 * 250)
          counter++;
        obj.frameID = (jjGameTicks / 8) % 4;
        obj.determineCurFrame();
        if (counter >= 140) {
          attack=true;
          counter = 0;
          int bulletID3 = jjAddObject(OBJECT::RAPIER, obj.xPos - obj.direction * 10, obj.yPos - 10, 0, CREATOR::LEVEL);
          jjOBJ @ bull3 = jjObjects[bulletID3];
          bull3.behavior = SMOKE::GhostBullet();
          bull3.direction = -obj.direction;
          bull3.state = 8;
		  bull3.special=0;
		  bull3.scriptedCollisions=true;
		  bull3.light=30;
		  bull3.lightType=LIGHT::LASER;
          bull3.bulletHandling = HANDLING::IGNOREBULLET;
          bull3.playerHandling=HANDLING::SPECIAL;
		  obj.points=0;
          obj.frameID = 0;
          obj.determineCurAnim(ANIM::CUSTOM[16], 1);
          obj.determineCurFrame();
          jjSample(obj.xPos, obj.yPos, SOUND::RAPIER_GOSTDIE);
        }
        }
      if(attack==true)
         {
        counter++;
        obj.frameID=0;
		          obj.determineCurFrame();


        if (counter >= 30) {
          obj.determineCurAnim(ANIM::CUSTOM[16], 0);
          attack=false;
          counter = 0;
        }
        
      }
	  obj.behave(BEHAVIOR::SPARK,false);
    }
	
    void onDraw(jjOBJ @ obj) {
       if (obj.state == STATE::FREEZE)
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, +obj.direction, SPRITE::FROZEN,0,1);
      else {
        if (obj.justHit == 0) 
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, +obj.direction, SPRITE::NORMAL,0,1);
         else
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, +obj.direction, SPRITE::SINGLECOLOR, 15,1);
      }
    }
	
  }
  

  class MechaBear: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      //the bear is initialized with walking phase
      if (obj.counter == 99) //stand still
      {
        obj.xSpeed = 1 * int(x) / abs(x);
        obj.frameID = 0;
      }
      if (obj.counter == 100) //attack phase
      {
        obj.special++;
        obj.determineCurAnim(ANIM::CUSTOM[18], 1); //attack animation

        if (obj.freeze == 0 && obj.special == 1 * 7 + 3) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::BOUNCERBULLET, obj.xPos + obj.direction * 18, obj.yPos - 32);
          jjOBJ @ bull2 = jjObjects[bulletID2];
          bull2.behavior = SMOKE::BigSnowball;
          bull2.xAcc = 0;
          bull2.xSpeed = obj.direction * ((2 + abs(jjRandom()) % 5));
          bull2.yAcc = 0.15;
          bull2.ySpeed = -4;
          bull2.determineCurAnim(ANIM::CUSTOM[18], 2);
          bull2.frameID = 0;
          bull2.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
          bull2.playerHandling = HANDLING::ENEMYBULLET;

          jjSample(obj.xPos, obj.yPos, SOUND::INTRO_SWISH4);

        }

        if (obj.special == 4 * 7 + 1) //end attack phase; start walking phase 
        {

          obj.special = 0;
          obj.counter = 0;
          obj.xSpeed = 1 * obj.direction;
          obj.determineCurAnim(ANIM::CUSTOM[18], 0); //walking animation

        }

      }

      if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
        obj.counter++;
      obj.behave(BEHAVIOR::WALKINGENEMY, false);
      obj.yPos = obj.yOrg - 12;
      obj.putOnGround();

      obj.direction = int((x) / abs(x));
      if (obj.state == STATE::FREEZE)
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::FROZEN);
      else {
        obj.xPos = obj.xOrg;
        if (obj.justHit == 0) {
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL);
        } else
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15);
      }
    }
  }

  void BigSnowball(jjOBJ @ obj) {
    if (obj.state != STATE::EXPLODE) {
      obj.behave(BEHAVIOR::BOUNCERBULLET, false);
      jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[18], 2, 0, jjGameTicks * 60);

    } else
      obj.behave(BEHAVIOR::BOUNCERBULLET, true);

  }

  class IceGolem: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      if(obj.state==STATE::START)
	  {
	  jjPlayers[playerID].boss=obj.objectID;
	  }
	  
	  //jjPlayers[playerID].activateBoss();
	  	if (playerID > -1 && obj.freeze == 0) {
			
			if (obj.age > 0) obj.age--;
			jjPLAYER@ play;
			float dx = jjPlayers[playerID].xPos - obj.xPos, dy = jjLocalPlayers[playerID].yPos - obj.yPos;
			if (obj.freeze == 0 && obj.age == 0 && dx * dx + dy * dy < 50 * 50) {
				obj.age = 35;
				jjPlayers[playerID].xSpeed = 16 * obj.direction;
				jjPlayers[playerID].ySpeed = -16 * obj.direction;
				jjPlayers[playerID].hurt(1, false);
				jjSample(jjPlayers[playerID].xPos, jjPlayers[playerID].yPos, SOUND::FATCHK_HIT1, 42, 0);
			}
		}
		
		if (obj.state == STATE::KILL)
		{
			jjTriggers[0] = true;
			jjPlayers[playerID].activateBoss(false);
			}
			
      if (obj.counter == 139) //stand still
      {
        obj.xSpeed = +0.001 * int(x) / abs(x);
        obj.frameID = 0;
      }
      if (obj.counter == 140) //attack phase
      {
        obj.special++;
        obj.determineCurAnim(ANIM::CUSTOM[17], 1); //attack animation

        if (obj.freeze == 0 && obj.special == 3 * 7) // shoot bullets
        {
          int bulletID2 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos+obj.direction*26, obj.yPos - 20);
          jjOBJ @ bull2 = jjObjects[bulletID2];
		  bull2.determineCurAnim(ANIM::CUSTOM[17],2);
		  bull2.behavior=SMOKE::SpikeBall;
          bull2.counterEnd=72;
          // bull2.xSpeed = obj.direction * 4;
         bull2.xSpeed=obj.direction*3;
		 bull2.ySpeed=-5;
		 bull2.yAcc=0.15;
		 bull2.xAcc=0;
          // bull2.yAcc=-0.1;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
          jjSample(obj.xPos, obj.yPos, SOUND::AMMO_ICEGUNPU);

        }

        if (obj.special == 8 * 7 + 1) //end attack phase; start walking phase 
        {

          obj.special = 0;
          obj.counter = 0;
          obj.xSpeed = 1 * obj.direction;
          obj.determineCurAnim(ANIM::CUSTOM[17], 0); //walking animation

        }

      }

      if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
      {
        if (y < 26)
          obj.counter++;
        else obj.counter = 120;
      }
     //obj.yPos=obj.yOrg-10;
	
      obj.behave(BEHAVIOR::WALKINGENEMY, false);
	 // obj.yPos=obj.yOrg-10;
      if (obj.state == STATE::FREEZE)
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::FROZEN);
      else {

        if (obj.justHit == 0) {
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL);
        } else
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, 15);
      }
	  if(obj.state==STATE::KILL)
	  {
	  obj.particlePixelExplosion(0);
	   obj.particlePixelExplosion(0);
	    obj.particlePixelExplosion(0);
	  obj.delete();
	  }
    }
	
	 bool onObjectHit(jjOBJ @ obj, jjOBJ @ bullet, jjPLAYER @ player, int force) { //As described in the signs in-level, this is a nearly 100% faithful recreation of standard enemy collision code.
        if (bullet!is null) {
        //recreation of HANDLING::HURTBYBULLET with HANDLING::ENEMY
        if (obj.causesRicochet) {
          if ((bullet.var[6] & 6) == 0) //not fire-based, not a laser beam
            bullet.ricochet();
          else if ((bullet.var[6] & 4) == 0) //not a laser beam
            bullet.delete();
        } else if ((bullet.var[6] & 16) == 0) //not a fireball
          bullet.state = STATE::EXPLODE;
        if (obj.freeze > 0 && force < 3)
          force = 3;
        obj.energy -= force;
        obj.justHit = 5; //flash white for 5 ticks--jjOBJ::justHit is automatically deincremented by the JJ2 engine, so individual behavior functions don't need to worry about doing that.
        if (obj.energy <= 0) { //killed
          obj.energy = 0;
          obj.state = STATE::KILL;
          if (obj.freeze > 0)
            obj.unfreeze(0);
          /*else if ((bullet.var[6] & 2) == 0) //not fire-based
            obj.particlePixelExplosion(0);
          else {
            jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN);
            if ((bullet.var[6] & 4) != 0) //laser beam
              obj.particlePixelExplosion(72); //gray
            else
              obj.particlePixelExplosion(((bullet.var[6] & 8) != 0) ? 32 : 40); //powered-up (blue) or not (orange)
          }*/
          if (player!is null) {
            //obj.grantPickup(player, (uint(bullet.curAnim) == jjAnimSets[ANIM::AMMO].firstAnim + 17) ? 5 : 10);
            //givePlayerPointsForObject(player, obj);
          }
        } else
          obj.freeze = 0;
      } else { //recreation of HANDLING::ENEMY; player guaranteed to be non-null
        if (force != 0) { //attacking via special attack, e.g. buttstomp
                    player.hurt(); //constant amount of damage for special attacks
          if (obj.energy <= 0) { //killed
            obj.energy = 0;
            obj.state = STATE::KILL;
          } /*else { //only wounded
            obj.justHit = 5;
          }*/

          if (obj.freeze > 0) {
            obj.unfreeze(1);
          }

          if (force > 0) { //buttstomp or sugar rush
            player.buttstomp = 50; //landing
            player.ySpeed = player.ySpeed / -2 - 8;
            player.yAcc = 0;
            player.extendInvincibility(-70);
          } else if (force == -101) { //running into frozen enemy
            player.xAcc = 0;
            player.xSpeed /= -2;
            player.ySpeed = -6;
            player.extendInvincibility(-10);
          }
        } else { //not attacking
          player.hurt();
        }
      }
      return true;
    }
  }
  void SpikeBall(jjOBJ @ obj) {
    obj.behave(BEHAVIOR::BULLET, true);
    if (obj.state == STATE::EXPLODE && obj.isActive) {
		obj.unfreeze(1);
		 for (int i = 0; i < 8; i++) {
            int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos, obj.yPos, obj.objectID, CREATOR::OBJECT);
            jjOBJ @ o = jjObjects[bulletID3];
            o.determineCurAnim(ANIM::CUSTOM[17], 3);
            o.direction = obj.direction;
            o.ySpeed = 6*sin(i*3.141592/4);
			o.yAcc=0;
            o.xAcc=0;
            o.xSpeed = 6 * cos(i*3.141592/4);
            o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
            o.playerHandling = HANDLING::ENEMYBULLET;
          }
		obj.delete();
		
	}
  }
  //motivated from hh17enemies' ice dragon
  class FrozeAlien: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      obj.direction = int(x / abs(x));
      switch (obj.state) {
      case STATE::START:
        obj.frameID = (obj.counter / 7) % 3;
        obj.determineCurFrame();
        obj.putOnGround();
        obj.yPos += 6;
        obj.special = 138;
        obj.state = STATE::IDLE;
        break;
      case STATE::IDLE:

        obj.counter++;
        if (x * x + y * y <= 320 * 320)
          obj.special++;
        else obj.special = 120;
        obj.frameID = (obj.counter / 7) % 3;
        obj.determineCurFrame();

        if (obj.special == 140) {
          obj.state = STATE::ATTACK;
          obj.special = 0;
          obj.frameID = 0;
          obj.determineCurAnim(ANIM::CUSTOM[21], 0);
          obj.determineCurFrame();
        }
        break;
      case STATE::ATTACK:

        obj.determineCurAnim(ANIM::CUSTOM[21], 1);

        obj.special++;
        obj.counter++;
        if (obj.frameID != 2)
          obj.frameID = obj.special / 7;
        obj.determineCurFrame();
        if (obj.special == 16)
          jjSample(obj.xPos, obj.yPos, SOUND::COMMON_FLAMER);
        if (obj.special > 16 && obj.special % 5 == 1) {
          int bulletID3 = jjAddObject(OBJECT::TOASTERBULLET, obj.xPos + obj.direction * 4, obj.yPos + 3, obj.objectID, CREATOR::OBJECT);
          jjOBJ @ o = jjObjects[bulletID3];
          o.behavior = SMOKE::IceCloud;
          o.direction = obj.direction;
          o.xSpeed = abs(o.xSpeed) * obj.direction;
          o.ySpeed -= 1;

          o.curAnim = o.determineCurAnim(ANIM::AMMO, 82, true);

          o.freeze = 210;
          o.playerHandling = HANDLING::ENEMYBULLET;

        }
        if (obj.special == 80) {
          obj.determineCurAnim(ANIM::CUSTOM[21], 0);
          obj.state = STATE::IDLE;
          obj.special = 0;
        }
        break;

      case STATE::FREEZE:
        if (--obj.freeze == 0) obj.state = obj.oldState;
        //consider calling jjOBJ::unfreeze() here
        break;
      case STATE::DEACTIVATE: //can be left out if level is MP-only
        obj.deactivate();
        break;
      case STATE::KILL: //can be left out if not using normal object energy handling
        //obj.particlePixelExplosion();
        obj.delete();
        break;
      }
    }
    void onDraw(jjOBJ @ obj) {
      obj.draw();
    }
  }
  void IceCloud(jjOBJ @ obj) {
    obj.behave(BEHAVIOR::TOASTERBULLET, true);
    int playerID = obj.findNearestPlayer(30000);
    if (obj.state == STATE::FLY && obj.doesCollide(jjPlayers[playerID], true)) {
      jjPlayers[playerID].freeze(true);
      jjPlayers[playerID].xSpeed -= (obj.xSpeed / (obj.direction == -1 ? 8 : -8)) * obj.direction;
    }
  }

  class IceDragBody: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(30000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      float t = float(jjGameTicks) / 30;
      obj.yPos = obj.yOrg + 50 * sin(t) * sin((2 + sin(t - 3.14 / 2)) * (obj.xAcc / 80));
      switch (obj.state) {
      case STATE::START:

        obj.determineCurFrame();
        obj.state = STATE::FLOAT;
        break;
      case STATE::FLOAT:
        obj.determineCurFrame();
        if (obj.creatorID != uint(obj.var[0])) //  dragon head
        {
          obj.xPos = obj.xOrg - 8 * (20 - obj.energy) * obj.direction;
          obj.xAcc = obj.special - (8 * (20 - obj.energy) * obj.direction);
          if (obj.counter < 130)
            obj.counter++;
          if (obj.counter >= 130) {
            if (obj.frameID != 5)
              obj.frameID = int((obj.counter - 130) / 7);
            obj.determineCurFrame();
            obj.counter++;
          }
          if (obj.counter >= 130 + 6 * 6 && obj.counter%10==0) {
            jjSample(obj.xPos, obj.yPos, SOUND::DEVILDEVAN_DRAGONFIRE);
            int bulletID3 = jjAddObject(OBJECT::FIRESHIELDBULLET, obj.xPos + obj.direction * 4, obj.yPos + 3, obj.objectID, CREATOR::OBJECT);
            jjOBJ @ o = jjObjects[bulletID3];
            o.direction = -1;
            o.xAcc = 0;
            o.xSpeed = 5 * obj.direction;
			o.animSpeed=1;
           // o.ySpeed = 2;
           // o.determineCurAnim(ANIM::CUSTOM[22], 3);
		    //o.determineCurAnim(ANIM::CUSTOM[24], 2);
            o.playerHandling = HANDLING::ENEMYBULLET;
            o.counterEnd = 50;
           // o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
           

          }
          if (obj.counter == 130 + 15 * 7) {
            obj.frameID = 0;
            obj.counter = 0;
          }
          if (obj.direction == -1 && obj.xAcc >= -8)
            obj.state = STATE::KILL;
          else if (obj.direction == 1 && obj.xAcc <= 8)
            obj.state = STATE::KILL;
        } else { // dragon bodyparts 
          if (obj.ySpeed <= 20 - jjObjects[obj.creatorID].energy)
            obj.delete();
          else if (obj.energy < 20) {
            jjObjects[obj.creatorID].energy -= 1;
            obj.energy = 20;

          }
        }

        if (obj.doesCollide(jjPlayers[playerID], true) || x * x + y * y < 32 * 32) {
        //  jjPlayers[playerID].freeze(true);
          jjPlayers[playerID].xSpeed += 16 * obj.direction;
          jjPlayers[playerID].hurt(1, false);
        }

        break;
      case STATE::FREEZE:
        obj.unfreeze(0);
        obj.state = obj.oldState;
        //consider calling jjOBJ::unfreeze() here
        break;
      case STATE::DEACTIVATE: //can be left out if level is MP-only
        obj.deactivate();
        break;
      case STATE::KILL: //can be left out if not using normal object energy handling
        //obj.particlePixelExplosion();
        obj.particlePixelExplosion(2);
        obj.delete();
        break;
      }
    }
    void onDraw(jjOBJ @ obj) {
	if(obj.creatorID != uint(obj.var[0]))
	{
      if (obj.justHit == 0) {
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction,  SPRITE::NORMAL,0,3);
      } else
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15,3);
		}
		else {
		 if (obj.justHit == 0) {
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL);
      } else
        jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15);
    }
	}
    
	
  }
  // I used lots of class instances without their real meaning here, forgive me for that
  
  class IceDrag: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      if (obj.state == STATE::START) {
        if (jjMaskedPixel(int(obj.xPos + 32), int(obj.yPos)) == true)
          obj.direction = -1;
        else obj.direction = 1;
        int DragHead = jjAddObject(OBJECT::CRAB, obj.xPos + 8 * 19 * obj.direction - ((19 == 19 ? (-5) : 0) + (19 > 0 ? (-3) : 0)) * obj.direction, obj.yPos, obj.objectID, CREATOR::OBJECT);
        jjOBJ @ oo = jjObjects[DragHead];
        oo.determineCurAnim(ANIM::CUSTOM[22], 0);
        oo.frameID = 0;
        oo.direction = obj.direction;
        oo.deactivates = false;
        oo.counter = 0;
        oo.behavior = SMOKE::IceDragBody();
		int temp=int(oo.xAcc);
        oo.special = temp= 8 * 19 * obj.direction + ((19 == 19 ? (5) : 0) + (19 > 0 ? (3) : 0)) * obj.direction;
        oo.yAcc = oo.xPos;
        for (int i = 0; i < 19; i++) {
          int DragBody = jjAddObject(OBJECT::CRAB, obj.xPos + 8 * i * obj.direction + (i > -1 ? (3) : 0) * obj.direction, obj.yPos, DragHead, CREATOR::OBJECT);
          jjOBJ @ o = jjObjects[DragBody];
          o.behavior = SMOKE::IceDragBody();
          if (i == 0) {
            o.frameID = 0;
            o.determineCurAnim(ANIM::CUSTOM[22], 1);
          }
          if (i > 0 && i < 19) {
            o.frameID = 0;
            o.determineCurAnim(ANIM::CUSTOM[22], 1);
          }
          o.direction = obj.direction;
          o.special = o.xAcc = 8 * i * obj.direction + (i > 0 ? (3) : 0) * obj.direction;
          o.yAcc = obj.xPos;
          o.ySpeed = 18 - i + 1;
          o.var[0] = DragHead;
          o.isBlastable = false;
          o.deactivates = false;
        }
        obj.state = STATE::KILL;

      } else obj.delete();
    }

  }

  class FrozenShade: jjBEHAVIORINTERFACE {
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      obj.direction = int(x / abs(x));
      switch (obj.state) {
      case STATE::START:
        obj.determineCurAnim(ANIM::CUSTOM[23], 0);
        obj.special = 80;
        obj.state = STATE::IDLE;
        break;
      case STATE::IDLE:
        obj.counter++;
        obj.xPos = obj.xOrg + sin(2 * float(obj.counter) / 90) * 16;
        obj.yPos = obj.yOrg + cos(2 * float(obj.counter) / 90) * 16;
        if (x * x + y * y <= 400 * 400)
          obj.special++;
        obj.frameID = (obj.counter / 7) % 4;
        obj.determineCurFrame();

        if (obj.special == 140) {
          obj.state = STATE::ATTACK;
          obj.special = 0;
          obj.frameID = 0;
          obj.determineCurAnim(ANIM::CUSTOM[23], 1);
          obj.determineCurFrame();
        }
        break;
      case STATE::ATTACK:

        // obj.determineCurAnim(ANIM::CUSTOM[21], 1);

        obj.special++;
        // obj.counter++;

        obj.frameID = obj.special / 7;
        obj.determineCurFrame();
        if (obj.special == 7 * 5 + 4) {
          jjSample(obj.xPos, obj.yPos, SOUND::AMMO_ICEPU2, 90);
          for (int i = -1; i < 2; i++) {
            int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 15, obj.yPos-8, obj.objectID, CREATOR::OBJECT);
            jjOBJ @ o = jjObjects[bulletID3];
            o.determineCurAnim(ANIM::CUSTOM[23], 3);
            o.direction = obj.direction;
            o.xSpeed = 0 * obj.direction;
            o.xAcc = obj.direction * 0.11;
			o.yAcc=0;
			o.counterEnd=60;
            o.ySpeed = 2 * i;
            o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
            o.playerHandling = HANDLING::ENEMYBULLET;
          }

        }
        if (obj.special == 10 * 7 - 1) {
          obj.determineCurAnim(ANIM::CUSTOM[23], 0);
          obj.state = STATE::IDLE;
          obj.special = 0;
        }
        break;

      case STATE::FREEZE:
        if (--obj.freeze == 0) obj.state = obj.oldState;
        //consider calling jjOBJ::unfreeze() here
        break;
      case STATE::DEACTIVATE: //can be left out if level is MP-only
        obj.deactivate();
        break;
      case STATE::KILL: //can be left out if not using normal object energy handling
        //obj.particlePixelExplosion();
        obj.delete();
        break;
      }
    }
    void onDraw(jjOBJ @ obj) {
      obj.draw();
    }
  }
  enum KangarooVariables {
    kvWIDTH = 0, kvHEIGHT, kvMINX, kvMAXX, kvMINY, kvMAXY, kvJUMPDELAY, kvMINDISTANCE, kvGLOVE1FRAME, kvGLOVE2FRAME, kvSECONDSTAGE
  }
  //credts to violetCLM
  jjOBJ @ SNOWMAN(uint8 eventID, int minX = 0, int maxX = 4, int minY = 6, int maxY = 12, int jumpDelay = 35, int minDistance = 224, int hp = 3) {
    //Kangaroo::Private::loadAnims();
    jjAnimSets[ANIM::CUSTOM[19]].load(4, "HH18E1.j2a");
    jjOBJ @ preset = jjObjectPresets[eventID];
    preset.behavior = Snowman;
    preset.state=STATE::START;
    preset.frameID = 0;
    preset.determineCurFrame();
    preset.determineCurAnim(ANIM::CUSTOM[19], 0);
    SMOKE::applyGenericEnemySettingsToPreset(preset);

    preset.deactivates = true;
    preset.energy = hp;
    preset.points = 200;
    preset.yAcc = 0.33f;
    preset.counter = 0;
    preset.var[kvWIDTH] = 12;
    preset.var[kvHEIGHT] = 28;
    preset.var[kvMINX] = minX;
    preset.var[kvMAXX] = maxX;
    preset.var[kvMINY] = minY;
    preset.var[kvMAXY] = maxY;
    preset.var[kvJUMPDELAY] = jumpDelay;
    preset.var[kvMINDISTANCE] = minDistance;
	preset.age=0;

    return preset;
  }
  
  //thanks VioletCLM
  void Snowman(jjOBJ @ obj) {
    float X = jjLocalPlayers[0].xPos - obj.xPos;
    float Y = jjLocalPlayers[0].yPos - obj.yPos;
    const int width = obj.var[kvWIDTH];
    const int height = obj.var[kvHEIGHT];
    switch (obj.state) {
    case STATE::START:
      obj.state = STATE::IDLE;
      SMOKE::putEnemyOnGround(obj);
	 
    case STATE::IDLE:
	      SMOKE::putEnemyOnGround(obj);
	if(obj.frameID!=2)
       obj.frameID=obj.age/14;
      if (obj.counter <= 0 || --obj.counter == 0) {
        const int nearestPlayerID = obj.findNearestPlayer(int(pow(obj.var[kvMINDISTANCE], 2)));
        if (nearestPlayerID >= 0) {
			  obj.age++;

          jjPLAYER @ nearestPlayer = jjPlayers[nearestPlayerID];
          obj.xSpeed = (nearestPlayer.xPos - obj.xPos) / 20.0f;
          obj.direction = (obj.xSpeed >= 0) ? 1 : -1;

          float xSpeed = abs(obj.xSpeed);
          if (xSpeed > obj.var[kvMAXX]) xSpeed = obj.var[kvMAXX];
          else if (xSpeed < obj.var[kvMINX]) xSpeed = obj.var[kvMINX];
          obj.xSpeed = xSpeed * obj.direction;

          float ySpeed = abs((nearestPlayer.yPos - obj.yPos) / 20.0f);
          if (ySpeed > obj.var[kvMAXY]) ySpeed = obj.var[kvMAXY];
          else if (ySpeed < obj.var[kvMINY]) ySpeed = obj.var[kvMINY];
          obj.ySpeed = -ySpeed;
         if(obj.age==49)
		 {
		  obj.ySpeed=-8;
          obj.state = STATE::JUMP;
          obj.counter = obj.var[kvJUMPDELAY];
          jjSample(obj.xPos, obj.yPos, ((jjRandom() & 1) == 0) ? SOUND::BUBBA_BUBBABOUNCE1 : SOUND::BUBBA_BUBBABOUNCE2);
        }
		} else
          obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
      }
      if (jjLocalPlayers[0].specialMove != 0 && (X * X + Y * Y < 300 * 300)) {
        obj.ySpeed = -8;
        obj.xSpeed = obj.var[kvMINY] * obj.direction;
        obj.state = STATE::JUMP;
        jjSample(obj.xPos, obj.yPos, SOUND::COMMON_JUMP);
      }
      obj.determineCurFrame();
      break;
    case STATE::FREEZE:
      if (obj.freeze > 0)
        --obj.freeze;
      if (obj.freeze <= 0) {
        obj.state = obj.oldState;
        obj.unfreeze(0);
      }
      break;
    case STATE::JUMP:
      {
        obj.yPos += (obj.ySpeed += obj.yAcc);
        const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction) / 2;
        if ((newXPos < 0) || (newXPos > jjLayerWidth[4] * 32) || jjMaskedVLine(newXPos, int(obj.yPos - height / 2), height)) {
          obj.xSpeed = -obj.xSpeed;
          obj.direction = -obj.direction;
        }
        obj.xPos += obj.xSpeed;
        int newYPos = int(obj.yPos + obj.ySpeed);
        if (obj.ySpeed < 0) {
          if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos - height / 2)) {
            obj.ySpeed = obj.yAcc;
            obj.frameID = 2;
          } else obj.frameID = 1;
        }
        if (obj.ySpeed > 0) {
          if ((newYPos > jjLayerHeight[4] * 32) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos + height / 2)) {
            obj.state = STATE::DUCK;
            // obj.yPos-=2;
            obj.ySpeed = 0;
            obj.frameID = 0;
            obj.counter = 0;
            obj.xSpeed = 7 * obj.direction;
            SMOKE::putEnemyOnGround(obj);
          } else obj.frameID = 2;
        }
        obj.determineCurFrame();
        break;

      }
    case STATE::DUCK:
      {

        if (obj.xSpeed > 0 && abs(obj.xSpeed) > 0.1)
          obj.xSpeed -= 0.07;
        if (obj.xSpeed < 0 && abs(obj.xSpeed) > 0.1)
          obj.xSpeed += 0.07;
        if (abs(obj.xSpeed) < 0.1)
          obj.xSpeed = 0;
        if (obj.xSpeed > 0)
          obj.direction = 1;
        else obj.direction = -1;

        obj.determineCurAnim(ANIM::CUSTOM[19], 2);
        obj.frameID = int((jjGameTicks / 7) % 4);
        //obj.yPos += (obj.ySpeed += obj.yAcc);
        const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction) / 2;

        if ((newXPos < 0) || (newXPos > jjLayerWidth[4] * 32) || jjMaskedVLine(newXPos, int(obj.yPos - height / 2) - 2, height - 8)) {
          obj.xSpeed = -obj.xSpeed;
          if (obj.xSpeed != 0)
            obj.direction = -obj.direction;
        }

        obj.xPos += obj.xSpeed;
        int newYPos = int(obj.yPos + obj.ySpeed);
        if (obj.ySpeed < 0) {
          if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos - height / 2)) {
            obj.ySpeed = obj.yAcc;

          }
        }
        if ((newYPos > jjLayerHeight[4] * 32) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos + height / 2)) {
          obj.special = 0;
          obj.counter++;
        } else {
          obj.special++;
          obj.yPos += obj.special * obj.yAcc;
        }
        obj.determineCurFrame();
        if (obj.counter == 100) {
          obj.frameID = 0;
		  obj.age=0;
          obj.state = STATE::IDLE;
          obj.counter = obj.var[kvJUMPDELAY];
          obj.determineCurAnim(ANIM::CUSTOM[19], 0);
        }
        break;
      }

    case STATE::DEACTIVATE:
      obj.deactivate();
      return;
    case STATE::KILL:
      obj.delete();
      return;
    }
    obj.draw();
  }
  void putKangarooOnGround(jjOBJ @ obj, int width, int height) {
    while (!jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height / 1))
      obj.yPos += 1;
  }
   void putEnemyOnGround(jjOBJ @ obj) {
    int width=jjAnimFrames[obj.curFrame].width;
   int height=jjAnimFrames[obj.curFrame].height;
   int hotY=jjAnimFrames[obj.curFrame].hotSpotY;
    while (!jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height + hotY))
      obj.yPos += 1;
	  //  while (jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height + hotY))
     // obj.yPos -= 1;
  }
    void liftEnemyFromGround(jjOBJ @ obj) {
    int width=jjAnimFrames[obj.curFrame].width;
   int height=jjAnimFrames[obj.curFrame].height;
   int hotY=jjAnimFrames[obj.curFrame].hotSpotY;
    while (jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height + hotY))
      obj.yPos -= 1;
  }
  void applyGenericEnemySettingsToPreset(jjOBJ @ preset) {
    preset.playerHandling = HANDLING::ENEMY;
    preset.bulletHandling = HANDLING::HURTBYBULLET;
    preset.causesRicochet = false;
    preset.isBlastable = false;
    preset.triggersTNT = true;
    preset.isFreezable = true;
    preset.isTarget = true;
    preset.scriptedCollisions = false;
    preset.direction = 1;
    preset.freeze = 0;
  }
  class CrystalKnight : jjBEHAVIORINTERFACE{
  float angle;
   void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(8000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      switch (obj.state) {
      case STATE::START:
        obj.direction = 1;
        obj.state = STATE::FLOAT;
        break;
      case STATE::FLOAT:
        obj.counter++;
        /*if (x * x + y * y <= 320 * 320)
          obj.special++;*/
        obj.frameID = (jjGameTicks / 7) % 3;
        obj.determineCurFrame();
        for (int i = 0; i < jjLocalPlayerCount; i++) {
          jjPLAYER @ p = jjLocalPlayers[i];
          if (obj.xPos < p.xPos) {
            obj.direction = 1;
          }
          if (obj.xPos > p.xPos) {
            obj.direction = -1;
          }
        }
		 if (x * x + y * y <= (10+jjDifficulty)*32* (10+jjDifficulty)*32)
		 {
          obj.special++;
		 angle= atan2((obj.yPos - jjPlayers[playerID].yPos), (obj.xPos- jjPlayers[playerID].xPos));
        obj.xPos -=cos(angle)*2+sin(jjGameTicks/20);
        obj.yPos -=sin(angle)*2+sin(jjGameTicks/10);
		}
		else 
		{
		obj.xPos+=sin(2 * float(jjGameTicks) / 90) * (12/8);
	  obj.yPos+=2*cos(7 * float(jjGameTicks) / 90) * (12/8);
		}
        if (obj.special == 120) {
          obj.state = STATE::ATTACK;
          obj.special = 0;
          obj.determineCurFrame();
		  obj.determineCurAnim(ANIM::CUSTOM[24], 1);
        
		  }
        
        break;
      case STATE::ATTACK:
	  if(obj.frameID<5)
        obj.frameID = (obj.special / 5) ;
		obj.determineCurFrame();
        obj.special++;
        //obj.counter++;
         if (obj.special == 4*6) {
        for(int i=-1;i<2;i+=1)
		  {
          int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 34, obj.yPos - 10);
          jjOBJ @ bull3 = jjObjects[bulletID3];
          bull3.behavior = SMOKE::CrystalBall();
		  bull3.state=STATE::START;
          bull3.determineCurAnim(ANIM::CUSTOM[24], 2);
		  bull3.playerHandling = HANDLING::ENEMYBULLET;
		  bull3.xAcc=bull3.yAcc=0;
		  bull3.special=i;
		  bull3.counter=0;
		  bull3.counterEnd=200;
		  bull3.killAnim=jjAnimSets[ANIM::AMMO].firstAnim+82;
		 // bull3.killAnim=jjObjectPresets[OBJECT::PLASMASHIELDBULLET].killAnim;
          obj.determineCurFrame();
		  obj.determineCurAnim(ANIM::CUSTOM[24], 1);
          jjSample(obj.xPos, obj.yPos, SOUND::AMMO_ICEPU4);
		  }
		  }
        if (obj.special == 8*6) {
          obj.determineCurAnim(ANIM::CUSTOM[24], 0);
          obj.state = STATE::FLOAT;
          obj.special = 0;
        }
        break;

      case STATE::FREEZE:
        if (--obj.freeze == 0) obj.state = obj.oldState;
        //consider calling jjOBJ::unfreeze() here
        break;
      case STATE::DEACTIVATE: //can be left out if level is MP-only
        obj.deactivate();
        break;
      case STATE::KILL: //can be left out if not using normal object energy handling
        //obj.particlePixelExplosion();
        obj.delete();
        break;
      }
    }
    void onDraw(jjOBJ @ obj) {
      obj.draw();
    }
  }
  class CrystalBall :jjBEHAVIORINTERFACE{
  float angle;
 void onBehave(jjOBJ @ obj) {
 
 int targetID = 0;
     if(obj.counter==0)
	  angle= atan2((obj.yOrg - jjPlayers[targetID].yPos), (obj.xOrg- jjPlayers[targetID].xPos));
	
	obj.xSpeed=(-cos(angle)-sin(angle)*obj.special*2*cos(float(2*obj.counter)/20))*3;
	obj.ySpeed=(-sin(angle)+cos(angle)*obj.special*2*cos(float(2*obj.counter)/20))*3;
	obj.behave(BEHAVIOR::BULLET, true);
			
   
  }
  }
  
  
  jjOBJ @ SNOWMAN2(uint8 eventID, int minX = 0, int maxX = 4, int minY = 6, int maxY = 12, int jumpDelay = 35, int minDistance = 224, int hp = 3) {
    //Kangaroo::Private::loadAnims();
    jjAnimSets[ANIM::CUSTOM[26]].load(10, "HH18E1.j2a");
    jjOBJ @ preset = jjObjectPresets[eventID];
    preset.behavior = Snowman2;

    preset.frameID = 0;
    preset.determineCurFrame();
    preset.determineCurAnim(ANIM::CUSTOM[26],0);
    SMOKE::applyGenericEnemySettingsToPreset(preset);

    preset.deactivates = true;
    preset.energy = hp;
    preset.points = 200;
    preset.yAcc = 0.33f;
    preset.counter = 0;
    preset.var[kvWIDTH] = 12;
    preset.var[kvHEIGHT] = 28;
    preset.var[kvMINX] = minX;
    preset.var[kvMAXX] = maxX;
    preset.var[kvMINY] = minY;
    preset.var[kvMAXY] = maxY;
    preset.var[kvJUMPDELAY] = jumpDelay;
    preset.var[kvMINDISTANCE] = minDistance;

    return preset;
  }
  
  void Snowman2(jjOBJ @ obj) {
    float X = jjLocalPlayers[0].xPos - obj.xPos;
    float Y = jjLocalPlayers[0].yPos - obj.yPos;
    const int width = obj.var[kvWIDTH];
    const int height = obj.var[kvHEIGHT];
    switch (obj.state) {
    case STATE::START:
      obj.state = STATE::IDLE;
      SMOKE::putEnemyOnGround(obj);
    case STATE::IDLE:
      SMOKE::putEnemyOnGround(obj);
	if(obj.frameID!=2)
       obj.frameID=obj.age/14;
      if (obj.counter <= 0 || --obj.counter == 0) {
        const int nearestPlayerID = obj.findNearestPlayer(int(pow(obj.var[kvMINDISTANCE], 2)));
        if (nearestPlayerID >= 0) {
			  obj.age++;

          jjPLAYER @ nearestPlayer = jjPlayers[nearestPlayerID];
          obj.xSpeed = (nearestPlayer.xPos - obj.xPos) / 20.0f;
          obj.direction = (obj.xSpeed >= 0) ? 1 : -1;

          float xSpeed = abs(obj.xSpeed);
          if (xSpeed > obj.var[kvMAXX]) xSpeed = obj.var[kvMAXX];
          else if (xSpeed < obj.var[kvMINX]) xSpeed = obj.var[kvMINX];
          obj.xSpeed = xSpeed * obj.direction;

          float ySpeed = abs((nearestPlayer.yPos - obj.yPos) / 20.0f);
          if (ySpeed > obj.var[kvMAXY]) ySpeed = obj.var[kvMAXY];
          else if (ySpeed < obj.var[kvMINY]) ySpeed = obj.var[kvMINY];
          obj.ySpeed = -ySpeed;
         if(obj.age==49)
		 {
		  obj.ySpeed=-10;
          obj.state = STATE::JUMP;
          obj.counter = obj.var[kvJUMPDELAY];
          jjSample(obj.xPos, obj.yPos, ((jjRandom() & 1) == 0) ? SOUND::BUBBA_BUBBABOUNCE1 : SOUND::BUBBA_BUBBABOUNCE2);
        }
		} else
          obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
      }
      if (jjLocalPlayers[0].specialMove != 0 && (X * X + Y * Y < 300 * 300)) {
        obj.ySpeed = -8;
        obj.xSpeed = obj.var[kvMINY] * obj.direction;
        obj.state = STATE::JUMP;
        jjSample(obj.xPos, obj.yPos, SOUND::COMMON_JUMP);
      }
      obj.determineCurFrame();
      break;
    case STATE::FREEZE:
      if (obj.freeze > 0)
        --obj.freeze;
      if (obj.freeze <= 0) {
        obj.state = obj.oldState;
        obj.unfreeze(0);
      }
      break;
    case STATE::JUMP:
      {
	  obj.counter++;
        obj.yPos += (obj.ySpeed += obj.yAcc);
        const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction) / 2;
        if ((newXPos < 0) || (newXPos > jjLayerWidth[4] * 32) || jjMaskedVLine(newXPos, int(obj.yPos - height / 2), height)) {
          obj.xSpeed = -obj.xSpeed;
          obj.direction = -obj.direction;
        }
        obj.xPos += obj.xSpeed;
        int newYPos = int(obj.yPos + obj.ySpeed);
        if (obj.ySpeed < 0) {
          if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos - height / 2)) {
            obj.ySpeed = obj.yAcc;
            obj.frameID = 2;
          } else obj.frameID = 1;
        }
        if (obj.ySpeed > 0) {
          if ((newYPos > jjLayerHeight[4] * 32) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos + height / 2)) {
            obj.state = STATE::FIRE;
            // obj.yPos-=2;
            obj.ySpeed = 0;
            obj.frameID = 0;
            obj.counter = 1;
            obj.xSpeed = 7 * (jjLocalPlayers[0].xPos - obj.xPos) / abs((jjLocalPlayers[0].xPos - obj.xPos));
            SMOKE::putEnemyOnGround(obj);
          } else obj.frameID = 2;
        }
        obj.determineCurFrame();
		if(obj.counter%20==0)
		{
	    
	   int bulletID2 = jjAddObject(OBJECT::BLASTERBULLET,obj.xPos,  obj.yPos +15);
          jjOBJ @ bull2 = jjObjects[bulletID2];
		  bull2.determineCurAnim(114,1 );
		  obj.age=0;
          bull2.xAcc = 0;
          bull2.xSpeed = 0;
          bull2.yAcc = 0.15;
          bull2.ySpeed = 0;
          bull2.counterEnd = 80;
          bull2.playerHandling = HANDLING::ENEMYBULLET;
		  bull2.killAnim=jjObjectPresets[OBJECT::RFBULLET].killAnim;
          jjSample(obj.xPos, obj.yPos, SOUND::AMMO_LAZRAYS);
	 
	 }
        break;

      }
    case STATE::FIRE:
     obj.counter++;
	
	 if(obj.counter==30)
	 {
	 obj.state=STATE::IDLE;
	 obj.determineCurAnim(ANIM::CUSTOM[26],0);
	 }
        break;
      

    case STATE::DEACTIVATE:
      obj.deactivate();
      return;
    case STATE::KILL:
      obj.delete();
      return;
    }
    obj.draw();
  }
  
  
 
  
}