Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import "std.zh"
- ////////////////////////////////////////////////////////////////
- // Charge Bow
- // by grayswandir
- ////////////////////////////////////////////////////////////////
- // Description:
- //
- // This is an 8-way bow that you can charge-up, aim, and shoot. If an arrow
- // hits a flame source, it'll turn into a flamming arrow (fire-type weapon).
- ////////////////////////////////////////////////////////////////
- // Setup:
- //
- // This requires std.zh.
- //
- // Read through the following Integration section and change all the values to
- // suit your quest.
- //
- // Make sure to load the ChargeBow ffc script, and the ChargeBow_Use item
- // script.
- //
- // Set ChargeBow_Use as the item use script of the item used to fire
- // it. Change it from an arrow to a Custom Item class. (Also remember to
- // change the subscreen slot from arrow to that custom item class as well.)
- // Make the first provided argument to the script the item's id. The second
- // should be the first arrow tile. The tiles should be in order of Up, Down,
- // Left, Right, Left-Up, Right-Up, Left-Down, Right-Down. The third and fourth
- // arguments are the csets to use for normal arrows and fire arrows.
- //
- // This makes use of global variables, so it will invalidate saves when added.
- ////////////////////////////////////////////////////////////////
- // Integration
- ////////////////
- // This section is the part that needs to be set manually for each quest. Read
- // the description for each part and set it accordingly.
- ////////////////
- ////////////////////////////////////////////////////////////////
- // Arrow Animation Setup
- // How fast arrows animate.
- const int CHARGEBOW_ARROW_ASPEED = 8;
- // The offset from the normal tiles for the fire animation.
- const int CHARGEBOW_FIRE_TILE_OFFSET = 20;
- // The number of frames the fire animation has.
- const int CHARGEBOW_FIRE_FRAMECOUNT = 2;
- ////////////////////////////////////////////////////////////////
- // Link Animation Setup
- // Each link animation is a block of tiles. Advancing to the right moves
- // through the different directions. (The order is Up, Down, Left, Right,
- // Left-Up, Right-Up, Left-Down, Right-Down). The first row is with the bow &
- // arrow, the second row is without the arrow. Each frame is a 2 by 2 tile
- // that is centered on Link.
- // Higher number costumes take precedence.
- //// Default Costume
- // The starting tile for the link animation.
- const int CHARGEBOW_LINK_C0_TILE = 1300;
- // The cset the link animation uses.
- const int CHARGEBOW_LINK_C0_CSET = 6;
- //// Costume 1
- // The item that marks using costume 1. Set to 0 to disable.
- const int CHARGEBOW_LINK_C1_ITEM = 17;
- // The starting tile for the link animation.
- const int CHARGEBOW_LINK_C1_TILE = 1300;
- // The cset the link animation uses.
- const int CHARGEBOW_LINK_C1_CSET = 7;
- //// Costume 2
- // The item that marks using costume 2. Set to 0 to disable.
- const int CHARGEBOW_LINK_C2_ITEM = 0;
- // The starting tile for the link animation.
- const int CHARGEBOW_LINK_C2_TILE = 0;
- // The cset the link animation uses.
- const int CHARGEBOW_LINK_C2_CSET = 6;
- //// Costume 3
- // The item that marks using costume 3. Set to 0 to disable.
- const int CHARGEBOW_LINK_C3_ITEM = 0;
- // The starting tile for the link animation.
- const int CHARGEBOW_LINK_C3_TILE = 0;
- // The cset the link animation uses.
- const int CHARGEBOW_LINK_C3_CSET = 6;
- //// Costume 4
- // The item that marks using costume 4. Set to 0 to disable.
- const int CHARGEBOW_LINK_C4_ITEM = 0;
- // The starting tile for the link animation.
- const int CHARGEBOW_LINK_C4_TILE = 0;
- // The cset the link animation uses.
- const int CHARGEBOW_LINK_C4_CSET = 6;
- ////////////////////////////////////////////////////////////////
- // Gameplay Setup
- // This is the sound played when you try to fire without any arrows. Set to 0
- // for no sound.
- const int CHARGEBOW_FAIL_SOUND = 21;
- //// Charge Level 0
- // This is the sound played when you first use the bow. Set to 0 for no sound.
- const int CHARGEBOW_START_SOUND = 0;
- // This is the sound played when you release a level 0 shot. Set to 0 for no sound.
- const int CHARGEBOW_L0_SHOT_SOUND = 1;
- // This is the amount of ammo this level shot uses.
- const int CHARGEBOW_L0_AMMO = 1;
- // This is the amount of magic this level shot uses.
- const int CHARGEBOW_L0_MAGIC = 0;
- //// Charge Level 1
- // This is the item id that unlocks this charge level. Set to 0 for no item
- // needed.
- const int CHARGEBOW_L1_ITEM_ID = 0;
- // This is the cumulative frames you need to charge for this charge level.
- const int CHARGEBOW_L1_CHARGE_TIME = 60;
- // This is the sound played when you reach charge level 1. Set to 0 for no
- // sound.
- const int CHARGEBOW_L1_CHARGE_SOUND = 35;
- // This is the sound played when you release a level 1 shot. Set to 0 for no
- // sound.
- const int CHARGEBOW_L1_SHOT_SOUND = 1;
- // This is the amount of ammo this level shot uses.
- const int CHARGEBOW_L1_AMMO = 1;
- // This is the amount of magic this level shot uses.
- const int CHARGEBOW_L1_MAGIC = 8;
- //// Charge Level 2
- // This is the item id that unlocks this charge level. Set to 0 for no item
- // needed.
- const int CHARGEBOW_L2_ITEM_ID = 0;
- // This is the cumulative frames you need to charge for this charge level.
- const int CHARGEBOW_L2_CHARGE_TIME = 150;
- // This is the sound played when you reach charge level 2. Set to 0 for no
- // sound.
- const int CHARGEBOW_L2_CHARGE_SOUND = 36;
- // This is the sound played when you release a level 2 shot. Set to 0 for no
- // sound.
- const int CHARGEBOW_L2_SHOT_SOUND = 1;
- // This is the amount of ammo this level shot uses.
- const int CHARGEBOW_L2_AMMO = 3;
- // This is the amount of magic this level shot uses.
- const int CHARGEBOW_L2_MAGIC = 32;
- //// Effects
- // This is the combo flag that sets an arrow on fire. Defaults to script 1.
- const int CHARGEBOW_BURN_FLAG = 98;
- // This is the sound that's made when the arrow catches on fire. Set to 0 for
- // no sound.
- const int CHARGEBOW_BURN_SOUND = 0;
- // This is the amount of damage the arrow does.
- int ChargeBow_Damage(int item_id, int charge_level, int element) {
- itemdata data = Game->LoadItemData(item_id);
- int damage = data->Power;
- if (element == CHARGEBOW_ELEMENT_FIRE) {damage *= 2;}
- return damage;
- }
- // The amount of speed each level of charge adds to the arrow.
- const int CHARGEBOW_ARROW_CHARGE_SPEED = 1;
- // Return the strongest bow link has, or -1 for none.
- int ChargeBow_StrongestBow() {
- int bow_id = -1;
- int bow_level = -1;
- itemdata data;
- // Find the highest level bow item the player has.
- for (int i = 0; i < 256; ++i) {
- data = Game->LoadItemData(i);
- if (!Link->Item[i]) {continue;}
- if (IC_BOW != data->Family) {continue;}
- if (data->Level > bow_level) {
- bow_id = i;
- bow_level = data->Level;
- }
- }
- return bow_id;
- }
- // This is the speed the arrow flies at. For reference, Link's movement is
- // 1.5. Defaults to the strongest bow that Link has. Return -1 for no bow.
- int ChargeBow_Speed(int item_id, int charge_level, int element) {
- int bow_id = ChargeBow_StrongestBow();
- itemdata data = Game->LoadItemData(bow_id);
- int speed = data->Power;
- // Add speed for each charge level.
- speed += charge_level * CHARGEBOW_ARROW_CHARGE_SPEED;
- return speed;
- }
- ////////////////////////////////////////////////////////////////
- // Main Script
- const int CHARGEBOW_ELEMENT_NONE = 0;
- const int CHARGEBOW_ELEMENT_FIRE = 1;
- item script ChargeBow_Use {
- void run(int item_id, int tile, int cset, int fire_cset) {
- int i; ffc f;
- // Cancel out if there's already an arrow on screen.
- if (ChargeBow.IsActive()) {return;}
- // Check to see that we pressed the button instead of held it.
- if ((GetEquipmentA() == item_id && !Link->PressA)
- || (GetEquipmentB() == item_id && !Link->PressB)) {
- return;
- }
- // Make sure we actually possess a bow.
- if (-1 == ChargeBow_StrongestBow()) {return;}
- // Look for a free FFC slot.
- for (i = 1; i <= 32; ++i) {
- f = Screen->LoadFFC(i);
- if (0 == f->Data && 0 == f->Script) {break;}
- }
- // If we didn't find a free ffc, quit.
- if (33 == i) {return;}
- // Start up the ffc script.
- f->Script = ChargeBow.ScriptId();
- f->InitD[0] = item_id;
- f->InitD[1] = tile;
- f->InitD[2] = cset;
- f->InitD[3] = fire_cset;
- // Play the start sound.
- if (CHARGEBOW_START_SOUND) {Game->PlaySound(CHARGEBOW_START_SOUND);}
- }
- }
- ffc script ChargeBow {
- // Get the script number for this script.
- int ScriptId() {
- int name[] = "ChargeBow";
- return Game->GetFFCScript(name);
- }
- // If the chargebow ffc is currently active.
- bool IsActive() {
- int script_id = ChargeBow.ScriptId();
- for (int i = 1; i <= 32; ++i) {
- ffc f = Screen->LoadFFC(i);
- if (script_id == f->Script) {return true;}
- }
- return false;
- }
- // Get a multiplier for the x component of a direction.
- int DirX(int dir) {
- if (DIR_LEFT == dir || DIR_LEFTUP == dir || DIR_LEFTDOWN == dir) {return -1;}
- else if (DIR_RIGHT == dir || DIR_RIGHTUP == dir || DIR_RIGHTDOWN == dir) {return 1;}
- else {return 0;}
- }
- // Get a multiplier for the y component of a direction.
- int DirY(int dir) {
- if (DIR_UP == dir || DIR_LEFTUP == dir || DIR_RIGHTUP == dir) {return -1;}
- else if (DIR_DOWN == dir || DIR_LEFTDOWN == dir || DIR_RIGHTDOWN == dir) {return 1;}
- else {return 0;}
- }
- // Get the direction rotated n steps counter-clockwise, using 8
- // directions. Negatives allow for clockwise.
- int RotateDir8(int dir, int count) {
- while (count < 0) {count += 8;}
- while (count > 0) {
- if (DIR_RIGHT == dir) {dir = DIR_RIGHTUP;}
- else if (DIR_RIGHTUP == dir) {dir = DIR_UP;}
- else if (DIR_UP == dir) {dir = DIR_LEFTUP;}
- else if (DIR_LEFTUP == dir) {dir = DIR_LEFT;}
- else if (DIR_LEFT == dir) {dir = DIR_LEFTDOWN;}
- else if (DIR_LEFTDOWN == dir) {dir = DIR_DOWN;}
- else if (DIR_DOWN == dir) {dir = DIR_RIGHTDOWN;}
- else if (DIR_RIGHTDOWN == dir) {dir = DIR_RIGHT;}
- --count;
- }
- return dir;
- }
- // Get the facing based on held buttons. If nothing is held returns Link->Dir.
- int LinkInputDir() {
- if (Link->InputUp) {
- if (Link->InputLeft) {return DIR_LEFTUP;}
- else if (Link->InputRight) {return DIR_RIGHTUP;}
- else {return DIR_UP;}
- }
- else if (Link->InputDown) {
- if (Link->InputLeft) {return DIR_LEFTDOWN;}
- else if (Link->InputRight) {return DIR_RIGHTDOWN;}
- else {return DIR_DOWN;}
- }
- else if (Link->InputLeft) {return DIR_LEFT;}
- else if (Link->InputRight) {return DIR_RIGHT;}
- else {return Link->Dir;}
- }
- // If we can activate the given charge level, based on items and ammo.
- bool CanCharge(int level) {
- if (0 == level) {
- return Game->Counter[CR_ARROWS] >= CHARGEBOW_L0_AMMO
- && Game->Counter[CR_MAGIC] >= CHARGEBOW_L0_MAGIC;
- }
- if (1 == level) {
- return (!CHARGEBOW_L1_ITEM_ID || Link->Item[CHARGEBOW_L1_ITEM_ID])
- && Game->Counter[CR_ARROWS] >= CHARGEBOW_L1_AMMO
- && Game->Counter[CR_MAGIC] >= CHARGEBOW_L1_MAGIC;
- }
- if (2 == level) {
- return (!CHARGEBOW_L2_ITEM_ID || Link->Item[CHARGEBOW_L2_ITEM_ID])
- && Game->Counter[CR_ARROWS] >= CHARGEBOW_L2_AMMO
- && Game->Counter[CR_MAGIC] >= CHARGEBOW_L2_MAGIC;
- }
- return false;
- }
- // The amount of time needed to reach this charge level.
- int ChargeTime(int level) {
- if (1 == level) {return CHARGEBOW_L1_CHARGE_TIME;}
- if (2 == level) {return CHARGEBOW_L2_CHARGE_TIME;}
- return 0;
- }
- // Use up the ammo for a given charge level.
- void UseAmmo(int level) {
- if (0 == level) {
- Game->Counter[CR_ARROWS] -= CHARGEBOW_L0_AMMO;
- Game->Counter[CR_MAGIC] -= CHARGEBOW_L0_MAGIC;
- }
- if (1 == level) {
- Game->Counter[CR_ARROWS] -= CHARGEBOW_L1_AMMO;
- Game->Counter[CR_MAGIC] -= CHARGEBOW_L1_MAGIC;
- }
- if (2 == level) {
- Game->Counter[CR_ARROWS] -= CHARGEBOW_L2_AMMO;
- Game->Counter[CR_MAGIC] -= CHARGEBOW_L2_MAGIC;
- }
- }
- // Play the charge sound for a given level.
- int PlayChargeSound(int level) {
- int sound = 0;
- if (1 == level) {sound = CHARGEBOW_L1_CHARGE_SOUND;}
- else if (2 == level) {sound = CHARGEBOW_L2_CHARGE_SOUND;}
- if (sound) {Game->PlaySound(sound);}
- }
- // Play the shot sound for a given level.
- int PlayShotSound(int level) {
- int sound = 0;
- if (0 == level) {sound = CHARGEBOW_L0_SHOT_SOUND;}
- else if (1 == level) {sound = CHARGEBOW_L1_SHOT_SOUND;}
- else if (2 == level) {sound = CHARGEBOW_L2_SHOT_SOUND;}
- if (sound) {Game->PlaySound(sound);}
- }
- // Get the tile base for link's graphic.
- int LinkTileBase() {
- if (CHARGEBOW_LINK_C4_ITEM && Link->Item[CHARGEBOW_LINK_C4_ITEM]) {return CHARGEBOW_LINK_C4_TILE;}
- else if (CHARGEBOW_LINK_C3_ITEM && Link->Item[CHARGEBOW_LINK_C3_ITEM]) {return CHARGEBOW_LINK_C3_TILE;}
- else if (CHARGEBOW_LINK_C2_ITEM && Link->Item[CHARGEBOW_LINK_C2_ITEM]) {return CHARGEBOW_LINK_C2_TILE;}
- else if (CHARGEBOW_LINK_C1_ITEM && Link->Item[CHARGEBOW_LINK_C1_ITEM]) {return CHARGEBOW_LINK_C1_TILE;}
- else {return CHARGEBOW_LINK_C0_TILE;}
- }
- // Get the cset for link's graphic.
- int LinkCSet() {
- if (CHARGEBOW_LINK_C4_ITEM && Link->Item[CHARGEBOW_LINK_C4_ITEM]) {return CHARGEBOW_LINK_C4_CSET;}
- else if (CHARGEBOW_LINK_C3_ITEM && Link->Item[CHARGEBOW_LINK_C3_ITEM]) {return CHARGEBOW_LINK_C3_CSET;}
- else if (CHARGEBOW_LINK_C2_ITEM && Link->Item[CHARGEBOW_LINK_C2_ITEM]) {return CHARGEBOW_LINK_C2_CSET;}
- else if (CHARGEBOW_LINK_C1_ITEM && Link->Item[CHARGEBOW_LINK_C1_ITEM]) {return CHARGEBOW_LINK_C1_CSET;}
- else {return CHARGEBOW_LINK_C0_CSET;}
- }
- // Make sure that Link is facing a cardinal direction.
- void ForceCardinal() {
- if (Link->Dir == DIR_LEFTUP) {Link->Dir = Choose(DIR_LEFT, DIR_UP);}
- if (Link->Dir == DIR_RIGHTUP) {Link->Dir = Choose(DIR_RIGHT, DIR_UP);}
- if (Link->Dir == DIR_LEFTDOWN) {Link->Dir = Choose(DIR_LEFT, DIR_DOWN);}
- if (Link->Dir == DIR_RIGHTDOWN) {Link->Dir = Choose(DIR_RIGHT, DIR_DOWN);}
- }
- // Make an arrow.
- lweapon MakeArrow(int item_id, int arrow_tile, int arrow_cset, int charge_level, int element, int dir) {
- int dx = ChargeBow.DirX(dir);
- int dy = ChargeBow.DirY(dir);
- lweapon arrow = Screen->CreateLWeapon(LW_ARROW);
- arrow->Damage = ChargeBow_Damage(item_id, charge_level, element);
- arrow->Dir = dir;
- arrow->X = Link->X + dx * 16;
- arrow->Y = Link->Y + dy * 16;
- arrow->Step = ChargeBow_Speed(item_id, charge_level, element) * 100;
- arrow->OriginalTile = arrow_tile + dir;
- arrow->OriginalCSet = arrow_cset;
- arrow->Tile = arrow_tile + dir;
- arrow->CSet = arrow_cset;
- arrow->NumFrames = 1;
- return arrow;
- }
- void run(int item_id, int arrow_tile, int arrow_cset, int fire_cset) {
- int i;
- // Hide Link.
- Link->Invisible = true;
- // Grab Link's graphic.
- int tile = ChargeBow.LinkTileBase();
- int cset = ChargeBow.LinkCSet();
- // Check for ammo.
- bool have_ammo = CanCharge(0);
- if (!have_ammo) {tile += 40;}
- // Find what button we're using.
- bool button_a = GetEquipmentA() == item_id;
- // Charge the shot.
- int charge_timer = 0;
- int charge_level = Cond(have_ammo, 0, -1);
- while (true) {
- // If link got hurt, quit the script.
- if (LA_GOTHURTLAND == Link->Action || LA_GOTHURTWATER == Link->Action) {
- Link->Invisible = false;
- ForceCardinal();
- Quit();
- }
- // Exit the loop if we've let go of the button.
- if (!Cond(button_a, Link->InputA, Link->InputB)) {break;}
- // Charge if we can reach the next level.
- if (CanCharge(charge_level + 1)) {
- // Increment the charge timer.
- ++charge_timer;
- // Check if we've passed to the next level.
- if (charge_timer >= ChargeTime(charge_level + 1)) {
- ++charge_level;
- PlayChargeSound(charge_level);
- }
- }
- // Set Link's direction.
- Link->Dir = ChargeBow.LinkInputDir();
- // Prevent normal commands.
- NoAction();
- // Disable shield.
- Link->Action = LA_NONE;
- Link->Action = LA_ATTACKING;
- // Draw Link.
- Screen->DrawTile(2, Link->X - 8, Link->Y - 8, tile + Link->Dir * 2, 2, 2,
- cset, -1, -1, 0, 0, 0, 0, true, OP_OPAQUE);
- // Wait for the next frame.
- Waitframe();
- }
- // Make Link visible again.
- Link->Invisible = false;
- // If we don't have ammo, play the fail sound and exit.
- if (!have_ammo) {
- if (CHARGEBOW_FAIL_SOUND) {Game->PlaySound(CHARGEBOW_FAIL_SOUND);}
- ForceCardinal();
- Quit();
- }
- lweapon arrows[3];
- // Create the arrow.
- int dir = ChargeBow.LinkInputDir();
- arrows[0] = ChargeBow.MakeArrow(
- item_id, arrow_tile, arrow_cset, charge_level, CHARGEBOW_ELEMENT_NONE, dir);
- // Triple shot for charge level 2.
- if (2 == charge_level) {
- arrows[1] = ChargeBow.MakeArrow(
- item_id, arrow_tile, arrow_cset, charge_level,
- CHARGEBOW_ELEMENT_NONE, RotateDir8(dir, 1));
- arrows[2] = ChargeBow.MakeArrow(
- item_id, arrow_tile, arrow_cset, charge_level,
- CHARGEBOW_ELEMENT_NONE, RotateDir8(dir, -1));
- }
- UseAmmo(charge_level);
- PlayShotSound(charge_level);
- ForceCardinal();
- while (true) {
- bool any_valid = false;
- // Loop through all arrows.
- for (i = 0; i < 3; ++i) {
- // Make sure arrow exists.
- lweapon arrow = arrows[i];
- if (!arrow->isValid()) {continue;}
- any_valid = true;
- // Check for burning the arrow.
- if (LW_ARROW == arrow->ID && ComboFI(arrow->X + 8, arrow->Y + 8, CHARGEBOW_BURN_FLAG)) {
- // Make the new weapon in the same spot.
- lweapon new_arrow = Screen->CreateLWeapon(LW_FIRE);
- new_arrow->Damage = ChargeBow_Damage(item_id, charge_level, CHARGEBOW_ELEMENT_FIRE);
- new_arrow->Dir = arrow->Dir;
- new_arrow->X = arrow->X;
- new_arrow->Y = arrow->Y;
- new_arrow->Step = 0;
- new_arrow->OriginalTile = arrow_tile + CHARGEBOW_FIRE_TILE_OFFSET
- + arrow->Dir * CHARGEBOW_FIRE_FRAMECOUNT;
- new_arrow->Tile = arrow_tile + CHARGEBOW_FIRE_TILE_OFFSET
- + arrow->Dir * CHARGEBOW_FIRE_FRAMECOUNT;
- new_arrow->OriginalCSet = fire_cset;
- new_arrow->CSet = fire_cset;
- new_arrow->NumFrames = CHARGEBOW_FIRE_FRAMECOUNT;
- new_arrow->ASpeed = CHARGEBOW_ARROW_ASPEED;
- // Start tracking the new weapon instead.
- Remove(arrow);
- arrow = new_arrow;
- arrows[i] = arrow;
- // Play the burn sound.
- if (CHARGEBOW_BURN_SOUND) {Game->PlaySound(CHARGEBOW_BURN_SOUND);}
- }
- // If the arrow is a fire arrow, move it manually, since we don't want it to stop.
- if (LW_FIRE == arrow->ID) {
- int speed = ChargeBow_Speed(item_id, charge_level, CHARGEBOW_ELEMENT_FIRE);
- arrow->X += ChargeBow.DirX(arrow->Dir) * speed;
- arrow->Y += ChargeBow.DirY(arrow->Dir) * speed;
- arrow->DeadState = WDS_ALIVE;
- // Get rid of if it hits the edge of the screen.
- if (arrow->X < 0 || 256 <= arrow->X || arrow->Y < 0 || 176 <= arrow->Y) {Remove(arrow);}
- }
- }
- // Quit if there's no arrows left.
- if (!any_valid) {Quit();}
- Waitframe();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement