Downloads containing HH24IceGolem.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Holiday Hare 24Featured Download PurpleJazz Single player 10 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_HH24 {
  int golemDeathCount = 0;
  int golemDuoHP = 0;
  const float PI = 3.1415927f;
  int maxHP = 0;

  void ICEGOLEMEDIT(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].bulletHandling=HANDLING::DETECTBULLET;
	jjObjectPresets[eventID].behavior = SMOKE_HH24::IceGolemEdit();
    jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[17], 0);
    jjObjectPresets[eventID].counter = 0;
	jjObjectPresets[eventID].energy = jjObjectPresets[eventID].var[0] = maxHP = jjObjectPresets[eventID].var[4] = hp;
	jjObjectPresets[eventID].xSpeed = 1 + (jjDifficulty/2);
	jjObjectPresets[eventID].var[2] = 140;
	jjObjectPresets[eventID].deactivates = false;
  }

  class IceGolemEdit : jjBEHAVIORINTERFACE {
    int armor, armorCounter;
	
	float bossHP = GolemMaxHP;
  
    void onBehave(jjOBJ @ obj) {
      int playerID = obj.findNearestPlayer(10000000);
      float x = -obj.xPos + jjPlayers[playerID].xPos;
      float y = -obj.yPos + jjPlayers[playerID].yPos;
      if(obj.state==STATE::START)
	  {
	  golemDuoHP = obj.energy * 2;
	  bossHP = GolemMaxHP;
	  }
	  
	  if (golemDeathCount < 0) {
		obj.delete();
	  }
	  
	  if (obj.var[4] > obj.energy) {
		golemDuoHP -= (obj.var[4] - obj.energy);
		obj.var[4] = obj.energy;
	  }
	  
	  obj.energy = int(bossHP);
	  
	  if (obj.justHit != 0) armorCounter = 0;
	  else armorCounter++;
	  
	  if (armorCounter > 0) {
		if (armorCounter < 35) {
			if (armorCounter % 7 == 0) {
				armor--;
			}
		}
		if (armorCounter >= 70) {
			if (armorCounter % 4 == 0) {
				armor--;
			}
		}
	  }
	  
	  if (armor > 20) armor = 20;
	  if (armor < 0) armor = 0;
	  
	  if (golemDeathCount > 0 && obj.counter < 140) {
		if (obj.var[1] == 0) {
			obj.bulletHandling = HANDLING::DETECTBULLET;
			obj.counter = 45;
			obj.special = 0;
			obj.var[1] = 1;
			obj.xSpeed = (2+jjDifficulty) * obj.direction;
			jjAlert("||YOU WILL PAY FOR THAT!",false,STRING::MEDIUM);
			obj.var[5] = 1;
			if (obj.energy < obj.var[0] - 4) {
				bossHP += maxHP;
				obj.energy += maxHP;
				obj.var[4] = obj.energy;
				golemDuoHP = int(bossHP);
			} else {
				obj.energy = golemDuoHP = obj.var[0];
				obj.var[4] = obj.energy;
			}
			jjSamplePriority(SOUND::INTRO_MONSTER);
			jjSamplePriority(SOUND::INTRO_MONSTER);
		}
	  }
	  
	  //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)
		{
			golemDeathCount++;
			obj.delete();
		}
			
      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.var[1] == 0) {
				if (obj.freeze == 0 && obj.special == (52-(jjDifficulty*8))) // 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_HH24::SpikeBall;
				  bull2.counterEnd=87;
				  // bull2.xSpeed = obj.direction * 4;
				 bull2.xSpeed=obj.direction*2.5;
				 bull2.ySpeed=-4;
				 bull2.yAcc=0.1;
				 bull2.xAcc=0;
				  // bull2.yAcc=-0.1;
				  bull2.playerHandling = HANDLING::ENEMYBULLET;
				  jjSamplePriority(SOUND::AMMO_ICEGUNPU);

				}
			} else {
				if (obj.freeze == 0 && obj.special >= 14 && obj.special % (11-(jjDifficulty*2)) == 0 && obj.special <= 49) // shoot bullets
				{
					int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + (42 * obj.direction), obj.yPos - 40, obj.objectID, CREATOR::OBJECT);
					jjOBJ @ o = jjObjects[bulletID3];
					o.behavior = Icicle;
					o.determineCurAnim(ANIM::CUSTOM[17], 3);
					o.direction = o.xSpeed < 0? 1:-1;
					o.xSpeed = -5 * o.direction;
					o.ySpeed = -1.5 + (0.1*(jjRandom()%30));
					o.xAcc = 0;
					o.yAcc = 0;
					o.counterEnd = 90;
					o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
					o.playerHandling = HANDLING::ENEMYBULLET;
					jjSamplePriority(SOUND::AMMO_ICEGUNPU);
				}
			}
			if (obj.special == 57) //end attack phase; start walking phase 
			{

			  obj.special = 0;
			  obj.counter = obj.var[1] == 0? 0 : (50+(jjDifficulty*15));
			  obj.xSpeed = (obj.var[1] == 0? 1.5:(2+jjDifficulty)) * (jjRandom()% 2 > 0? 1:-1);

			  obj.determineCurAnim(ANIM::CUSTOM[17], 0); //walking animation
			}
	}

      if ((obj.special == 0) && (x * x + y * y <= 560 * 560)) // 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, obj.var[1] > 0? SPRITE::TINTED : SPRITE::NORMAL, 50);
        } else
          jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, jjLocalPlayers[0].blink == 0? 15:32);
      }
	  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;
		  
		float multiplier = ((bullet.var[3] == 4 || bullet.var[3] == 5)? 0.4f : 0.6f) * (player.blink == 0? 1:0.5);
		
        bossHP -= ((damageCalc(obj, bullet, armor, player) > (bullet.animSpeed * multiplier))? damageCalc(obj, bullet, armor, player) : (bullet.animSpeed * multiplier)) * (player.blink == 0? 1:0.5);
		armor += bullet.animSpeed;
		
				/*jjPARTICLE@ text = jjAddParticle(PARTICLE::STRING);
				if (text !is null) {
					text.xPos = obj.xPos;
					text.yPos = obj.yPos;
					text.ySpeed = -0.25;
					text.string.text = "" + (damageCalc(obj,bullet,armor) > (bullet.animSpeed * multiplier)? damageCalc(obj,bullet,armor) : (bullet.animSpeed * multiplier));
				}*/
		
        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;
          if (golemDeathCount == 0 || obj.var[5] == 1) 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;
    }
  }

  float damageCalc(jjOBJ@ obj, jjOBJ@ bullet, int armor, jjPLAYER@ play) {
	if (armor <= bullet.animSpeed) {
		return bullet.animSpeed * (play.blink == 0? 1:0.125);
	} else {
		return (bullet.animSpeed - ((0.0125f * (bullet.animSpeed*3)) * armor)) * (play.blink == 0? 1:0.125);
	}
  }
  
  void SpikeBall(jjOBJ @ obj) {
    obj.behave(BEHAVIOR::BULLET, true);
    if (obj.state == STATE::EXPLODE && obj.isActive) {
		obj.unfreeze(1);
		if (jjDifficulty > 0) {
		 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 = 4*sin(i*3.141592/4);
			o.yAcc=0;
            o.xAcc=0;
            o.xSpeed = 4*cos(i*3.141592/4);
			o.counterEnd = 45;
            o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
            o.playerHandling = HANDLING::ENEMYBULLET;
          }
		}
		obj.delete();
		
	}
  }
  
  void Icicle(jjOBJ @ obj) {
    if (obj.state == STATE::EXPLODE && obj.isActive) {
      obj.unfreeze(1);
      obj.delete();
    }
    obj.behave(BEHAVIOR::BULLET, true);
  }
}