#include "std.zh"
#include "string.zh"
#include "ffcscript.zh"
namespace Mani
{
//code here
ffc script Healing_Tile{
void run(int Type){
bool PlayTheSFX = false;
while(true){
if(Link->X <= this->X + 3 && Link->X >= this->X - 3 && Link->Y < this->Y + 3 && Link->Y > this->Y - 3 ){
if(Type == 0 || Type == 2){
if(Link->HP < Link->MaxHP){
PlayTheSFX = true;
Link->HP ++;
}
}
if(Type == 1 || Type == 2){
if(Link->MP < Link->MaxMP){
PlayTheSFX = true;
Link->MP ++;
}
if(Link->MP < Link->MaxMP)Link->MP ++;
if(Link->MP < Link->MaxMP)Link->MP ++;
if(Link->MP < Link->MaxMP)Link->MP ++;
}
}
if(PlayTheSFX){
Game->PlaySound(23);
PlayTheSFX = false;
}
Waitframe();
}
}
}
// Item secripts //
//Spin attack SFX for the sword
const int MW_SPINATTACK_SFX = 54;
//Spin attack Charge time
const int MW_SWORD_CHARGE = 120;
item script ManiSword{
void run(int StabType, int Unused2, int Unused3, int S_DMG, int Range, int SFX, int Variable4){
if(!CounterCost(this->CostCounter, this->Cost) && this->Cost > 0) return;
Link->Action = LA_ATTACKING;
Game->PlaySound(SFX);
int DMG = this->Power;
int Sprite = this->Sprites[0];
int ItemID = this->ID;
//Check for Stab or Swing based on Input duration
int AttackType = 0; // 0 = Default and is Slash. 1 = Stabbing
if(StabType == 0){
int Stab = 0;
while(Link->Dir == DIR_LEFT && Link->InputLeft && Stab < 4
|| Link->Dir == DIR_RIGHT && Link->InputRight && Stab < 4
|| Link->Dir == DIR_UP && Link->InputUp && Stab < 4
|| Link->Dir == DIR_DOWN && Link->InputDown && Stab < 4){
Stab++;
Waitframe();
}
if(Stab >= 4) AttackType = 1; // Stabbing time!
}
else if(StabType == 1){
AttackType = 1; // Stabbing time!
}
else if(StabType == 2){
AttackType = 0; // Slash Sword
}
int BaseImg = 0;
int BaseCSet = 0;
int OrgDir = Link->Dir;
int OrgX = Link->X;
int OrgY = Link->Y;
lweapon Damage;
lweapon Sword;
Sword = Screen->CreateLWeapon(LW_SCRIPT10);
Sword->UseSprite(Sprite);
Sword->CollDetection = false;
Sword->X = Link->X;
Sword->Y = Link->Y;
BaseImg = Sword->OriginalTile;
BaseCSet = Sword->OriginalCSet;
int Sw_Dir = OrgDir;
if(AttackType == 1) StabSword(Range * 2 + 2, false, Damage, Sword, Sw_Dir, Range, DMG);
else{
SwingSword(2, false, Damage, Sword, Sw_Dir, Range, DMG);
}
Link->Action = LA_NONE;
//cleanup
if(Sword->isValid()){
Sword->DeadState = 0;
Sword->X = -70000;
Sword->Y = -70000;
}
if(Damage->isValid()){
Damage->DeadState = 0;
Damage->X = -70000;
Damage->Y = -70000;
}
//If the special move damage is set to 0, there is no special move.
if(S_DMG > 0){
//This function uses S_DMG for MP cost here, rather than damage value, actually not used at all, lol, needs to be not zero
//Brings the FFC with you:
//this->Flags[FFCF_CARRYOVER] = true; //actually waaaaay too cursed to use.
int ChargeUp = 0;
while(((GetEquipmentB() == ItemID) && Link->InputB == true) || ((GetEquipmentA() == ItemID) && Link->InputA == true)
|| (Link->ItemX == ItemID && Link->InputEx1)
|| (Link->ItemY == ItemID && Link->InputEx2)){
ChargeUp ++;
//If the special move have any requirements, this is where you put a check for that in order to play the charge complete SFX.
if(ChargeUp == MW_SWORD_CHARGE){
Game->PlaySound(35);
}
Waitframe();
}
//this->Flags[FFCF_CARRYOVER] = false;
//This part happens when you have charged long enough and meet the requirements.
if(ChargeUp >= MW_SWORD_CHARGE){
Game->PlaySound(SFX);
Link->Action = LA_ATTACKING;
Sword = Screen->CreateLWeapon(LW_SCRIPT10);
Sword->UseSprite(Sprite);
Sword->CollDetection = false;
Sword->X = Link->X;
Sword->Y = Link->Y;
SwingSword(5, true, Damage, Sword, Link->Dir, Range, DMG*2);
Link->Action = LA_NONE;
}
}
//cleanup
if(Sword->isValid()){
Sword->DeadState = 0;
Sword->X = -70000;
Sword->Y = -70000;
}
if(Damage->isValid()){
Damage->DeadState = 0;
Damage->X = -70000;
Damage->Y = -70000;
}
//this->Data = 0;
//this->X = 0;
//this->Y = 0;
}
void SwingSword(int MakeSwings, bool TurnLink, lweapon Damage, lweapon Sword, int Sw_Dir, int Range, int DMG){
int Swings = 0;
float SwingAngle = 0;
int SwindDistance = Range;
int SwingTime = 8;
int Swordtile = Sword->Tile;
int SwordCSet = Sword->CSet;
Sword->UseSprite(BLNK_SPRITE);
if(MakeSwings > 2) SwingTime = 6;
while(Swings < MakeSwings){
Link->Action = LA_NONE;
Link->Action = LA_ATTACKING;
for(int i = 0; i < SwingTime; i++){
if(i < 14){
Link->Action = LA_NONE;
Link->Action = LA_ATTACKING;
}
if(Damage->isValid() == false){
Damage = Screen->CreateLWeapon(LW_SCRIPT10);
Damage->UseSprite(BLNK_SPRITE);
Damage->HitWidth = 16;
Damage->HitHeight = 16;
Damage->Damage = DMG;
Damage->Weapon = LW_SWORD;
Damage->Flags[WFLAG_PICKUP_ITEMS] = true;
}
if(Sw_Dir == DIR_UP){
SwingAngle = 0; //if(i < SwingTime/2) Damage->Dir = DIR_RIGHT;
}
else if(Sw_Dir == DIR_RIGHT){
SwingAngle = 90; //if(i < SwingTime/2) Damage->Dir = DIR_DOWN;
}
else if(Sw_Dir == DIR_DOWN){
SwingAngle = 180; //if(i < SwingTime/2) Damage->Dir = DIR_LEFT;
}
else if(Sw_Dir == DIR_LEFT){
SwingAngle = 270; //if(i < SwingTime/2) Damage->Dir = DIR_UP;
}
if(TurnLink) Link->Dir = Sw_Dir;
Damage->Dir = Link->Dir;
SwingAngle = SwingAngle - (i*(90/SwingTime));
Sword->X = Link->X + VectorX(SwindDistance, SwingAngle);
Sword->Y = Link->Y + VectorY(SwindDistance, SwingAngle);
Damage->X = Link->X + VectorX(SwindDistance + 8, SwingAngle);
Damage->Y = Link->Y + VectorY(SwindDistance + 8, SwingAngle);
//Screen->PutPixel(6, Sword->X, Sword->Y, 0x44, 0, 0, 0, OP_OPAQUE);
if(Sword->X != 0 && Sword->Y != 0) Screen->DrawTile(2, Sword->X - 8, Sword->Y, Swordtile, 2, 1, SwordCSet, -1, -1, Sword->X - 8, Sword->Y, SwingAngle, 0, true, OP_OPAQUE);
// ManiCollectItem(Damage);
Waitframe();
}
Swings++;
if(Sw_Dir == DIR_UP) Sw_Dir = DIR_LEFT;
else if(Sw_Dir == DIR_RIGHT) Sw_Dir = DIR_UP;
else if(Sw_Dir == DIR_DOWN) Sw_Dir = DIR_RIGHT;
else if(Sw_Dir == DIR_LEFT) Sw_Dir = DIR_DOWN;
if(Damage->isValid()){
Damage->DeadState = 0;
//Damage->X = -20000;
//Damage->Y = -20000;
}
}
}
void StabSword(int StabTime, bool TurnLink, lweapon Damage, lweapon Sword, int Sw_Dir, int Range, int DMG){
float SwingAngle = 0;
int SwingDistance = -2;
int Swordtile = Sword->Tile;
int SwordCSet = Sword->CSet;
Sword->UseSprite(BLNK_SPRITE);
Link->Action = LA_NONE;
Link->Action = LA_ATTACKING;
for(int i = 0; i < StabTime; i++){
if(i < 14){
Link->Action = LA_NONE;
Link->Action = LA_ATTACKING;
}
if(Damage->isValid() == false){
Damage = Screen->CreateLWeapon(LW_SCRIPT10);
Damage->UseSprite(BLNK_SPRITE);
Damage->HitWidth = 16;
Damage->HitHeight = 16;
Damage->Damage = DMG;
Damage->Weapon = LW_SWORD;
Damage->Flags[WFLAG_PICKUP_ITEMS] = true;
}
if(i + (Range/2) + 2 >= StabTime) SwingDistance = SwingDistance - 2;
else if(SwingDistance < Range){
SwingDistance = SwingDistance + 2;
if(SwingDistance > Range) SwingDistance = Range;
}
if(Sw_Dir == DIR_UP){
SwingAngle = 270; //if(i < SwingTime/2) Damage->Dir = DIR_RIGHT;
}
else if(Sw_Dir == DIR_RIGHT){
SwingAngle = 0; //if(i < SwingTime/2) Damage->Dir = DIR_DOWN;
}
else if(Sw_Dir == DIR_DOWN){
SwingAngle = 90; //if(i < SwingTime/2) Damage->Dir = DIR_LEFT;
}
else if(Sw_Dir == DIR_LEFT){
SwingAngle = 180; //if(i < SwingTime/2) Damage->Dir = DIR_UP;
}
if(TurnLink) Link->Dir = Sw_Dir;
Damage->Dir = Link->Dir;
Sword->X = Link->X + VectorX(SwingDistance, SwingAngle);
Sword->Y = Link->Y + VectorY(SwingDistance, SwingAngle);
Damage->X = Link->X + VectorX(SwingDistance + 8, SwingAngle);
Damage->Y = Link->Y + VectorY(SwingDistance + 8, SwingAngle);
//Screen->PutPixel(6, Sword->X, Sword->Y, 0x44, 0, 0, 0, OP_OPAQUE);
if(Sword->X != 0 && Sword->Y != 0) Screen->DrawTile(2, Sword->X - 8, Sword->Y, Swordtile, 2, 1, SwordCSet, -1, -1, Sword->X - 8, Sword->Y, SwingAngle, 0, true, OP_OPAQUE);
// ManiCollectItem(Damage);
Waitframe();
}
if(Sw_Dir == DIR_UP) Sw_Dir = DIR_LEFT;
else if(Sw_Dir == DIR_RIGHT) Sw_Dir = DIR_UP;
else if(Sw_Dir == DIR_DOWN) Sw_Dir = DIR_RIGHT;
else if(Sw_Dir == DIR_LEFT) Sw_Dir = DIR_DOWN;
if(Damage->isValid()){
Damage->DeadState = 0;
//Damage->X = -20000;
//Damage->Y = -20000;
}
}
}
// FFC Scripts //--------------------------------------//
ffc script TriggerOrb{ // Trigger orbs, hit all on screen on the same time to trigger secrets.
void run(int WeaponType, int Checker){
int OriginalTile = this->Data;
lweapon ValidWeapon;
int ThisNumb = FFCNum(this);
int FFCs[35];
ffc CheckFFC;
int TotalFFCs = 0;
//If checker then make array
if(Checker > 0){
for(int i = 0; i < 35; i++){
FFCs[i] = -1;
}
int ArraySpot = 0;
for(int i=1; i<=32; i++){
CheckFFC = Screen->LoadFFC(i);
if(CheckFFC->Script == this->Script){
FFCs[ArraySpot] = FFCNum(CheckFFC);
ArraySpot ++;
}
}
TotalFFCs = ArraySpot;
}
while(Screen->State[ST_SECRET] == false){
//Check to see if self is hit
for(int i = 1; i <= Screen->NumLWeapons(); i++){
ValidWeapon = Screen->LoadLWeapon(i);
if(ValidWeapon->Weapon > 0 && ValidWeapon->Weapon == WeaponType && Collision(this, ValidWeapon)) this->Misc[8] = 2;
else if(ValidWeapon->ID == WeaponType && Collision(this, ValidWeapon)) this->Misc[8] = 2;
}
//If checker then check all orbs and trigger secret
if(Checker > 0){
int ArraySpot = 0;
int ActiveOrbs = 0;
for(int i = 0; FFCs[i] != -1; i++){
if(FFCs[i] > -1){
CheckFFC = Screen->LoadFFC(FFCs[i]);
if(CheckFFC->Misc[8] > 0) ActiveOrbs ++;
}
if(ActiveOrbs == TotalFFCs){
Screen->TriggerSecrets();
Screen->State[ST_SECRET] = true;
Game->PlaySound(27);
}
}
//Screen->DrawInteger(6, this->X +8, this->Y - 24, 0, 0x0F, -1, -1, -1, TotalFFCs, 0, OP_OPAQUE);
//Screen->DrawInteger(6, this->X +8 , this->Y - 16, 0, 0x0F, -1, -1, -1, ActiveOrbs, 0, OP_OPAQUE);
}
//Visuals of switch and hit frames decreasing
if(this->Misc[8] > 0) this->Data = OriginalTile + 1;
else if(this->Data != OriginalTile) this->Data = OriginalTile;
if(this->Misc[8] > 0) this->Misc[8] --;
Waitframe();
}
//Setting tile when ending script
this->Data = OriginalTile + 2;
}
}
ffc script SecretActivater{ // Triggers secrets when run.
void run(){
SecretTrigger(9);
}
}
ffc script ItemCheckSecret{ // Secret trigger if Hero has a variable number of items (from 1 to 7)
void run(int D0, int D1, int D2, int D3, int D4, int D5, int D6, int SFX){
while(Screen->State[ST_SECRET] == false){
if(D1 == 0) D1 = D0;
if(D2 == 0) D2 = D0;
if(D3 == 0) D3 = D0;
if(D4 == 0) D4 = D0;
if(D5 == 0) D5 = D0;
if(D6 == 0) D6 = D0;
if(SFX == 0) SFX = 27;
if((Link->Item[D0] == true) && (Link->Item[D1] == true) && (Link->Item[D2] == true) && (Link->Item[D3] == true) && (Link->Item[D4] == true) && (Link->Item[D5] == true) && (Link->Item[D6] == true)){
Waitframes(60);
Game->PlaySound(SFX);
Screen->TriggerSecrets();
Screen->State[ST_SECRET] = true;
}
Waitframe();
}
}
}
ffc script TenRupeeRoom{ // Oracles style rupee room (very cursed) requires four identical looking rupee items.
void run(int LowChance, int MidChamce, int HighChance, int BigRupeeID, int Medium, int Small, int OneRupee){
if(Screen->State[ST_ITEM]) return;
int Placed = 1;
int CreateID = 0;
item Rupee;
int X = 16 * 5;
int Y = 16 * 3;
int Offset = 0;
while(Placed <= 34){
// these used: SeedRand() before instead of Rand
if(HighChance != 0 && Rand(HighChance) == 1) CreateID = BigRupeeID;
else if(MidChamce != 0 && Rand(MidChamce) == 1) CreateID = Medium;
else if(LowChance != 0 && Rand(LowChance) == 1) CreateID = Small;
else{
CreateID = OneRupee;
}
Rupee = Screen->CreateItem(CreateID);
Rupee->X = X;
Rupee->Y = Y;
Rupee->Pickup = IP_ST_ITEM;
X = X + 16;
if(Placed == 6){
X = 16*5 - 8;
Y = Y + 16;
}
else if(Placed == 13){
X = 16*4;
Y = Y + 16;
}
else if(Placed == 21){
X = 16*5 - 8;
Y = Y + 16;
}
else if(Placed == 28){
X = 16*5;
Y = Y + 16;
}
Placed ++;
// Waitframe();
}
return;
}
}
ffc script TransitionFade{ // Fades the screen after a delay, then warps Hero.
void run(int Timer, int Dmap, int Screen, int Colour, int Speed){
while(Timer > 0){
Timer --;
Waitframe();
}
for(int i = 0; i < 5; i++){
for(int i2 = 0; i < Speed; i++){
FastRectangle(6, 0, -98, 16*17, 16*16, Colour, OP_TRANS);
if(i >= 1) FastRectangle(6, 0, -98, 16*17, 16*16, Colour, OP_TRANS);
if(i >= 2) FastRectangle(6, 0, -98, 16*17, 16*16, Colour, OP_TRANS);
if(i >= 3) FastRectangle(6, 0, -98, 16*17, 16*16, Colour, OP_OPAQUE);
NoActionFull();
Waitframe();
}
}
Link->Warp(Dmap, Screen);
}
}
// Utility Secripts //--------------------------------------//
item script Give_MultItem_AND_String{ // Run on pickup to play a string and give more items, a bit obsoloete.
void run(int PlayString, int Item1, int Item2, int Item3){
Screen->Message(PlayString);
if(Item1 != 0){
Link->Item[Item1] = true;
}
if(Item2 != 0){
Link->Item[Item2] = true;
}
if(Item3 != 0){
Link->Item[Item3] = true;
}
}
}
item script GiveItemS{ //Gives inventory items on all D0-D7 slots. Considering limited item IDs in ZC, this is better than bundel.
void run(int D0, int D1, int D2, int D3, int D4, int D5, int D6, int D7){
if(!Link->Item[D0] && D0 > 0) Link->Item[D0] = true;
if(!Link->Item[D1] && D0 > 0) Link->Item[D1] = true;
if(!Link->Item[D2] && D0 > 0) Link->Item[D2] = true;
if(!Link->Item[D3] && D0 > 0) Link->Item[D3] = true;
if(!Link->Item[D4] && D0 > 0) Link->Item[D4] = true;
if(!Link->Item[D5] && D0 > 0) Link->Item[D5] = true;
if(!Link->Item[D6] && D0 > 0) Link->Item[D6] = true;
if(!Link->Item[D7] && D0 > 0) Link->Item[D7] = true;
}
}
// Utility Functions //--------------------------------------//
int FrameCount; // see function below
void FrameCounter(){ // a simple frame counter for the global scope
FrameCount += 1;
if(FrameCount >= 60){
FrameCount = 0;
}
}
void NoActFullWaitframe(){
NoActionFull();
Waitframe();
}
void NoActionFull(){
Link->InputUp = false; Link->PressUp = false;
Link->InputDown = false; Link->PressDown = false;
Link->InputLeft = false; Link->PressLeft = false;
Link->InputRight = false; Link->PressRight = false;
Link->InputStart = false; Link->PressStart = false;
Link->InputMap = false; Link->PressMap = false;
Link->InputR = false; Link->PressR = false;
Link->InputL = false; Link->PressL = false;
Link->InputA = false; Link->PressA = false;
Link->InputB = false; Link->PressB = false;
Link->InputEx1 = false; Link->PressEx1 = false;
Link->InputEx2 = false; Link->PressEx2 = false;
Link->InputEx3 = false; Link->PressEx3 = false;
Link->InputEx4 = false; Link->PressEx4 = false;
Link->InputAxisUp = false; Link->PressAxisUp = false;
Link->InputAxisDown = false; Link->PressAxisDown = false;
Link->InputAxisLeft = false; Link->PressAxisLeft = false;
Link->InputAxisRight = false; Link->PressAxisRight = false;
}
void FasterRupeeDrain(){ // Empties the rupee drain counter faster; Should run every frame from the global scope.
if(Game->DCounter[CR_RUPEES]<-50){
Game->DCounter[CR_RUPEES] = Min(0, Game->DCounter[CR_RUPEES]+9);
Game->Counter[CR_RUPEES] = Max(0, Game->Counter[CR_RUPEES]-9);
}
}
void FasterCounterDrain(){ // Same as above but for all counters
for(int i = 0; i < 30; i++){
if(Game->DCounter[i]<-50){
Game->DCounter[i] = Min(0, Game->DCounter[i]+9);
Game->Counter[i] = Max(0, Game->Counter[i]-9);
}
}
}
void SecretTrigger(int SFX){ // Triggers the screen secret when run.
Game->PlaySound(SFX);
Screen->TriggerSecrets();
}
void FastInt(int Layer, int X, int Y, int font, int Colour, int Numb){
Screen->DrawInteger(Layer, X, Y, font, Colour, -1, -1, -1, Numb, 0, OP_OPAQUE);
}
void FasterInt(int Layer, int X, int Y, int Numb){
Screen->DrawInteger(Layer, X, Y, FONT_S2, 0x0E, 0x0F, -1, -1, Numb, 0, OP_OPAQUE);
}
void FastRectangle(int layer, int x, int y, int x2, int y2, int color, int opacity){
Screen->Rectangle(layer, x, y, x2, y2, color, 1, 0, 0, 0, true, opacity);
}
bool isSolid_Water(int x, int y){
if(Screen->ComboT[ComboAt(x, y)] == CT_WATER) return false;
else{
if(Screen->isSolid(x, y)) return true;
}
}
bool RestrictUseScrnEdg(){
if(Hero->Dir == DIR_LEFT && Hero->X < 16) return true;
else if(Hero->Dir == DIR_RIGHT && Hero->X > 16*14) return true;
else if(Hero->Dir == DIR_UP && Hero->Y < 16) return true;
else if(Hero->Dir == DIR_DOWN && Hero->Y > 16*9) return true;
else{
return false;
}
}
bool ChckItmButtonInput(int ItemID){
if(Hero->ItemA == ItemID && Input->Press[CB_A]) return true;
else if(Hero->ItemB == ItemID && Input->Press[CB_B]) return true;
else if(Hero->ItemX == ItemID && Input->Press[CB_X]) return true;
else if(Hero->ItemY == ItemID && Input->Press[CB_Y]) return true;
else{
return false;
}
}
} // END OF NAMESPACE