Copy to Clipboard Test

Estus Flask (Souls-like) Code

const int ESTUSFLASK_INITIAL_CAPACITY = 5; //How many estus you can carry to start with
const int ESTUSFLASK_MAX_CAPACITY = 20; //The max estus flasks you can ever carry
const int ESTUSFLASK_UPGRADE_TIERS = 5; //How many times the flask can be upgraded (scales healing from ESTUSFLASK_HEALING to ESTUSFLASK_HEALING_MAX)

const int ESTUSFLASK_HEALING = 48; //How much HP the flask heals minimum (16 = one heart)
const int ESTUSFLASK_HEALING_MAX = 80; //How much HP the flask heals maximum
const int ESTUSFLASK_DRINK_TIME = 60; //How many frames it takes to drink a flask and start the healing
const int ESTUSFLASK_HEAL_TIME = 40; //How many frames it takes for the flask to heal

const int ESTUSFLASK_REFILL_ON_F6 = 1; //If 1, the player gets all their flasks back on death/F6
const int ESTUSFLASK_HEALING_IS_PERCENT = 0; //If 1, healing from the estus flask is a percentage of max HP
const int ESTUSFLASK_GETTING_HIT_INTERRUPTS_HEALING = 1; //If 1, getting hit will interrupt the healing even after you finish drinking
const int ESTUSFLASK_CAN_DOUBLE_DRINK = 1; //If 1, using consecutive flasks will make the animation faster
const int ESTUSFLASK_CAN_WASTE = 0; //If 1, getting hit while drinking a flask will waste the flask
const int ESTUSFLASK_BONFIRE_HEALS = 1; //If 1, using a bonfire will fully heal you
const int ESTUSFLASK_BONFIRE_RESETENEMIES = 1; //If 1, using the bonfire will try to reset GuyCount[]
const int ESTUSFLASK_BONFIRE_SETS_CONTINUE = 1; //If 1, using the bonfire will set the continue point
const int ESTUSFLASK_BONFIRE_OVERRIDES_CONTINUE = 0; //If 1, only bonfires will be able to set the continue point

//Tile and CSet for the animation of Link drinking from the estus flask
const int TIL_ESTUSFLASK_DRINK = 540;
const int CS_ESTUSFLASK_DRINK = 6; 
//How many animation frames the drinking animation lasts for
const int FRAMES_ESTUSFLASK_DRINK = 8; 

//Tile for the estus flask item
const int TIL_ESTUSFLASK_ITEM = 520;
//Number of tiles following TIL_ESTUSFLASK_ITEM marking how much is left, going from empty to full
const int STATES_ESTUSFLASK_ITEM = 6;

//Layer, combo, and cset for A button prompts
const int LAYER_APROMPT = 4; 
const int CMB_APROMPT = 900; 
const int CS_APROMPT = 8;

void DrawAPrompt(){
	if(CMB_APROMPT>0)
		Screen->FastCombo(LAYER_APROMPT, Link->X, Link->Y-16, CMB_APROMPT, CS_APROMPT, 128);
}

//Sprite in weapons/misc for particles drawn while healing
const int SPR_ESTUSFLASK_PARTICLES = 88;

//Sound when Link drinks an estus flask
const int SFX_ESTUSFLASK_DRINK = 32; 
//Healing sound after drinking a flask
const int SFX_ESTUSFLASK_HEAL = 56; 
//Sound when refilling estus flasks
const int SFX_ESTUSFLASK_REFILL = 25;

//Counter for the current number of estus flasks (Script 3 by default)
const int CR_ESTUSFLASK_COUNT = 9;
//Counter for the current upgrade level of the estus flask (Script 4 by default)
const int CR_ESTUSFLASK_UPGRADE = 10;

