Copy to Clipboard Test

Empty Bottles Code

import "std.zh"
import "ffcscript.zh"

//X--------------------X
//|  Bottle Constants  |
//X--------------------X

const int FFC_SFA = 31; //FFC used for screen freeze A
const int FFC_SFB = 32; //FFC used for screen freeze B
const int CMB_SFA = 2; //Combo used for screen freeze A
const int CMB_SFB = 3; //Combo used for screen freeze B

const int BOTTLE_SETTING_NO_WATER = 0; //Set to 1 if water shouldn't be bottleable

const int TIL_BOTTLE = 52020; //First of the tiles used for the bottle items. Should come in four identical rows.
                              //Tile order in each row should go as such:
							  //Empty, Empty, Red Potion, Green Potion, Blue Potion, Water, Fairy, Bee

const int REDPOTION_HEARTS = 8; //Hearts the red potion heals
const int GREENPOTION_MP = 256; //MP the green potion restores
const int BLUEPOTION_HEARTS = 16; //Hearts the blue potion heals
const int BLUEPOTION_MP = 256; //MP the blue potion restores

const int LW_WATER = 31; //LWeapon type used for bottled water. Script 1 by default
const int SPR_BOTTLEWATER = 88; //Sprite used for bottled water
const int SFX_BOTTLEWATER = 55; //Sound when water is dumped out

const int FAIRY_HEARTS = 3; //Hearts healed by a fairy
const int CMB_FAIRY = 904; //Fairy combo
const int CS_FAIRY = 8; //Fairy cset
const int SFX_FAIRY = 64; //Sound that plays when a fairy appears

const int IC_BOTTLE = 67; //Item class used for bottles. Custom 1 by default.

const int I_BOTTLE1 = 143; //Item ID for the first bottle (Level 1)
const int I_BOTTLE2 = 144; //Item ID for the second bottle (Level 2)
const int I_BOTTLE3 = 145; //Item ID for the second bottle (Level 3)
const int I_BOTTLE4 = 146; //Item ID for the second bottle (Level 4)

const int FREQ_HEARTREFILL = 8; //Frequency in frames at which potions/fairies restore hearts
const int SFX_HEARTREFILL = 22; //Sound when potion/fairy restores a heart
const int FREQ_MAGICSOUND = 8; //Frequency in frames where the magic refill sound plays
const int SFX_MAGICREFILL = 61; //Magic refill sound
const int SFX_ERROR = 62; //Error sound
						  
const int TIL_BOTTLESWING = 52006; //Tile of a right facing open bottle used when trying to catch something
const int CS_BOTTLESWING = 11; //CSet of the swinging bottle
const int SFX_BOTTLESWING = 63; //Sound used for the bottle being swung

const int I_WATERBOTTLE = 150; //Item for bottle water pickup
const int I_FAIRYBOTTLE = 151; //Item for bottle fairy pickup
const int I_BEEBOTTLE = 152; //Item for bottle bee pickup

const int CMB_BEE = 905; //Combo used for the bee
const int CS_BEE = 8; //CSet used for the bee
const int SFX_BEE = 65; //SFX used for the bee
const int LW_BEE = 32; //Lweapon used for the bee (Script 2 by default)
const int EW_BEE = 32; //Eweapon used for the bee (Script 2 by default)
const int DAMAGE_BEE = 4; //Damage the bee deals
const int FFCM_BEE_SELFDESTRUCT = 0; //FFC misc used to tell the bee to disappear

const int STR_CANTAFFORD = 2; //Message for when you can't afford an item
const int STR_NOBOTTLE = 3; //Message for when you don't have a bottle to store a potion in

const int C_WHITE = 0x01; //The color white
const int C_BLACK = 0x0F; //The color black


//X--------------------------X
//|  Screen Freeze Function  |
//X--------------------------X

void Screen_Freeze(){
	ffc f1 = Screen->LoadFFC(FFC_SFA);
	ffc f2 = Screen->LoadFFC(FFC_SFB);
	f1->Data = CMB_SFA;
	f2->Data = CMB_SFB;
}

void Screen_Unfreeze(){
	ffc f1 = Screen->LoadFFC(FFC_SFA);
	ffc f2 = Screen->LoadFFC(FFC_SFB);
	f1->Data = 0;
	f2->Data = 0;
}


