Copy to Clipboard Test

Z2 True Evil Blob Code

const int SFX_Z2_TRUE_FINAL_BOSS_BOUNCE = 3;//Sound used to bounce off solid combos, when boss is vulnerable.
const int SFX_Z2_TRUE_FINAL_BOSS_BERSERK = 56;//Sound to play, when boss goes berserk(low HP).

const int LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE = 8;//ID of Lweapon used to expose boss eye.
const int LW_Z2_TRUE_FINAL_BOSS_RELEASE_HEAD = 1;//ID of Lweapon used to render boss vulnerable to various harmful stuff.

const int LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE_MINDAMAGE = 8;//Minimum damage needed for LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE to work.

const int Z2_TRUE_FINAL_BOSS_BERSERK_HP_THRESHOLD = 64;//Berserk HP threshold
const int Z2_TRUE_FINAL_BOSS_BERSERK_SPEED_MODIFIER = 100;//Berserk speed modifier

//Evil Blob Tries to jump on top of Link, triple-firing eweapons at Link. Hit him with Silver Arrow to expose his eye, then hit him with sword to send him mad and bounce off walls, like Armadillo, then use all your weapons to dish out as much damage, as you can before the boss recovers. 

//Uses 5 rows of tiles, normal ,then jumping directly below, then the same 2 rows but with exposed eye, then one for bouncing state.

