Copy to Clipboard Test

AcidHandla Code

import "std.zh"
import "ffcscript.zh"
import "ghost.zh"
import "string.zh"
//Screen dimensions
const int screenWidth = 256;
const int screenHeight = 176;
//Acid pool constants
const int ACID_MAX_ON_SCREEN = 8; //Max number of acid puddles allowed on screen
//Mist colors (color = CSet# * 16 + color within CSet from 0 to 15)
const int COLOR_MIST_YELLOW = 6;
const int COLOR_MIST_RED = 5;
const int COLOR_MIST_GREEN = 82;
const int COLOR_MIST_BLUE = 3;

//AcidHandla enemy (place this one on screen)
//Type: Other
//Attrib 1: ID of head enemy
//Attrib 2: Max time between head sockets dropping acid (Recommend 120)
//Attrib 3: Acid combo (Set the CSet2 attribute so that it looks right with CSet 0)
//Attrib 4: Acid duration (120)
//Attrib 5: Maximum time between mist changes (240)
//Attrib 6: Minimum time between mist changes (180)
//Attrib 7: Time until heads respawn (240)
//Attrib 11: -1
//Attrib 12: Slot # of this script
//Weapon damage: Frames between acid damaging Link (10)
//Random rate: Frames before changing direction / 10 (e.g. 4 = 40 frames)
//HP, Damage, Step, Frame Rate: Set as normal
//Head enemy
//Type: Walking enemy
//Weapon Shot Type: Rapid Fire
//Set up all attributes as normal, including weapon of choice
ffc script acidHandla{
void run(int enemyID){
	 npc ghost = Ghost_InitAutoGhost(this, enemyID, GHF_NORMAL); //Load main enemy
	 npc heads[4]; //Acidhandla's heads - fireballs while alive, acid when dead
	 int headXY[8] = { 0,-15, 0,15, -15,0, 15,0 }; //Head X/Y offset in order UDLR
	 int acidTime[4]; //Time before each head socket drops acid
	 int storeDefense[18]; //Store defenses while invulnerable
	 int mistCounter; //Time before changing mist on/off
	 int mistType; //Currently active mist type
		 //0 = None
		 //1 = Yellow (switch button inputs)
		 //2 = Red (player and boss slow down)
		 //3 = Green (player and boss speed up)
		 //4 = Blue (instantly restore one head)
	 int curStep = ghost->Step; //Red/Green mists modify step speed
	 int headlessStep; //Step speed addition: (4-#heads)*15
	 int moveCountdown = ghost->Rate*10; //Time before changing direction


	 //==== Setup ====

	 //Load attributes
	 int headID = ghost->Attributes[0];
	 int acidDropRate = ghost->Attributes[1];
	 int acidSprite = ghost->Attributes[2];
	 int acidDuration = ghost->Attributes[3];
	 int hurtFreq = ghost->WeaponDamage;
	 int mistTimeMax = ghost->Attributes[4];
	 int mistTimeMin = ghost->Attributes[5];
	 int respawnRate = ghost->Attributes[6];
	 int respawnTime = respawnRate; //Time before heads respawn (all at once, starting when they're all gone)

	 //Find phase-change HP values
	 int phase2HP = ghost->HP / 2;
	 //int phase3HP = ghost->HP / 3;

	 //Create heads
	 for ( int i = 0; i < 4; i++ ){
		 heads[i] = Screen->CreateNPC(headID);
	 }

	 //Store defenses and make body invulnerable
	 for ( int i = 0; i < 18; i++ ){
		 storeDefense[i] = ghost->Defense[i];
		 ghost->Defense[i] = NPCDT_QUARTERDAMAGE;
	 }
	
	 //==== Begin loop ====
	 while ( ghost->HP > 0 ){
		 //Manage heads
		 int headCount;
		 for ( int i = 0; i < 4; i++ ){
			 if ( !heads[i]->isValid() ){ //If dead
				 if ( acidTime[i] <= 0 ){ //Acid time is up
					 int ffcScriptName[] = "acidPool";
					 int ffcScriptNum = Game->GetFFCScript(ffcScriptName);
					 if ( CountFFCsRunning(ffcScriptNum) < ACID_MAX_ON_SCREEN ){ //Fewer than max acid
						 int x = ghost->X + headXY[i*2];
						 int y = ghost->Y + headXY[i*2+1];
						 int args[5] = { x, y, acidSprite, hurtFreq, acidDuration };
						 RunFFCScript(ffcScriptNum, args); //Drop some!
					 }
					 acidTime[i] = Rand(acidDropRate) + 1; //Reset time to random length
				 }
				 else //Otherwise decrement acid counter
						 acidTime[i]--;
				 }
			 else{ //Alive: keep in place
				 headCount++;
				 //Heads should handle their own fireballs
				 heads[i]->Dir = i; //Keep it facing in right direction
				 heads[i]->X = ghost->X + headXY[i*2];
				 heads[i]->Y = ghost->Y + headXY[i*2 + 1];
			 }
		 }
		 //If all heads destroyed, restore defenses
		 if ( headCount <= 0 ){
			 if ( respawnTime <= 0 ){ //If respawn time up
				 respawnTime = respawnRate;
				 for ( int i = 0; i < 4; i++ ){ //Regenerate heads
					 heads[i] = Screen->CreateNPC(headID);
					 heads[i]->X = ghost->X + headXY[i*2];
					 heads[i]->Y = ghost->Y + ghost->Y + headXY[i*2+1];
				 }
			 }
			 else
				 respawnTime--; //If set, count down to respawn; regeneration handled above
			 for ( int i = 0; i < 18; i++ )
				 ghost->Defense[i] = storeDefense[i];
		 }
		 //Otherwise make invulnerable (if heads respawn, takes effect next frame
		 else{
			 for ( int i = 0; i < 18; i++ )
				 ghost->Defense[i] = NPCDT_QUARTERDAMAGE;
			 respawnTime = respawnRate;
		 }
		
		 //Mist change
		 if ( mistCounter <= 0 && ghost->HP <= phase2HP ){ //If counter hits 0 and boss is on phase 2
			 mistCounter = Rand(mistTimeMax-mistTimeMin) + mistTimeMin; //Set random time
			 if ( mistType > 0 ) //If mist is active, disable it
				 mistType = 0;
			 else{ //If mist is inactive, enable it
				 mistType = Rand(4) + 1;
				 if ( mistType == 4 ){ //If blue
					 for ( int i = 0; i < 4; i++ ){ //Check each head
						 if ( !heads[i]->isValid() ){ //If dead
							 heads[i] = Screen->CreateNPC(headID); //Regenerate it
							 heads[i]->X = ghost->X + headXY[i*2];
							 heads[i]->Y = ghost->Y + ghost->Y + headXY[i*2+1];
							 break; //Then stop. Only one head is regenerated.
						 }
					 }
				 }
			 }
		 }
		 else if ( mistCounter > 0 )
			 mistCounter--;
		
		 //Mist effects
		 if ( mistType == 0 ) //None: Reset speed
			 curStep = ghost->Step;
		 else if ( mistType == 1 ){ //Yellow: Switch inputs
			 Screen->Rectangle(6, 0, 0, screenWidth, screenHeight, COLOR_MIST_YELLOW, 1, 0, 0, 0, true, 64);
			 switchInputs();
			 curStep = ghost->Step;
		 }
		 else if ( mistType == 2 ){ //Red: Slow down
			 Screen->Rectangle(6, 0, 0, screenWidth, screenHeight, COLOR_MIST_RED, 1, 0, 0, 0, true, 64);
			 curStep = ghost->Step/2;
			 if ( Rand(2) )
				 NoMovement();
		 }
		 else if ( mistType == 3 ){ //Green: Speed up
			 Screen->Rectangle(6, 0, 0, screenWidth, screenHeight, COLOR_MIST_GREEN, 1, 0, 0, 0, true, 64);
			 curStep = ghost->Step*2;
			 fastWalk(1);
		 }
		 else if ( mistType == 4 ){ //Blue: Nothing; head was regenerated at beginning
			 Screen->Rectangle(6, 0, 0, screenWidth, screenHeight, COLOR_MIST_BLUE, 1, 0, 0, 0, true, 64);
			 curStep = ghost->Step;
		 }
		
		 //Finally, move the 'Handla
		 moveCountdown--;
		 if ( moveCountdown <= 0 ){
			 moveCountdown = ghost->Rate*10;
			 ghost->Dir = Rand(4);
		 }
		
		 headlessStep = (4 - headCount) * 15;
		 Ghost_Move(ghost->Dir, (curStep+headlessStep)/100, 0);
		 Ghost_Waitframe(this, ghost, false, false);
	 }
	
	 for ( int i = 0; i < 4; i++ ){ //Kill off heads
		 if ( heads[i]->isValid() )
			 heads[i]->HP = 0;
	 }
	 Ghost_Explode(this, ghost); //Play asploding animation
}
}
void switchInputs(){
bool temp = Link->InputDown;
Link->InputDown = Link->InputUp;
Link->InputUp = temp;

temp = Link->InputRight;
Link->InputRight = Link->InputLeft;
Link->InputLeft = temp;

temp = Link->InputB;
Link->InputB = Link->InputA;
Link->InputA = temp;

temp = Link->InputR;
Link->InputR = Link->InputL;
Link->InputL = temp;
}
//Don't set speed too high!
void fastWalk ( int speed ){
//Up
if( Link->InputUp
&& !Screen->isSolid(Link->X,Link->Y+6) //NW
&& !Screen->isSolid(Link->X+7,Link->Y+6) //N
&& !Screen->isSolid(Link->X+15,Link->Y+6) //NE
)
	 Link->Y -= speed;
//Down
else if( Link->InputDown
&& !Screen->isSolid(Link->X,Link->Y+17) //SW
&& !Screen->isSolid(Link->X+7,Link->Y+17) //S
&& !Screen->isSolid(Link->X+15,Link->Y+17) //SE
)
	 Link->Y += speed;
//Left
else if( Link->InputLeft
&& !Screen->isSolid(Link->X-2,Link->Y+8) //NW
&& !Screen->isSolid(Link->X-2,Link->Y+15) //SW
)
	 Link->X -= speed;
//Right
else if( Link->InputRight
&& !Screen->isSolid(Link->X+17,Link->Y+8) //NE
&& !Screen->isSolid(Link->X+17,Link->Y+15) //SE
)
	 Link->X += speed;
}

//Hurts Link as long as he touches it - no knockback, no invuln
//D0: X position
//D1: Y position
//D2: Combo to use
//D3: Frames between hurting Link
//D4: Frames before this dissappears
ffc script acidPool{
void run ( int x, int y, int combo, int freq, int duration ){
	 int hurtTimer;
	 this->Data = combo;
	 this->CSet = 0;
	 this->X = x;
	 this->Y = y;
	 while ( duration > 0 ){
		 if ( LinkCollision(this) && Link->Z <= 0 ){
			 hurtTimer = (hurtTimer + 1) % freq;
			 if ( hurtTimer == 0 ){
				 Link->HP--;
			 }
		 }
		 else
			 hurtTimer = 0;
		 duration--;
		 Waitframe();
	 }
	 this->Data = 0;
}
}

//Prevents moving in any direction
void NoMovement(){
Link->InputUp = false; Link->PressUp = false;
Link->InputDown = false; Link->PressDown = false;
Link->InputLeft = false; Link->PressLeft = false;
Link->InputRight = false; Link->PressRight = false;
}