//X--------------------------X
//|  Empty Bottle Functions  |
//X--------------------------X

//X--------------------------------------------------------X
//|  These constants don't need to be changed.             |
//|  They just define various states of the empty bottle.  |
//|  BS_ constants are also used for  the potion filling   |
//|  pickup item script. Look here to see what to set D2   |
//|  to for that.                                          |
//X--------------------------------------------------------X
//                                                         |
const int BS_EMPTY = 0; //                                 |
const int BS_POTIONRED = 1; //                             |
const int BS_POTIONGREEN = 2; //                           |
const int BS_POTIONBLUE = 3; //                            |
const int BS_WATER = 4; //                                 |
const int BS_FAIRY = 5; //                                 |
const int BS_BEE = 6; //                                   |
//                                                         |
const int BSI_BOTTLEUSED = 4; //                           |
const int BSI_BOTTLETIMER = 5; //                          |
const int BSI_OLDHP = 6; //                                |
const int BSI_OLDMP = 7; //                                |
const int BSI_FAIRYTIMER = 8; //                           |
const int BSI_FAIRYREVIVE = 9; //                          |
//                                                         |
//---------------------------------------------------------X


int BottleState[12]; //0-3: States of bottles, 4: Bottle used, 
                     //5: Potion timer, 6: OldHP, 7: OldMP

//This function should be called at the beginning of your global and 
//refreshes the graphics for the bottles.
void RefreshBottles(){
	for(int i=0; i<4; i++){
		CopyTile(TIL_BOTTLE+20*i+1+BottleState[i], TIL_BOTTLE+20*i);
	}
}

int UsingEmptyBottle(){
	if(Link->PressA){
		int id = GetEquipmentA();
		if(id>0){
			itemdata A = Game->LoadItemData(id);
			if(A->Family==IC_BOTTLE)
				return A->Level-1;
		}
	}
	else if(Link->PressB){
		int id = GetEquipmentB();
		if(id>0){
			itemdata B = Game->LoadItemData(id);
			if(B->Family==IC_BOTTLE)
				return B->Level-1;
		}
	}
	return -1;
}

bool CanFillBottle(){
	int bottles[4] = {I_BOTTLE1, I_BOTTLE2, I_BOTTLE3, I_BOTTLE4};
	for(int i=0; i<4; i++){
		if(Link->Item[bottles[i]]&&BottleState[i]==BS_EMPTY)
			return true;
	}
	return false;
}

int FillBottle(int state){
	int bottles[4] = {I_BOTTLE1, I_BOTTLE2, I_BOTTLE3, I_BOTTLE4};
	for(int i=0; i<4; i++){
		if(Link->Item[bottles[i]]&&BottleState[i]==BS_EMPTY){
			BottleState[i] = state;
			RefreshBottles();
			return i;
		}
	}
}

int HasFairy(){
	int bottles[4] = {I_BOTTLE1, I_BOTTLE2, I_BOTTLE3, I_BOTTLE4};
	for(int i=0; i<4; i++){
		if(Link->Item[bottles[i]]&&BottleState[i]==BS_FAIRY)
			return i;
	}
	return -1;
}

