// Delete these import lines if you already have them in your script file.
import "std.zh"
import "ffcscript.zh"
const int SPRITE_SPARKLE = 29;
const int SFX_BOW_CHARGE = 36;
int facing_dir;
bool bow_charging;
global script BowActive
{
void run()
{
while (true)
{
Waitdraw();
BowAnimation();
Waitframe();
}
}
}
void BowAnimation()
{
if (bow_charging)
{
Link->Dir = facing_dir;
}
bow_charging = false;
}
// Bow and arrow tiles cannot exceed 32768!
// Your bow and arrow tiles should be in the order up, down, left, right.
// This item script should be attached to the Action Script slot of an item that has a custom item class, not an existing bow.
// D0: bow tile
// D1: bow CSet
// D2: arrow tile
// D3: arrow CSet
// D4: arrow damage
// D5: arrow step speed
item script LttPBow
{
void run(int bow_tile, int bow_cset, int arrow_tile, int arrow_cset, int arrow_damage, int arrow_step)
{
// Only triggers if the bow isn't already drawn.
int script_name[] = "LttPBowFFC";
int script_num = Game->GetFFCScript(script_name);
int bow_family = this->Family;
if (CountFFCsRunning(script_num) == 0)
{
float args[] = {bow_tile, bow_cset, arrow_tile, arrow_cset, arrow_damage, arrow_step, bow_family};
RunFFCScript(script_num, args);
}
}
}
ffc script LttPBowFFC
{
void run(int bow_tile, int bow_cset, int arrow_tile, int arrow_cset, int arrow_damage, int arrow_step, int bow_family)
{
itemdata A_item;
itemdata B_item;
bool using_B = false;
B_item = Game->LoadItemData(GetEquipmentB());
if (B_item->Family == bow_family)
{
using_B = true;
}
// Comment this out to give Link's bowmanship a lot less oomph.
Link->Action = LA_ATTACKING;
// Loop to draw the bow for 15 frames before firing. Similar for loops for additional frames of animation, such as taking out the bow
// à la Link to the Past, can be placed here.
for (int i = 0; i < 15; i++)
{
A_item = Game->LoadItemData(GetEquipmentA());
B_item = Game->LoadItemData(GetEquipmentB());
Link->InputUp = false;
Link->InputDown = false;
Link->InputLeft = false;
Link->InputRight = false;
if (A_item->Family != bow_family)
{
Link->InputA = false;
// Quits if you switch item.
if (!using_B)
{
Quit();
}
}
if (B_item->Family != bow_family)
{
Link->InputB = false;
// Quits if you switch item.
if (using_B)
{
Quit();
}
}
// Disable other button inputs here if you want.
// Quits if Link gets hit. Comment this out if you don't want arrow firing to be interrupted.
if (Link->Action == LA_GOTHURTLAND)
{
Quit();
}
Screen->FastTile(4, Link->X + InFrontX(Link->Dir, 7), Link->Y + InFrontY(Link->Dir, 7), bow_tile + Link->Dir, bow_cset, OP_OPAQUE);
Waitframe();
}
// Checks to see that you have arrows and that no previously fired arrows are on screen.
if (Game->Counter[CR_ARROWS] > 0 && NumLWeaponsOf(LW_ARROW) == 0)
{
Game->Counter[CR_ARROWS]--;
Game->PlaySound(SFX_ARROW);
lweapon arrow = NextToLink(LW_ARROW, 0);
arrow->Tile = arrow_tile + Link->Dir;
arrow->CSet = arrow_cset;
arrow->Damage = arrow_damage;
arrow->Step = arrow_step;
arrow->Dir = Link->Dir;
//Arrow hitbox shenanigans. Modeled after ZC arrow defaults.
if (arrow->Dir == DIR_UP || arrow->Dir == DIR_DOWN)
{
arrow->HitWidth = 15;
arrow->HitHeight = 12;
arrow->HitXOffset = 0;
arrow->HitYOffset = 2;
arrow->DrawXOffset = 0;
arrow->DrawYOffset = -2;
}
else
{
arrow->HitWidth = 12;
arrow->HitHeight = 14;
arrow->HitXOffset = 2;
arrow->HitYOffset = 2;
arrow->DrawXOffset = 0;
arrow->DrawYOffset = 1;
}
}
else
{
if (Game->Counter[CR_ARROWS] == 0)
{
//Game->PlaySound(0); // Uncomment and put in appropriate number for failure sound if out of arrows.
}
Quit();
}
}
}
// Bow and arrow tiles cannot exceed 32768!
// Your bow and arrow tiles should be in the order up, down, left, right.
// This item script should be attached to the Action Script slot of an item that has a custom item class, not an existing bow.
// D0: bow tile
// D1: bow CSet
// D2: arrow tile
// D3: arrow CSet
// D4: arrow damage
// D5: arrow step speed
// D6: charge time
item script LttPChargeBow
{
void run(int bow_tile, int bow_cset, int arrow_tile, int arrow_cset, int arrow_damage, int arrow_step, int charge_time)
{
// Only triggers if the bow isn't already drawn.
int script_name[] = "LttPChargeBowFFC";
int script_num = Game->GetFFCScript(script_name);
int bow_family = this->Family;
if (CountFFCsRunning(script_num) == 0)
{
float args[] = {bow_tile, bow_cset, arrow_tile, arrow_cset, arrow_damage, arrow_step, charge_time, bow_family};
RunFFCScript(script_num, args);
}
}
}
ffc script LttPChargeBowFFC
{
void run(int bow_tile, int bow_cset, int arrow_tile, int arrow_cset, int arrow_damage, int arrow_step, int charge_time, int bow_family)
{
itemdata A_item;
itemdata B_item;
bool using_B = false;
int bow_charge;
lweapon sparkle;
facing_dir = Link->Dir;
B_item = Game->LoadItemData(GetEquipmentB());
if (B_item->Family == bow_family)
{
using_B = true;
}
// Comment this out to give Link's bowmanship a lot less oomph.
//Link->Action = LA_ATTACKING;
// Loop to draw the bow for 15 frames before firing. Similar for loops for additional frames of animation, such as taking out the bow
// à la Link to the Past, can be placed here.
for (int i = 0; true; i++)
{
A_item = Game->LoadItemData(GetEquipmentA());
B_item = Game->LoadItemData(GetEquipmentB());
if (i % 2 == 0)
{
Link->InputUp = false;
Link->InputDown = false;
Link->InputLeft = false;
Link->InputRight = false;
}
if (A_item->Family != bow_family)
{
Link->InputA = false;
// Quits if you switch item.
if (!using_B)
{
Quit();
}
}
if (B_item->Family != bow_family)
{
Link->InputB = false;
// Quits if you switch item.
if (using_B)
{
Quit();
}
}
if (using_B && !Link->InputB)
{
if (bow_charge >= charge_time)
{
break;
}
else
{
Quit();
}
}
else if (!using_B && !Link->InputA)
{
if (bow_charge >= charge_time)
{
break;
}
else
{
Quit();
}
}
else
{
bow_charge++;
}
// Disable other button inputs here if you want.
// Quits if Link gets hit. Comment this out if you don't want arrow firing to be interrupted.
if (Link->Action == LA_GOTHURTLAND)
{
Quit();
}
bow_charging = true;
// Make Link stay continue facing the same direction as when bow was drawn.
Link->Dir = facing_dir;
// Charge up sparkle animation.
if (i == charge_time)
{
Game->PlaySound(SFX_BOW_CHARGE);
sparkle = Screen->CreateLWeapon(LW_SPARKLE);
sparkle->X = Link->X;
sparkle->Y = Link->Y;
sparkle->UseSprite(SPRITE_SPARKLE);
sparkle->CollDetection = false;
sparkle->Misc[0] = 15;
}
for (int j = 1; j <= Screen->NumLWeapons(); j++)
{
sparkle = Screen->LoadLWeapon(j);
if (sparkle->ID == LW_SPARKLE && sparkle->Misc[0] == 15)
{
DrawToLayer(sparkle, 4, OP_OPAQUE);
sparkle->X = Link->X;
sparkle->Y = Link->Y;
}
}
Screen->FastTile(4, Link->X + InFrontX(Link->Dir, 7), Link->Y + InFrontY(Link->Dir, 7), bow_tile + Link->Dir, bow_cset, OP_OPAQUE);
Waitframe();
}
Link->Action = LA_ATTACKING;
for (int i = 0; i < 10; i++)
{
A_item = Game->LoadItemData(GetEquipmentA());
B_item = Game->LoadItemData(GetEquipmentB());
Link->InputUp = false;
Link->InputDown = false;
Link->InputLeft = false;
Link->InputRight = false;
if (A_item->Family != bow_family)
{
Link->InputA = false;
// Quits if you switch item.
if (!using_B)
{
Quit();
}
}
if (B_item->Family != bow_family)
{
Link->InputB = false;
// Quits if you switch item.
if (using_B)
{
Quit();
}
}
// Quits if Link gets hit. Comment this out if you don't want arrow firing to be interrupted.
if (Link->Action == LA_GOTHURTLAND)
{
Quit();
}
Screen->FastTile(4, Link->X + InFrontX(Link->Dir, 7), Link->Y + InFrontY(Link->Dir, 7), bow_tile + Link->Dir, bow_cset, OP_OPAQUE);
Waitframe();
}
// Checks to see that you have arrows and that no previously fired arrows are on screen.
if (Game->Counter[CR_ARROWS] > 0 && NumLWeaponsOf(LW_ARROW) == 0)
{
Game->Counter[CR_ARROWS]--;
Game->PlaySound(SFX_ARROW);
lweapon arrow = NextToLink(LW_ARROW, 0);
arrow->Tile = arrow_tile + Link->Dir;
arrow->CSet = arrow_cset;
arrow->Damage = arrow_damage;
arrow->Step = arrow_step;
arrow->Dir = Link->Dir;
//Arrow hitbox shenanigans. Modeled after ZC arrow defaults.
if (arrow->Dir == DIR_UP || arrow->Dir == DIR_DOWN)
{
arrow->HitWidth = 15;
arrow->HitHeight = 12;
arrow->HitXOffset = 0;
arrow->HitYOffset = 2;
arrow->DrawXOffset = 0;
arrow->DrawYOffset = -2;
}
else
{
arrow->HitWidth = 12;
arrow->HitHeight = 14;
arrow->HitXOffset = 2;
arrow->HitYOffset = 2;
arrow->DrawXOffset = 0;
arrow->DrawYOffset = 1;
}
}
else
{
if (Game->Counter[CR_ARROWS] == 0)
{
//Game->PlaySound(0); // Uncomment and put in appropriate number for failure sound if out of arrows.
}
Quit();
}
}
}