Copy to Clipboard Test

Deku Leaf Code

//Miscellenous Constants used by the Deku Leaf.
const int I_DEKULEAF = 123;
const int I_DEKULEAF_LTM = 124;
const float GRAVITY2 = 0.3333;
const int LW_GUST = 31;
const int SFX_WIND1 = 0;
const int SFX_WIND2 = 0;
const int SFX_GLIDE = 0;
const int SFX_LAND = 0;

//Miscellaneous Variables used by the Deku Leaf.
float Link_Z;
int Glide_Time;
int draintimer;
int looptimer;
bool HitGround;

//These constants control how the whirlwind behaves and interacts with other things.
const int DEKU_DECELERATION = 1; //The deceleration in 100th's of a pixel per frame that undergoes the gust of wind.
const int DEKU_SPIN_LINK	= 4; //Whether or not the whirlwinds spin link into the air, also the spin speed in frames per 90 degree rotation.
const int DEKU_SPIN_NPCS	= 4; //Whether or not the whirlwinds spin npcs into the air, also the spin speed in frames per 90 degree rotation.
const int DEKU_GROUND_SPINS = 2; //The number of spins to do while the target is on the ground.
const int DEKU_AIR_SPINS	= 2; //The number of spins to do while the target is mid air.
const int DEKU_SPIN_JUMP	= 5; //The jump force to apply to the target in the whirlwind when it shoots them up in the air.

//These constants control how the deku parachute works.
const int DEKU_MAX_GLIDE_TIME = 60; //This is the max time that parachute can be open.
const int DEKU_CANCELLABLE	= 0;  //Whether or not the deku leaf can be cancelled. 0 = false, 1 = true.
const int DEKU_DRAIN		  = 0;  //This is the speed at which MP is consumed.
const int DEKU_LOOP		   = 0;  //This is the length of the glide sound effect in tics.

//This function should appear in your script file only once.
bool UsedItem(int id){
	return ((GetEquipmentA() == id && Link->PressA) || (GetEquipmentB() == id && Link->PressB));
}

//Combine this global script with your other ones if you want the gliding to work.
global script Slot2{
	void run(){
		//Declare a variable to keep the mp drain rate constant.
		while(true){
			if(Link->Z == 0){
				if(!HitGround) Game->PlaySound(SFX_LAND);
				HitGround = true;
			}
			//Check if Link has the Deku Leaf LTM item.
			if(Link->Item[I_DEKULEAF_LTM]){
				//Increment Glide_Time if it's greater than or equal to 0;
				if(Glide_Time >= 0)  Glide_Time++;
				//Check if DEKU_DRAIN doesn't equal 0.
				if(DEKU_DRAIN != 0){
					//Increment draintimer and wrap it to DEKU_DRAIN. If it equals 0 after all that decrement MP.
					draintimer = (draintimer + 1) % DEKU_DRAIN;
					if(draintimer == 0) Link->MP--;
				}
				//If Glide_Time has reached DEKU_MAX_GLIDE_TIME or MP has reached 0 cancel the gliding by removing the LTM item.
				if(Glide_Time == DEKU_MAX_GLIDE_TIME || Link->MP == 0) Link->Item[I_DEKULEAF_LTM] = false;
				//Otherwise if not scrolling glide down to the ground.
				else if(Link->Action != LA_SCROLLING){
					looptimer = (looptimer + 1) % DEKU_LOOP;
					if(looptimer == 0) Game->PlaySound(SFX_GLIDE);
					DekuGlide();
				}
				//Check if Link just used the DekuLeaf and if so cancel the gliding by removing the LTM item.
				if(UsedItem(I_DEKULEAF) && DEKU_CANCELLABLE) Link->Item[I_DEKULEAF_LTM] = false;
				//Null the A and B buttons to prevent item use.
				Link->InputA = false;
				Link->InputB = false;
			}
			//Waitframe to prevent freezing.
			Waitframe();
		}
	}
	//This function makes it appear that Link is holding the leaf overhead and makes him fall slower.
	void DekuGlide(){
		//Check Link's Z position and if it's less than or equal to 0 cancel the glide by removing the LTM item.
		if(Link->Z <= 0){
			Link_Z = 0;
			Link->Item[I_DEKULEAF_LTM] = 0;
		}
		//Otherwise load the itemdata of the LTM item and use it to draw the leaf on layer 4.
		else{
			itemdata id = Game->LoadItemData(I_DEKULEAF_LTM);
			Screen->FastTile(4, Link->X, Link->Y - Link_Z - 8, (id->InitD[0]*10) + Link->Dir, id->InitD[1], 128);
		}
		//Set Link's Z position to Link_Z and subtract Link_Z by GRAVITY2.
		Link->Z = Link_Z;
		Link_Z -= GRAVITY2;
	}
}