//This function goes in the while loop of your global script before waitdraw
void EmptyBottleGlobal(){
	int bottle = BottleState[BSI_BOTTLEUSED];
	if(BottleState[BSI_BOTTLETIMER]>0){
		if(BottleState[bottle]==BS_POTIONRED){
			if(BottleState[BSI_BOTTLETIMER]%FREQ_HEARTREFILL==0){
				Link->HP += 16;
				Game->PlaySound(SFX_HEARTREFILL);
				if(Link->HP>=Link->MaxHP){
					BottleState[BSI_BOTTLETIMER] = 0;
				}
			}
		}
		else if(BottleState[bottle]==BS_POTIONGREEN){
			Link->MP += 2;
			if(BottleState[BSI_BOTTLETIMER]%FREQ_MAGICSOUND==0)
				Game->PlaySound(SFX_MAGICREFILL);
			if(Link->MP>=Link->MaxMP){
				BottleState[BSI_BOTTLETIMER] = 0;
			}
		}
		else if(BottleState[bottle]==BS_POTIONBLUE){
			if(BottleState[BSI_BOTTLETIMER]%FREQ_HEARTREFILL==0&&Link->HP<BottleState[BSI_OLDHP]+BLUEPOTION_HEARTS*16&&Link->HP<Link->MaxHP){
				Link->HP += 16;
				Game->PlaySound(SFX_HEARTREFILL);
			}
			if(Link->MP<BottleState[BSI_OLDMP]+BLUEPOTION_MP&&Link->MP<Link->MaxMP){
				if(BottleState[BSI_BOTTLETIMER]%FREQ_MAGICSOUND==0)
					Game->PlaySound(SFX_MAGICREFILL);
				Link->MP += 2;
			}
			if(Link->HP>=Link->MaxHP&&Link->MP>=Link->MaxMP){
				BottleState[BSI_BOTTLETIMER] = 0;
			}
		}
		else if(BottleState[bottle]==BS_FAIRY){
			if(BottleState[BSI_BOTTLETIMER]<2&&BottleState[BSI_FAIRYTIMER]<120)
				BottleState[BSI_BOTTLETIMER] = 2;
			BottleState[BSI_FAIRYTIMER]++;
			int X = Link->X+VectorX(16*(BottleState[BSI_FAIRYTIMER]/120), BottleState[BSI_FAIRYTIMER]*8);
			int Y = Link->Y+VectorY(8*(BottleState[BSI_FAIRYTIMER]/120), BottleState[BSI_FAIRYTIMER]*8)-BottleState[BSI_FAIRYTIMER]/8;
			if(BottleState[BSI_FAIRYREVIVE]==1){
				if(BottleState[BSI_FAIRYTIMER]<10||BottleState[BSI_FAIRYTIMER]>110)
					Screen->Rectangle(6, 0, 0, 256, 176, C_BLACK, 1, 0, 0, 0, true, 64);
				else
					Screen->Rectangle(6, 0, 0, 256, 176, C_BLACK, 1, 0, 0, 0, true, 128);
				Screen->FastTile(6, Link->X+Link->DrawXOffset, Link->Y+Link->DrawYOffset, Link->Tile, 6, 128);
			}
			if(BottleState[BSI_FAIRYTIMER]<80||BottleState[BSI_FAIRYTIMER]%2==0)
				Screen->FastCombo(6, X, Y, CMB_FAIRY, CS_FAIRY, 128);
			if(BottleState[BSI_BOTTLETIMER]%FREQ_HEARTREFILL==0&&Link->HP<Link->MaxHP){
				Link->HP += 16;
				Game->PlaySound(SFX_HEARTREFILL);
			}
			if(Link->HP>=Link->MaxHP&&BottleState[BSI_FAIRYTIMER]>=120){
				BottleState[BSI_BOTTLETIMER] = 0;
			}
		}
		BottleState[BSI_BOTTLETIMER]--;
		NoAction();
		if(BottleState[BSI_BOTTLETIMER]<=0){
			BottleState[bottle] = BS_EMPTY;
			BottleState[BSI_BOTTLEUSED] = -1;
			RefreshBottles();
			Screen_Unfreeze();
		}
	}
	else{
		bottle = UsingEmptyBottle();
		if(bottle>-1){
			if(BottleState[bottle]==BS_EMPTY){
				int scriptname[] = "Bottle_Empty";
				int scriptid = Game->GetFFCScript(scriptname);
				int Args[8] = {bottle};
				RunFFCScript(scriptid, Args);
			}
			else if(BottleState[bottle]==BS_POTIONRED){
				if(Link->HP==Link->MaxHP){
					Game->PlaySound(SFX_ERROR);
				}
				else{
					BottleState[BSI_BOTTLEUSED] = bottle;
					BottleState[BSI_BOTTLETIMER] = FREQ_HEARTREFILL*REDPOTION_HEARTS;
					Screen_Freeze();
				}
			}
			else if(BottleState[bottle]==BS_POTIONGREEN){
				if(Link->MP==Link->MaxMP){
					Game->PlaySound(SFX_ERROR);
				}
				else{
					BottleState[BSI_BOTTLEUSED] = bottle;
					BottleState[BSI_BOTTLETIMER] = GREENPOTION_MP/2;
					Screen_Freeze();
				}
			}
			else if(BottleState[bottle]==BS_POTIONBLUE){
				if(Link->HP==Link->MaxHP&&Link->MP==Link->MaxMP){
					Game->PlaySound(SFX_ERROR);
				}
				else{
					BottleState[BSI_BOTTLEUSED] = bottle;
					BottleState[BSI_BOTTLETIMER] = Max(FREQ_HEARTREFILL*BLUEPOTION_HEARTS, BLUEPOTION_MP/2);
					BottleState[BSI_OLDHP] = Link->HP;
					BottleState[BSI_OLDMP] = Link->MP;
					Screen_Freeze();
				}
			}
			else if(BottleState[bottle]==BS_WATER){
				Link->Action = LA_ATTACKING;
				lweapon l = CreateLWeaponAt(LW_WATER, Link->X+InFrontX(Link->Dir, 0), Link->Y+InFrontY(Link->Dir, 0));
				l->UseSprite(SPR_BOTTLEWATER);
				l->DeadState = l->ASpeed*l->NumFrames;
				l->CollDetection = false;
				Game->PlaySound(SFX_BOTTLEWATER);
				BottleState[bottle] = BS_EMPTY;
				RefreshBottles();
			}
			else if(BottleState[bottle]==BS_FAIRY){
				if(Link->HP==Link->MaxHP){
					Game->PlaySound(SFX_ERROR);
				}
				else{
					BottleState[BSI_BOTTLEUSED] = bottle;
					BottleState[BSI_BOTTLETIMER] = FREQ_HEARTREFILL*FAIRY_HEARTS;
					BottleState[BSI_FAIRYTIMER] = 0;
					BottleState[BSI_FAIRYREVIVE] = 0;
					Game->PlaySound(SFX_FAIRY);
					Screen_Freeze();
				}
			}
			else if(BottleState[bottle]==BS_BEE){
				int scriptname[] = "Bottle_Bee";
				int scriptid = Game->GetFFCScript(scriptname);
				int vars[8] = {1};
				RunFFCScript(scriptid, vars);
				BottleState[bottle] = BS_EMPTY;
				RefreshBottles();
			}
		}
		int fairy = HasFairy();
		if(Link->HP<=0&&fairy>-1){
			Link->HP = 1;
			BottleState[BSI_BOTTLEUSED] = fairy;
			BottleState[BSI_BOTTLETIMER] = FREQ_HEARTREFILL*FAIRY_HEARTS;
			BottleState[BSI_FAIRYTIMER] = 0;
			BottleState[BSI_FAIRYREVIVE] = 1;
			Game->PlaySound(SFX_FAIRY);
			Screen_Freeze();
		}
	}
}