const int _EF_HEALHP = 0;
const int _EF_HEALHP2 = 1;
const int _EF_HEALHPPERFRAME = 2;
const int _EF_DRINKTIMER = 3;
const int _EF_FIRSTLOAD = 4;
const int _EF_MAXREFILL = 5;
const int _EF_UPGRADETIER = 6;
const int _EF_LASTMAP = 7;
const int _EF_CONTINUEDMAP = 8;
const int _EF_CONTINUESCREEN = 9;
const int _EF_MAXDRINKTIME = 10;
const int _EF_DOUBLEDRINKTIMER = 11;
const int _EF_RESETMAP = 20; //First of map enemy spawn reset indices (20-275)
int EstusFlask[512];

void EstusFlask_Init(){
	//On the first load, set the capacity maximum for the flasks
	if(!EstusFlask[_EF_FIRSTLOAD]){
		Game->MCounter[CR_ESTUSFLASK_COUNT] = ESTUSFLASK_MAX_CAPACITY;
		EstusFlask[_EF_MAXREFILL] = ESTUSFLASK_INITIAL_CAPACITY;
		
		EstusFlask[_EF_CONTINUEDMAP] = Game->GetCurMap();
		EstusFlask[_EF_CONTINUESCREEN] = Game->GetCurDMapScreen();
		
		EstusFlask[_EF_FIRSTLOAD] = 1;
	}
	
	if(ESTUSFLASK_REFILL_ON_F6){
		Game->Counter[CR_ESTUSFLASK_COUNT] = EstusFlask[_EF_MAXREFILL];
	}
	
	EstusFlask_RefreshTiles();
}