//Deku Leaf item script.
item script DekuLeaf{
	//D0 is the ffcScript Slot number that contains the GustofWind script.
	//D1 is the initial step speed of the whirlwind in 100th's of a pixel per frame.
	//D2 is the sprite used by the whirlwind.
	//D3 is the sound used when a whirlwind is fired.
	//D4 is the lifespan of the whirlwind in frames. Only used when it decelerates.
	void run(int ffcScriptNum, int step, int sprite, int sound, int lifespan){
		//Check if Link is in the air, and if so reset Glide_Time, set Link_Z to Link's Z position, Give him the LTM item and set his action to LA_NONE.
		if(Link->Z > 0){
			if(HitGround){
				HitGround = false;
				Glide_Time = 0;
				draintimer = 0;
				looptimer = 0;
				Link_Z = Link->Z;
				Link->Item[I_DEKULEAF_LTM] = true;
				Game->PlaySound(SFX_GLIDE);
			}
			Link->Action = LA_NONE;
		}
		//Otherwise if no FFC is running the GustofWind script launch one.
		else if(CountFFCsRunning(ffcScriptNum) == 0){
			int args[8] = {step, sprite, sound, lifespan};
			RunFFCScript(ffcScriptNum, args);
		}
	}
}

//GustofWind script for controlling Deku Leaf projectiles.
ffc script GustofWind{
	void run(int step, int sprite, int sound, int lifespan){
		//Create a lweapon next to link.
		lweapon gust = NextToLink(LW_GUST, 0);
		//Set the gust's sprite, step, and direction.
		gust->UseSprite(sprite);
		gust->Step = step;
		gust->Dir = Link->Dir;
		//Play the firing sound.
		Game->PlaySound(sound);
		//Turn off collision for the gust.
		gust->CollDetection = false;
		//Declare a npc pointer, and three variables for controlling the spinning of npcs and Link.
		npc target;
		bool spinning;
		int spintimer;
		float spins;
		//Loop until the wind either goes offscreen or step reaches 0.
		while(gust->isValid() && lifespan){
			//Draw the gust to layer 3.
			DrawToLayer(gust, 3, 128);
			//Check if it can move and if not set step to 0.
			if(!CanMove(gust)) gust->Step = 0;
			//Declerate the gust if it's step has not reached 0 yet.
			if(gust->Step > 0) gust->Step -= DEKU_DECELERATION;
			else gust->Step = 0;
			//Check if the gust of wind is not spinning anything.
			if(!spinning){
				//Resize Link's collision box for precision purposes.
				Link->HitWidth = 15;
				Link->HitHeight = 15;
				//First check for collision with Link if he's on the ground, but only if DEKU_SPIN_LINK is true.
				if(LinkCollision(gust) && Link->Z == 0 && DEKU_SPIN_LINK) spinning = true;
				//Otherwise check for collision with npcs.
				else if(DEKU_SPIN_NPCS){
					for(int i = Screen->NumNPCs(); i > 0; i--){
						npc n = Screen->LoadNPC(i);
						if(n->Attributes[11] == 0) continue;
						if(!Collision(n, gust) || !n->CollDetection) continue;
						target = n;
						spinning = true;
					}
				}
				//Return Link's collision box back to it's default size.
				Link->HitWidth = 16;
				Link->HitHeight = 16;
				//If spinning something play the sucked in sound
				if(spinning) Game->PlaySound(SFX_WIND1);
			}
			//Now check if spinning is true.
			if(spinning){
				if(target->isValid()){
					if(target->Z == 0){
						target->X = gust->X;
						target->Y = gust->Y;
					}
					spintimer = (spintimer + 1) % DEKU_SPIN_NPCS;
					if(spintimer == 0){
						if(target->Dir == DIR_UP) target->Dir = DIR_RIGHT;
						else if(target->Dir == DIR_DOWN) target->Dir = DIR_LEFT;
						else if(target->Dir == DIR_LEFT) target->Dir = DIR_UP;
						else if(target->Dir == DIR_RIGHT) target->Dir = DIR_DOWN;
						spins += .25;
						if(spins == DEKU_GROUND_SPINS){
							target->Jump = DEKU_SPIN_JUMP;
							Game->PlaySound(SFX_WIND2);
						}
						else if(spins == DEKU_GROUND_SPINS + DEKU_AIR_SPINS){
							npc n;
							target = n;
							spinning = false;
							spins = 0;
						}
					}
				}
				else{
					if(Link->Z == 0){
						Link->X = gust->X;
						Link->Y = gust->Y;
						NoAction();
					}
					spintimer = (spintimer + 1) % DEKU_SPIN_LINK;
					if(spintimer == 0){
						if(Link->Dir == DIR_UP) Link->Dir = DIR_RIGHT;
						else if(Link->Dir == DIR_DOWN) Link->Dir = DIR_LEFT;
						else if(Link->Dir == DIR_LEFT) Link->Dir = DIR_UP;
						else if(Link->Dir == DIR_RIGHT) Link->Dir = DIR_DOWN;
						spins += .25;
						if(spins == DEKU_GROUND_SPINS){
							Link->Jump = DEKU_SPIN_JUMP;
							Game->PlaySound(SFX_WIND2);
						}
						else if(spins == DEKU_GROUND_SPINS + DEKU_AIR_SPINS){
							spinning = false;
							spins = 0;
						}
					}
				}
			}
			//Now if Ceiling(gust->Step/100) equals 0 then decrement lifespan.
			if(Ceiling(gust->Step/100) == 0) lifespan--;
			//If lifespan equal 0 and it's spinning something set lifespan to 1.
			if(lifespan == 0 && spinning) lifespan = 1;
			//Waitframe to prevent freezing.
			Waitframe();
		}
		//If the gust is still valid set it's deadstate to 0.
		if(gust->isValid()) gust->DeadState = WDS_DEAD;
	}
	//gust function is used to determine if the statue can move in the given gust->Direction.
	bool CanMove(lweapon gust){
		//Initialize a boolean as true
		bool condition = true;
		//Go through the following loop 16 times.
		for(int i; i < 16; i++){
			//Check for solidity.
			if(gust->Dir == 0 && Screen->isSolid(gust->X + i, gust->Y - Ceiling(gust->Step/100))) condition = false;
			else if(gust->Dir == 1 && Screen->isSolid(gust->X + i, gust->Y + 15 + Ceiling(gust->Step/100))) condition = false;
			else if(gust->Dir == 2 && Screen->isSolid(gust->X - Ceiling(gust->Step/100), gust->Y + i)) condition = false;
			else if(gust->Dir == 3 && Screen->isSolid(gust->X + 15 + Ceiling(gust->Step/100), gust->Y + i)) condition = false;
			//Only do the rest of the loop for the first and last iteration of the loop.
			if(i == 0 || i == 15){
				//Check for water.
				if(gust->Dir == 0 && IsWater(ComboAt(gust->X + i, gust->Y - Ceiling(gust->Step/100)))) condition = false;
				else if(gust->Dir == 1 && IsWater(ComboAt(gust->X + i, gust->Y + 15 + Ceiling(gust->Step/100)))) condition = false;
				else if(gust->Dir == 2 && IsWater(ComboAt(gust->X - Ceiling(gust->Step/100), gust->Y + i))) condition = false;
				else if(gust->Dir == 3 && IsWater(ComboAt(gust->X + 15 + Ceiling(gust->Step/100), gust->Y + i))) condition = false;
				//Check for pits.
				if(gust->Dir == 0 && IsPit(ComboAt(gust->X + i, gust->Y - Ceiling(gust->Step/100)))) condition = false;
				else if(gust->Dir == 1 && IsPit(ComboAt(gust->X + i, gust->Y + 15 + Ceiling(gust->Step/100)))) condition = false;
				else if(gust->Dir == 2 && IsPit(ComboAt(gust->X - Ceiling(gust->Step/100), gust->Y + i))) condition = false;
				else if(gust->Dir == 3 && IsPit(ComboAt(gust->X + 15 + Ceiling(gust->Step/100), gust->Y + i))) condition = false;
			}
		}
		//Return the boolean we declared at the beginning of the function.
		return condition;
	}
}