//X-------------------------------X
//|  Empty Bottle Action Scripts  |
//X-------------------------------X

ffc script Bottle_Empty{
	void run(int bottleid){
		int Angle = 0;
		if(Link->Dir==DIR_UP)
			Angle = -90;
		else if(Link->Dir==DIR_DOWN)
			Angle = 90;
		else if(Link->Dir==DIR_LEFT)
			Angle = 180;
		Game->PlaySound(SFX_BOTTLESWING);
		Link->Action = LA_ATTACKING;
		int Collected = 0;
		for(int i=-45; i<45; i+=10){
			int X = Link->X+VectorX(12, Angle+i);
			int Y = Link->Y+VectorY(12, Angle+i);
			Screen->DrawTile(2, X, Y, TIL_BOTTLESWING, 1, 1, CS_BOTTLESWING, -1, -1, X, Y, Angle+i+90, 0, true, 128);
			if(Collected==0||Collected==BS_WATER){
				if(OnWater(X+8, Y+8)&&Collected==0&&BOTTLE_SETTING_NO_WATER==0){
					Collected = BS_WATER;
				}
				for(int j=1; j<=Screen->NumItems(); j++){
					item itm = Screen->LoadItem(j);
					if(itm->ID==I_FAIRY||itm->ID==I_FAIRYSTILL){
						if(RectCollision(itm->X+itm->HitXOffset, itm->Y+itm->HitYOffset, itm->X+itm->HitXOffset+itm->HitWidth, itm->Y+itm->HitYOffset+itm->HitHeight, X+4, Y+4, X+11, Y+11)){
							Collected = BS_FAIRY;
							Remove(itm);
							break;
						}
					}
				}
				for(int j=1; j<=32; j++){
					ffc f = Screen->LoadFFC(j);
					int scriptname[] = "Bottle_Bee";
					int scriptid = Game->GetFFCScript(scriptname);
					if(f->Script==scriptid){
						if(RectCollision(X+4, Y+4, X+11, Y+11, f->X+4, f->Y+4, f->X+11, f->Y+11)){
							Collected = BS_BEE;
							f->Misc[FFCM_BEE_SELFDESTRUCT] = 1;
						}
					}
				}
			}
			WaitNoAction();
		}
		if(Collected==BS_WATER){
			BottleState[bottleid] = BS_WATER;
			RefreshBottles();
			item itm = CreateItemAt(I_WATERBOTTLE, Link->X, Link->Y);
			itm->Pickup = IP_HOLDUP;
		}
		else if(Collected==BS_FAIRY){
			BottleState[bottleid] = BS_FAIRY;
			RefreshBottles();
			item itm = CreateItemAt(I_FAIRYBOTTLE, Link->X, Link->Y);
			itm->Pickup = IP_HOLDUP;
		}
		else if(Collected==BS_BEE){
			BottleState[bottleid] = BS_BEE;
			RefreshBottles();
			item itm = CreateItemAt(I_BEEBOTTLE, Link->X, Link->Y);
			itm->Pickup = IP_HOLDUP;
		}
		WaitNoAction(10);
	}
	bool OnWater(int x, int y){
		int ct = Screen->ComboT[ComboAt(x, y)];
		if(ct==CT_WATER||ct==CT_SHALLOWWATER)
			return true;
		return false;
	}
}