void EstusFlask_Update(){
	int i; int j;
	//Drinking animation
	if(EstusFlask[_EF_DRINKTIMER]>0){
		i = EstusFlask[_EF_MAXDRINKTIME]-EstusFlask[_EF_DRINKTIMER];
		EstusFlask[_EF_DRINKTIMER]--;
		//If the timer runs out, make Link visible and proceed to the healing
		if(EstusFlask[_EF_DRINKTIMER]==0){
			Link->Invisible = false;
			
			Game->PlaySound(SFX_ESTUSFLASK_HEAL);
			EstusFlask[_EF_DOUBLEDRINKTIMER] = 32;
			//If flasks can be wasted, the counter has been decremented, otherwise do it here
			if(!ESTUSFLASK_CAN_WASTE){
				Game->Counter[CR_ESTUSFLASK_COUNT]--;
			}
		}
		//Otherwise make Link invisible and draw his tiles
		else{
			Link->Invisible = true;
			
			//If Link gets hit, make him visible and interrupt the animation
			if(Link->Action==LA_GOTHURTLAND){
				Link->Invisible = false;
				EstusFlask[_EF_DRINKTIMER] = 0;
				EstusFlask[_EF_HEALHP] = 0;
				EstusFlask[_EF_HEALHPPERFRAME] = 0;
				EstusFlask[_EF_DOUBLEDRINKTIMER] = 0;
			}
			//If he hasn't been hit, draw him
			else{
				int layer = 2;
				if(ScreenFlag(1, 4)) //Layer -2
					layer = 1;
					
				j = Clamp(Floor(i/(EstusFlask[_EF_MAXDRINKTIME]/FRAMES_ESTUSFLASK_DRINK)), 0, EstusFlask[_EF_MAXDRINKTIME]-1);
				Screen->FastTile(layer, Link->X+Link->DrawXOffset, Link->Y+Link->DrawYOffset, TIL_ESTUSFLASK_DRINK+j, CS_ESTUSFLASK_DRINK, 128);
				NoAction();
			}
		}
	}
	else if(EstusFlask[_EF_HEALHP]>0){
		//If Link gets hit or caps out, end the healing
		if(Link->HP>=Link->MaxHP||(ESTUSFLASK_GETTING_HIT_INTERRUPTS_HEALING&&Link->Action==LA_GOTHURTLAND)){
			EstusFlask[_EF_DRINKTIMER] = 0;
			EstusFlask[_EF_HEALHP] = 0;
			EstusFlask[_EF_HEALHPPERFRAME] = 0;
			if(ESTUSFLASK_GETTING_HIT_INTERRUPTS_HEALING&&Link->Action==LA_GOTHURTLAND)
				EstusFlask[_EF_DOUBLEDRINKTIMER] = 0;
		}
		else{
			//Subtract HP each frame being healed from the total frames
			//Get the difference minus decmials to determine how much to heal Link
			j = Floor(EstusFlask[_EF_HEALHP]);
			EstusFlask[_EF_HEALHP] = Max(EstusFlask[_EF_HEALHP]-EstusFlask[_EF_HEALHPPERFRAME], 0);
			int healAmount = j-Floor(EstusFlask[_EF_HEALHP]);
			
			Link->HP += healAmount;
			
			//Draw particles around Link if applicable
			if(SPR_ESTUSFLASK_PARTICLES){
				lweapon particle = CreateLWeaponAt(LW_SCRIPT10, Link->X+Rand(-8, 8), Link->Y+Rand(-8, 8));
				particle->UseSprite(SPR_ESTUSFLASK_PARTICLES);
				particle->DeadState = particle->ASpeed*particle->NumFrames;
				particle->CollDetection = false;
				particle->HitYOffset = -1000;
			}
		}
	}
	
	//Backup heal (Used when double drinking)
	if(EstusFlask[_EF_HEALHP2]>0){
		//If Link gets hit or caps out, end the healing
		if(Link->HP>=Link->MaxHP||(ESTUSFLASK_GETTING_HIT_INTERRUPTS_HEALING&&Link->Action==LA_GOTHURTLAND)){
			EstusFlask[_EF_HEALHP2] = 0;
		}
		else{
			//Subtract HP each frame being healed from the total frames
			//Get the difference minus decmials to determine how much to heal Link
			j = Floor(EstusFlask[_EF_HEALHP2]);
			EstusFlask[_EF_HEALHP2] = Max(EstusFlask[_EF_HEALHP2]-EstusFlask[_EF_HEALHPPERFRAME], 0);
			int healAmount = j-Floor(EstusFlask[_EF_HEALHP2]);
			
			Link->HP += healAmount;
			
			//Draw particles around Link if applicable
			if(SPR_ESTUSFLASK_PARTICLES){
				lweapon particle = CreateLWeaponAt(LW_SCRIPT10, Link->X+Rand(-8, 8), Link->Y+Rand(-8, 8));
				particle->UseSprite(SPR_ESTUSFLASK_PARTICLES);
				particle->DeadState = particle->ASpeed*particle->NumFrames;
				particle->CollDetection = false;
				particle->HitYOffset = -1000;
			}
		}
	}
	
	if(EstusFlask[_EF_DOUBLEDRINKTIMER]>0&&EstusFlask[_EF_DRINKTIMER]<=0)
		EstusFlask[_EF_DOUBLEDRINKTIMER]--;
	
	//Reset all guycounts if a bonfire has been used
	j = Game->GetCurMap();
	if(EstusFlask[_EF_LASTMAP]!=j){
		if(EstusFlask[_EF_RESETMAP+j]){
			for(i=0; i<=0x7F; i++){
				Game->GuyCount[i] = 10;
			}
			EstusFlask[_EF_RESETMAP+j] = 0;
		}
	}
	EstusFlask[_EF_LASTMAP] = j;
	
	//If bonfires overwrite continue points, set them every frame
	if(ESTUSFLASK_BONFIRE_OVERRIDES_CONTINUE){
		Game->LastEntranceDMap = EstusFlask[_EF_CONTINUEDMAP];
		Game->LastEntranceScreen = EstusFlask[_EF_CONTINUESCREEN];
		Game->ContinueDMap = EstusFlask[_EF_CONTINUEDMAP];
		Game->ContinueScreen = EstusFlask[_EF_CONTINUESCREEN];
	}
	
	//Update the estus flask tile to suit how many you have
	EstusFlask_RefreshTiles();
}