ffc script Z2TrueFinalBoss{
	void run(int enemyID){
		npc ghost = Ghost_InitAutoGhost(this, enemyID);
		
		int HF = ghost->Homing;
		int HR = ghost->Haltrate;
		int RR = ghost->Rate;
		int HNG = ghost->Hunger;
		int SPD = ghost->Step;
		int WPND = ghost->WeaponDamage;
		
		int sizex = Ghost_GetAttribute(ghost, 0, 4);//Tile Width
		int sizey = Ghost_GetAttribute(ghost, 1, 4);//Tile Height
		int jumpdelay = Ghost_GetAttribute(ghost, 2, 42);//minimum delay between jumps, in frames.
		int maxjumpdelay = Ghost_GetAttribute(ghost, 3, 60);//Maximum delay between jumps, in frames.
		int jumppower = Ghost_GetAttribute(ghost, 4, 320);//jumping height
		int moveangle = Ghost_GetAttribute(ghost, 5, 0);//0 - use diagonal dumps only, 1 - 8-way jumping, 2+ = fine jumping angle
		int esposeduration = Ghost_GetAttribute(ghost, 6, 120);//Duration between eye exposure and eye closing, in frames
		int WPNS = Ghost_GetAttribute(ghost, 7, -1);//Eweapon sprite
		int numbounces = Ghost_GetAttribute(ghost, 8, 20);//Number of bounces in ball form before returning to normal state.
		int rolldamage = Ghost_GetAttribute(ghost, 9, ghost->Damage+2);//Damage caused by trampling Link in ball form, in 1/4ths of heart
		
		ghost->Extend=3;
		Ghost_SetSize(this, ghost, sizex, sizey);
		if (sizex>2)Ghost_SetHitOffsets(ghost, 4, 4, 8, 8);
		
		int State = 0;
		
		int haltcounter = -1;
		int statecounter = jumpdelay+Rand(maxjumpdelay-jumpdelay);
		eweapon e;
		lweapon l;
		int angle=0;
		int origtile = ghost->OriginalTile;
		int offset = 0;
		float xStep=0;
		float yStep=0;
		int angle4[4]={45,135,-45,-135};
		int angle8[8]={0,45,90,135,180,-135,-90,-45};
		int exposetimer = 0;
		int Ghost_MaxHP = Ghost_HP;
		int origdam = ghost->Damage;
		bool berserk=false;
		int rollspeed = SPD+20;
		
		Ghost_SetFlag(GHF_NORMAL);
		Ghost_UnsetFlag(GHF_KNOCKBACK);	
		
		int defs[18];
		Ghost_StoreDefenses(ghost,defs);
		Ghost_SetAllDefenses(ghost, NPCDT_IGNORE);
		
		while(true){
			if (State==0){
				statecounter--;
				if (statecounter==0){
					angle = Angle(CenterX(ghost),CenterY(ghost),CenterLinkX(),CenterLinkY());
					if (Rand(256)>=HF) angle = Rand(360);
					if (moveangle==0) angle = GetClosestFromArray(angle4, angle);
					if (moveangle==1) angle = GetClosestFromArray(angle8, angle);
					xStep = SPD/100*Cos(angle);
					yStep = SPD/100*Sin(angle);
					Ghost_Jump=jumppower/100;
					offset = 20*Ghost_TileHeight;
					State=1;
				}
				if (exposetimer>0)exposetimer--;
				for (int i=1;i<=Screen->NumLWeapons();i++){
					if (exposetimer>0)break;
					lweapon l = Screen->LoadLWeapon(i);
					if (l->ID!=LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE) continue;
					if (l->Damage<LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE_MINDAMAGE) continue;
					if (!Collision(l,ghost)) continue;
					Remove(l);
					Game->PlaySound(SFX_EHIT);
					exposetimer = esposeduration;
				}
				for (int i=1;i<=Screen->NumLWeapons();i++){
					if (exposetimer==0)break;
					lweapon l = Screen->LoadLWeapon(i);
					if (l->ID!=LW_Z2_TRUE_FINAL_BOSS_RELEASE_HEAD) continue;
					if (!Collision(l,ghost)) continue;
					Game->PlaySound(SFX_EHIT);
					statecounter = numbounces;
					ghost->Damage =  rolldamage;
					Ghost_SetDefenses(ghost, defs);
					angle = Angle(CenterX(ghost),CenterY(ghost), CenterLinkX(), CenterLinkY())+180;
					xStep=rollspeed*Cos(angle)/100;
					yStep=rollspeed*Sin(angle)/100;
					exposetimer = 0;
					offset=80*Ghost_TileHeight;
					State=2;
				}
			}
			else if (State==1){				
				
				if(xStep<0)// Bounce
				{
					if(!Ghost_CanMove(DIR_LEFT, -xStep, 3))
					xStep*=-1;
				}
				else
				{
					if(!Ghost_CanMove(DIR_RIGHT, xStep, 3))
					xStep*=-1;
				}
				
				if(yStep<0)
				{
					if(!Ghost_CanMove(DIR_UP, -yStep, 3))
					yStep*=-1;
				}
				else
				{
					if(!Ghost_CanMove(DIR_DOWN, yStep, 3))
					yStep*=-1;
				}
				Ghost_MoveXY(xStep, yStep, 3);
				if (Ghost_Z<=0&&Ghost_Jump<=0){
					e=FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8-Ghost_Z, 0, 180, WPND, WPNS, -1, EWF_ROTATE);
					e=FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8-Ghost_Z, 0.2, 180, WPND, WPNS, -1, EWF_ROTATE);
					e=FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8-Ghost_Z, -0.2, 180, WPND, WPNS, -1, EWF_ROTATE);
					statecounter = jumpdelay+Rand(maxjumpdelay-jumpdelay);
					offset = 0;
					Ghost_Z=0;
					xStep=0;
					yStep=0;
					State=0;
				}
				if (exposetimer>0)exposetimer--;
				for (int i=1;i<=Screen->NumLWeapons();i++){
					if (exposetimer>0)break;
					lweapon l = Screen->LoadLWeapon(i);
					if (l->ID!=LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE) continue;
					if (l->Damage<LW_Z2_TRUE_FINAL_BOSS_EXPOSE_FACE_MINDAMAGE) continue;
					if (!Collision(l,ghost)) continue;
					Remove(l);
					Game->PlaySound(SFX_EHIT);
					exposetimer = esposeduration;
				}
				for (int i=1;i<=Screen->NumLWeapons();i++){
					if (exposetimer==0)break;
					lweapon l = Screen->LoadLWeapon(i);
					if (l->ID!=LW_Z2_TRUE_FINAL_BOSS_RELEASE_HEAD) continue;
					if (!Collision(l,ghost)) continue;
					Game->PlaySound(SFX_EHIT);
					statecounter = numbounces;
					ghost->Damage =  rolldamage;
					Ghost_SetDefenses(ghost, defs);
					angle = Angle(CenterX(ghost),CenterY(ghost), CenterLinkX(), CenterLinkY());
					xStep=rollspeed*Cos(angle)/100;
					yStep=rollspeed*Sin(angle)/100;
					exposetimer = 0;
					offset=80*Ghost_TileHeight;
					State=2;
				}
			}
			else if (State==2){
				if(xStep<0)	{
					if(!Ghost_CanMove(DIR_LEFT, -xStep, 3)){
						if (sizex>1 || sizey>1)Game->PlaySound(SFX_Z2_TRUE_FINAL_BOSS_BOUNCE);
						statecounter--;
						xStep*=-1;
					}
				}
				else{
					if(!Ghost_CanMove(DIR_RIGHT, xStep, 3)){
						if (sizex>1 || sizey>1)Game->PlaySound(SFX_Z2_TRUE_FINAL_BOSS_BOUNCE);
						statecounter--;
						xStep*=-1;
					}
				}
				
				if(yStep<0)	{
					if(!Ghost_CanMove(DIR_UP, -yStep, 3)){
						if (sizex>1 || sizey>1)Game->PlaySound(SFX_Z2_TRUE_FINAL_BOSS_BOUNCE);
						statecounter--;
						yStep*=-1;
					}
				}
				else{
					if(!Ghost_CanMove(DIR_DOWN, yStep, 3)){
						if (sizex>1 || sizey>1)Game->PlaySound(SFX_Z2_TRUE_FINAL_BOSS_BOUNCE);
						statecounter--;
						yStep*=-1;
					}
				}
				if (statecounter>0){
					Ghost_MoveXY(xStep, yStep,2);
				}
				else{
					statecounter = jumpdelay+Rand(maxjumpdelay-jumpdelay);;
					ghost->Damage =  origdam;
					Ghost_SetAllDefenses(ghost, NPCDT_IGNORE);
					offset = 0;
					State=0;
				}
			}
			if (!berserk&&(Z2_TRUE_FINAL_BOSS_BERSERK_HP_THRESHOLD>0)&&Ghost_HP<Z2_TRUE_FINAL_BOSS_BERSERK_HP_THRESHOLD){
				SPD+=Z2_TRUE_FINAL_BOSS_BERSERK_SPEED_MODIFIER;
				Game->PlaySound(SFX_Z2_TRUE_FINAL_BOSS_BERSERK);
				if (State==2){
					angle = ArcTan(xStep,yStep)*57.2958;;
					xStep=(SPD/100*Cos(angle));
					yStep=(SPD/100*Sin(angle));
				}
				berserk=true;
			}
			if (exposetimer>0)offset+=40*Ghost_TileHeight;
			ghost->OriginalTile = origtile+offset;
			if (exposetimer>0)offset-=40*Ghost_TileHeight;
			// debugValue(1, Ghost_HP);
			//debugValue(2, Ghost_Z);
			if (!Ghost_Waitframe(this, ghost, false, false)){
				Ghost_DeathAnimation(this, ghost, GHD_EXPLODE);
				Quit();
			}
		}
	}
} 

int GetClosestFromArray(int arr, int target){
	int diff = 99999;
int newdiff;
int ret = 0;
for (int i=0;i<SizeOfArray(arr);i++){
	newdiff = Abs(arr[i]- target);
	if (newdiff>=diff) continue;
	diff=newdiff;
	ret = i;
	if (newdiff==0)return target;
}
return arr[ret];
}