ffc script Bottle_Bee{
	void run(int friendly){
		this->Data = CMB_BEE;
		this->CSet = CS_BEE;
		if(friendly==1){
			this->X = Link->X;
			this->Y = Link->Y;
		}
		int i; int j; int k;
		int X = this->X;
		int Y = this->Y;
		lweapon lh;
		eweapon eh;
		int Lifespan = Rand(900, 1200);
		for(i=0; i<40; i++){
			Y -= 0.5;
			this->X = X;
			this->Y = Y;
			Waitframe();
		}
		while(Lifespan>0){
			int Angle;
			if(friendly==1){
				int Tx = -1000;
				int Ty = -1000;
				int Dist = 1000;
				for(i=1; i<=Screen->NumNPCs(); i++){
					npc n = Screen->LoadNPC(i);
					if(Distance(X+8, Y+8, CenterX(n), CenterY(n))<Dist){
						Dist = Distance(X+8, Y+8, CenterX(n), CenterY(n));
						Tx = CenterX(n)-8;
						Ty = CenterY(n)-8;
					}
				}
				Angle = Angle(X, Y, Tx, Ty);
				if(Screen->NumNPCs()==0)
					Angle = Angle(X, Y, Link->X, Link->Y);
			}
			else{
				if(Distance(Link->X, Link->Y, X, Y)<80&&Rand(2)==0)
					Angle = Angle(X, Y, Link->X, Link->Y);
				else
					Angle = Rand(360);
			}
			k = Rand(32, 48);
			for(i=0; i<k; i++){
				Lifespan--;
				j = (j+1)%360;
				if(j%30==0)
					Game->PlaySound(SFX_BEE);
				X = Clamp(X+VectorX(2, Angle), -16, 256);
				Y = Clamp(Y+VectorY(2, Angle), -16, 176);
				this->X = X;
				this->Y = Y;
				if(friendly==1){
					if(lh->isValid()){
						lh->X = X;
						lh->Y = Y;
					}
					else{
						lh = CreateLWeaponAt(LW_BEE, X, Y);
						lh->HitXOffset = 4;
						lh->HitYOffset = 4;
						lh->HitWidth = 8;
						lh->HitHeight = 8;
						lh->DrawYOffset = -1000;
						lh->Dir = 8;
						lh->Damage = DAMAGE_BEE;
					}
				}
				else{
					if(eh->isValid()){
						eh->X = X;
						eh->Y = Y;
					}
					else{
						eh = CreateEWeaponAt(EW_BEE, X, Y);
						eh->HitXOffset = 4;
						eh->HitYOffset = 4;
						eh->HitWidth = 8;
						eh->HitHeight = 8;
						eh->DrawYOffset = -1000;
						eh->Dir = 8;
						eh->Damage = DAMAGE_BEE;
					}
				}
				if(this->Misc[FFCM_BEE_SELFDESTRUCT]==1){
					if(lh->isValid())
						lh->DeadState = 0;
					if(eh->isValid())
						eh->DeadState = 0;
					this->Data = 0;
					this->CSet = 0;
					Quit();
				}
				Waitframe();
			}
		}
		if(lh->isValid())
			lh->DeadState = 0;
		if(eh->isValid())
			eh->DeadState = 0;
		this->Data = 0;
		this->CSet = 0;
		for(i=0; i<40; i++){
			if(i%2==0)
				Screen->FastCombo(2, X, Y, CMB_BEE, CS_BEE, 128);
			Waitframe();
		}
	}
}