void EstusFlask_RefreshTiles(){
	if(TIL_ESTUSFLASK_ITEM>0&&STATES_ESTUSFLASK_ITEM>=2){
		int st = 0;
		if(Game->Counter[CR_ESTUSFLASK_COUNT]>0){
			st = Clamp(Round((Game->Counter[CR_ESTUSFLASK_COUNT]/EstusFlask[_EF_MAXREFILL])*(STATES_ESTUSFLASK_ITEM-1)), 1, STATES_ESTUSFLASK_ITEM-1);
		}
		
		CopyTile(TIL_ESTUSFLASK_ITEM+1+st, TIL_ESTUSFLASK_ITEM);
	}
}

//Put this script as the action script on the estus flask item
item script EstusFlask_Use{
	void run(){
		if(Game->Counter[CR_ESTUSFLASK_COUNT]>0){
			//Calculate how much to heal
			int baseHeal = ESTUSFLASK_HEALING;
			if(ESTUSFLASK_UPGRADE_TIERS>0){
				if(Game->Counter[CR_ESTUSFLASK_UPGRADE]>0){
					int addedHealth = Floor((ESTUSFLASK_HEALING_MAX-ESTUSFLASK_HEALING)*(Game->Counter[CR_ESTUSFLASK_UPGRADE]/ESTUSFLASK_UPGRADE_TIERS));
					baseHeal += addedHealth;
				}
			}
			
			//Get percentage of Link's max HP if applicable
			int healAmount = baseHeal;
			if(ESTUSFLASK_HEALING_IS_PERCENT){
				healAmount = Clamp(Round(Link->HP*(baseHeal*0.01)), 0, Link->MaxHP);
			}
			
			if(EstusFlask[_EF_DRINKTIMER]<=0&&EstusFlask[_EF_HEALHP]<=0&&EstusFlask[_EF_DOUBLEDRINKTIMER]<=0){
				Game->PlaySound(SFX_ESTUSFLASK_DRINK);
				//Set how much to heal and start drinking animation
				EstusFlask[_EF_HEALHP] = healAmount;
				EstusFlask[_EF_HEALHPPERFRAME] = healAmount/ESTUSFLASK_HEAL_TIME;
				EstusFlask[_EF_MAXDRINKTIME] = ESTUSFLASK_DRINK_TIME;
				EstusFlask[_EF_DRINKTIMER] = EstusFlask[_EF_MAXDRINKTIME];
				
				//If flasks can be wasted, decrement the counter here, otherwise do it in the global
				if(ESTUSFLASK_CAN_WASTE){
					Game->Counter[CR_ESTUSFLASK_COUNT]--;
				}
			}
			//If already drunk an estus flask, make drinking a second one immediately after go faster
			else if(ESTUSFLASK_CAN_DOUBLE_DRINK&&EstusFlask[_EF_DRINKTIMER]<=0){
				Game->PlaySound(SFX_ESTUSFLASK_DRINK);
				//Set how much to heal and start drinking animation
				EstusFlask[_EF_HEALHP2] += EstusFlask[_EF_HEALHP];
				EstusFlask[_EF_HEALHP] = healAmount;
				EstusFlask[_EF_HEALHPPERFRAME] = healAmount/ESTUSFLASK_HEAL_TIME;
				EstusFlask[_EF_MAXDRINKTIME] = Floor(ESTUSFLASK_DRINK_TIME/2);
				EstusFlask[_EF_DRINKTIMER] = EstusFlask[_EF_MAXDRINKTIME];
				
				//If flasks can be wasted, decrement the counter here, otherwise do it in the global
				if(ESTUSFLASK_CAN_WASTE){
					Game->Counter[CR_ESTUSFLASK_COUNT]--;
				}
			}
		}
	}
}

