const int SCREEN_D_DYNAMIC_LOCKBLOCK = 0; //Screen D to track lockblocks ststes
const int SFX_DYNAMIC_LOCKBLOCK_ERROR = 16; //Sound to play on failure to unlock lockblock.
const int SFX_DYNAMIC_LOCKBLOCK_UNLOCK = 9; //Sound to play on unlocking lockblock.
const int SFX_DYNAMIC_LOCKBLOCK_LOCK = 9;// Sound to play on locking locblock and retrieving items.
const int DYNAMIC_LOCKBLOCK_SENSIVITY = 12;//Lockblock pushing sensivity.
//1. Set up items that add to counters in Item Editor.
//2. Set up 2 sequential combos. 1 for locked state, 1 for unlocked one. Set their type to None and solidity to full-solid.
//3. Set SCREEN_D_DYNAMIC_LOCKBLOCK constant to avoid conflicts with other scripts.
//4. Import and compile the script. Nothing beyond default libraries is needed. Assign 2 FFC script slots.
//5. Place 1 invisible FFC for each dynamic lockblock onto combo in the screen from step 1, assign MultiitemDynamicLock script.
// - D0 to D5: item requirements and counter costs as following:
// if D>=0 - #####.____ - Counter to check.
// _____.#### - Counter cost.
// if D<0 - Abs(D) - ID of item required.
// All of those conditions must be met simultaneously to unlock lockblock.
// D6 - #####.____ - Screen D bit used to track lockblock state. Must be unique for each lockblock in the screen.
// _____.#### - Allowed unlock directions.
// D7 - Abs->String to display when cannot afford unlocking.
// If D7 id set to <0, items will get stuck in lockbock, rendering it stay unlocked permanently.
//6. Place 1 invisible FFC with LockBlockTrigger script.
// D0 - Number of dynamic lockblocks need to be unlocked to trigger.
// D1 - Screen State to track. Only use 8-LockBlock, 9-BossLockBlock, 10-TreasureChest, 11-LockedChest and 12-BossLockedChest screen states.
// D2 - Quake power to trigger when unlocked. if set to <0, also stops music.
ffc script MultiitemDynamicLock{
void run(int item1, int item2, int item3, int item4, int item5, int item6, int dirsd, int msg){
int dbit = GetHighFloat(dirsd);
int dirs = GetLowFloat(dirsd);
if (dirs==0)dirs=15;
int itemreq[6] = {item1,item2,item3,item4,item5,item6};
bool unlocked = GetScreenDBit(SCREEN_D_DYNAMIC_LOCKBLOCK, dbit);
int cmb = ComboAt(CenterX(this), CenterY(this));
int origdata = this->Data;
int sens = 0;
if (unlocked){
this->Data++;
Screen->ComboD[cmb]++;
}
if (msg<0){
if (unlocked) Quit();
}
while(true){
if (PressedOn(this, Link->Dir, dirs,6)){
sens++;
if (sens>=DYNAMIC_LOCKBLOCK_SENSIVITY){
if (!unlocked){
if (HasEnoughItems(itemreq)){
Game->PlaySound(SFX_DYNAMIC_LOCKBLOCK_UNLOCK);
SubtractItemCost(itemreq);
SetScreenDBit(SCREEN_D_DYNAMIC_LOCKBLOCK, dbit, true);
unlocked=true;
this->Data++;
Screen->ComboD[cmb]++;
if (msg<0) Quit();
}
else {
Game->PlaySound(SFX_DYNAMIC_LOCKBLOCK_ERROR);
Screen->Message(Abs(msg));
}
}
else{
Game->PlaySound(SFX_DYNAMIC_LOCKBLOCK_LOCK);
RetreiveItemCost(itemreq);
SetScreenDBit(SCREEN_D_DYNAMIC_LOCKBLOCK, dbit, false);
unlocked=false;
this->Data--;
Screen->ComboD[cmb]--;
}
sens=0;
}
}
else sens=0;
Waitframe();
}
}
}
ffc script LockBlockTrigger{
void run (int numlocks, int state, int quake){
int cmb_normal = 0;
int cmb_copycat = 0;
if (state == ST_LOCKBLOCK){
cmb_normal = 59;
cmb_copycat = 60;
}
else if (state == ST_BOSSLOCKBLOCK){
cmb_normal = 61;
cmb_copycat = 62;
}
else if (state == ST_CHEST){
cmb_normal = 65;
cmb_copycat = 66;
}
else if (state == ST_LOCKEDCHEST){
cmb_normal = 67;
cmb_copycat = 68;
}
else if (state == ST_BOSSCHEST){
cmb_normal = 69;
cmb_copycat = 70;
}
int ret = 0;
while(true){
ret=0;
for (int i=1; i<=17; i++){
if(GetScreenDBit(SCREEN_D_DYNAMIC_LOCKBLOCK, i)) ret++;
}
if (ret>=numlocks){
if (!Screen->State[state]){
Screen->State[state] = true;
for (int i=0; i<176; i++){
if (Screen->ComboT[i] == cmb_normal) Screen->ComboD[i]++;
if (Screen->ComboT[i] == cmb_copycat) Screen->ComboD[i]++;
}
Screen->Quake= Abs(quake);
if (quake<0) Game->PlayMIDI(0);
}
}
else {
if (Screen->State[state]){
Screen->State[state] = false;
for (int i=0; i<176; i++){
Screen->ComboD[i]--;
if ((Screen->ComboT[i] != cmb_normal)&&(Screen->ComboT[i] != cmb_copycat )) {Screen->ComboD[i]++;}
}
}
}
// debugValue(1, ret);
Waitframe();
}
}
}
bool PressedOn(ffc this, int dir,int dirs, int margin){
if (dir==DIR_UP){
if ((dirs&1)==0) return false;
}
if (dir==DIR_DOWN){
if ((dirs&2)==0) return false;
}
if (dir==DIR_LEFT){
if ((dirs&4)==0) return false;
}
if (dir==DIR_RIGHT){
if ((dirs&8)==0) return false;
}
if((Link->X == this->X - 16 && (CenterLinkY() < this->Y+this->EffectHeight - 8+margin && CenterLinkY() > this->Y - margin) && Link->InputRight && dir == DIR_RIGHT) || // Right
(Link->X == this->X + this->EffectWidth && (CenterLinkY() < this->Y+this->EffectHeight - 8+margin && CenterLinkY() > this->Y - margin) && Link->InputLeft && dir == DIR_LEFT) || // Left
(Link->Y == this->Y - 16 && (Link->X < (this->X + this->EffectWidth-16+margin) && Link->X > this->X - margin) && Link->InputDown && dir == DIR_DOWN) || // Down
(Link->Y == this->Y + this->EffectHeight-8 && (Link->X < (this->X + this->EffectWidth-16+margin) && Link->X > this->X - margin) && Link->InputUp && dir == DIR_UP)) { // Up
return true;
}
return false;
}
bool HasEnoughItems(int arritem){
for (int i=0; i<SizeOfArray(arritem);i++){
if (arritem[i]>0){
int counter = GetHighFloat(arritem[i]);
int cost = GetLowFloat(arritem[i]);
if (Game->Counter[counter]<cost) return false;
else continue;
}
if (arritem[i]<0){
int req = arritem[i]*-1;
if (!Link->Item[req]) return false;
else continue;
}
}
return true;
}
void SubtractItemCost(int arritem){
for (int i=0; i<SizeOfArray(arritem);i++){
if (arritem[i]>0){
int counter = GetHighFloat(arritem[i]);
int cost = GetLowFloat(arritem[i]);
Game->Counter[counter] -=cost;
}
if (arritem[i]<0){
int req = arritem[i]*-1;
Link->Item[req] = false;
}
}
}
void RetreiveItemCost(int arritem){
for (int i=0; i<SizeOfArray(arritem);i++){
if (arritem[i]>0){
int counter = GetHighFloat(arritem[i]);
int cost = GetLowFloat(arritem[i]);
Game->Counter[counter] +=cost;
}
if (arritem[i]<0){
int req = arritem[i]*-1;
Link->Item[req] = true;
}
}
}