//X----------------------------X
//|  Other Associated Scripts  |
//X----------------------------X

item script PotionFill{
	void run(int str, int state){
		FillBottle(state);
		Screen->Message(str);
	}
}

ffc script ItemShop{
	void run(int id, int strdescription, int price, int potion){
		itemdata ic = Game->LoadItemData(id);
		while(true){
			if(Link->X>this->X-8&&Link->X<this->X+8&&Link->Y>this->Y&&Link->Y<this->Y+10&&Link->Dir==DIR_UP){
				if(Link->PressL){
					Screen->Message(strdescription);
					NoAction();
				}
				else if(Link->PressR){
					if(Game->Counter[CR_RUPEES]+Game->DCounter[CR_RUPEES]>=price){
						if(potion>0&&!CanFillBottle()){
							Screen->Message(STR_NOBOTTLE);
							NoAction();
						}
						else{
							item itm = CreateItemAt(id, Link->X, Link->Y);
							itm->Pickup = IP_HOLDUP;
							Game->DCounter[CR_RUPEES] -= price;
							for(int i=0; i<10; i++){
								WaitNoAction();
							}
						}
					}
					else{
						Screen->Message(STR_CANTAFFORD);
						NoAction();
					}
				}
			}
			DrawPrice(this, price);
			Waitframe();
		}
	}
	void DrawPrice(ffc this, int price){
		int xoff = -2;
		if(price>999)
			xoff = -8;
		else if(price>99)
			xoff = -6;
		else if(price>9)
			xoff = -4;
		Screen->DrawInteger(5, this->X+8+xoff+1, this->Y+18+1, FONT_Z3SMALL, C_BLACK, -1, -1, -1, price, 0, 128);
		Screen->DrawInteger(5, this->X+8+xoff, this->Y+18, FONT_Z3SMALL, C_WHITE, -1, -1, -1, price, 0, 128);
	}
}

ffc script BeeGrass{
	void run(int chances){
		int Combo = Screen->ComboD[ComboAt(this->X+8, this->Y+8)];
		while(Screen->ComboD[ComboAt(this->X+8, this->Y+8)]==Combo){
			Waitframe();
		}
		if(Rand(chances)==0){
			int scriptname[] = "Bottle_Bee";
			int scriptid = Game->GetFFCScript(scriptname);
			int i = RunFFCScript(scriptid, 0);
			ffc f = Screen->LoadFFC(i);
			f->X = this->X;
			f->Y = this->Y;
		}
	}
}

ffc script WaterTrigger{
	void run(){
		if(!Screen->State[ST_SECRET]){
			while(true){
				for(int i=1; i<=Screen->NumLWeapons(); i++){
					lweapon l = Screen->LoadLWeapon(i);
					if(l->ID==LW_WATER&&Collision(this, l)){
						Screen->TriggerSecrets();
						Game->PlaySound(SFX_SECRET);
						Screen->State[ST_SECRET] = true;
						Quit();
					}
				}
				Waitframe();
			}
		}
	}
}

//X-------------------------X
//|  Example Global Script  |
//X-------------------------X


global script Main2{
	void run(){
		RefreshBottles();
		while(true){
			EmptyBottleGlobal();
			Waitdraw();
			Waitframe();
		}
	}
}