Deku Leaf
Description
This highly customizable collection of scripts allows you to do two things. One you can create gust of wind with it that when you use it on the ground, and these gust can be made to spin link and enemies into the air. You can also use it as a parachute when used in the air.
Screenshots and Demo
Example Quest
Code
Script
//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;
}
}Setup
First set your constants. If you don't understand what a constant does. Post here and I'll explain it to you. Second you need to create two items the selectable deku leaf item and a second unselectable passive equipment item "Deku Leaf LTM" that changes his sprite to the gliding sprite. Oh and you must have Expanded Link Tile Modifiers or the graphics will be glitchy when facing up. Now for the arguments of these two items, they are split between two items for easy access. Now to make it spin npcs the npc's attribute 12 must not be 0. If it's 0 it won't be spinnable. So go through all your enemies and set the ones you want to be spinnable to 1. And remember that not all enemy types can be spinnable moldorms for example.
Deku Leaf
- D0 = the ffc script slot with the GustofWind script.
- D1 = the initial step speed of the whirlwind.
- D2 = the sprite of the whirlwind
- D3 = the sound played when a whirlwind is fired.
- D4 = the lifespan of the whirlwind.
- D0 = the first of 4 tiles ordered up, down, left, right used to draw the leaf above Link. Divide this number by 10. So tile 1 would be .1.
- D1 = the cset to use for the leaf tile.
You will need both std.zh and ffcscript.zh for this to compile and function.