//Put this script as the pickup script on items that raise your estus flask capacity
//D0: String to play on pickup
//D1: How much to increase capacity by
item script EstusFlask_CapacityUpgrade{
	void run(int str, int amount){
		if(amount==0)
			amount = 1;
		if(str>0)
			Screen->Message(str);
		EstusFlask[_EF_MAXREFILL] = Min(EstusFlask[_EF_MAXREFILL]+amount, ESTUSFLASK_MAX_CAPACITY);
		Game->Counter[CR_ESTUSFLASK_COUNT] = Min(Game->Counter[CR_ESTUSFLASK_COUNT]+amount, ESTUSFLASK_MAX_CAPACITY);
	}
}

global script EstusFlask_Example{
	void run(){
		EstusFlask_Init();
		while(true){
			EstusFlask_Update();
			Waitdraw();
			Waitframe();
		}
	}
}



ffc script EstusFlask_Bonfire{
	void run(){
		int i;
		while(true){
			bool canUse;
			if(Link->X>=this->X-8&&Link->X<=this->X+8&&Link->Y>=this->Y-16&&Link->Y<=this->Y&&Link->Dir==DIR_DOWN)
				canUse = true;
			if(Link->X>=this->X-8&&Link->X<=this->X+8&&Link->Y>=this->Y&&Link->Y<=this->Y+8&&Link->Dir==DIR_UP)
				canUse = true;
			if(Link->X>=this->X-16&&Link->X<=this->X&&Link->Y>=this->Y-12&&Link->Y<=this->Y+4&&Link->Dir==DIR_RIGHT)
				canUse = true;
			if(Link->X>=this->X&&Link->X<=this->X+16&&Link->Y>=this->Y-12&&Link->Y<=this->Y+4&&Link->Dir==DIR_LEFT)
				canUse = true;
			if(canUse){
				DrawAPrompt();
				if(Link->PressA){
					Link->PressA = false;
					Link->InputA = false;
					NoAction();
					Game->PlaySound(SFX_ESTUSFLASK_REFILL);
					
					if(ESTUSFLASK_BONFIRE_HEALS){
						int healAmount = Link->MaxHP-Link->HP;
						EstusFlask[_EF_HEALHP] = healAmount;
						EstusFlask[_EF_HEALHPPERFRAME] = healAmount/30;
						EstusFlask[_EF_DRINKTIMER] = 0;
					}
					
					if(ESTUSFLASK_BONFIRE_RESETENEMIES){
						EstusFlask[_EF_LASTMAP] = -1;
						for(i=0; i<=255; i++){
							EstusFlask[_EF_RESETMAP+i] = 1;
						}
					}
					
					if(ESTUSFLASK_BONFIRE_SETS_CONTINUE||ESTUSFLASK_BONFIRE_OVERRIDES_CONTINUE){
						EstusFlask[_EF_CONTINUEDMAP] = Game->GetCurDMap();
						EstusFlask[_EF_CONTINUESCREEN]= Game->GetCurDMapScreen();
						
						Game->LastEntranceDMap = Game->GetCurDMap();
						Game->LastEntranceScreen = Game->GetCurDMapScreen();
						Game->ContinueDMap = Game->GetCurDMap();
						Game->ContinueScreen = Game->GetCurDMapScreen();
					}
					
					if(Game->Counter[CR_ESTUSFLASK_COUNT]<EstusFlask[_EF_MAXREFILL]){
						for(i=0; Game->Counter[CR_ESTUSFLASK_COUNT]<EstusFlask[_EF_MAXREFILL]; i++){
							Game->Counter[CR_ESTUSFLASK_COUNT] = Min(Game->Counter[CR_ESTUSFLASK_COUNT]+1, EstusFlask[_EF_MAXREFILL]);
							WaitNoAction(4);
						}
						WaitNoAction(20);
					}
					else{
						WaitNoAction(20);
					}
					while(EstusFlask[_EF_HEALHP]>0){
						WaitNoAction();
					}
				}
			}
			Waitframe();
		}
	}
}