Copy to Clipboard Test

Link`s Awakening Freeform Lights Out puzzle. Code

const int CSET_FF_LIGHTSOUT_ON = 8; //CSet to render light FFC in ON state
const int CSET_FF_LIGHTSOUT_OFF = 7;//CSet to render light FFC in OFF state

const int CMB_FF_LIGHTSOUT_SOLID = 891;//Solid Combo to place under FFC 

const int SFX_FF_LIGHTSOUT_HIT = 16;//Sound to play on activating FFC

const int SCREEN_D_FF_LIGHTSOUT_COOLDOWN = 0;//Screen D to track cooldown between activationd.

const int FF_LIGHTSOUT_AUTOMATIC_ADJACENT_FFC_SETUP = 1;//>0 - Automatic adjacent FFC setup: each FFC is linked to nearest in all 4 cardinal directions, unless path to it is obsctructed by flag #67, or solid combo.

const int FF_LIGHTSOUT_COOLDOWN_TIME = 15; //Delay between registering sword hits, in frames.

//FreeForm Lights Out

//Works just like the oft-cloned puzzle game. Triggering one item triggers the adjacent as well.
//1.Set up 2 consecutive combos, Off then ON state.
//2.Place FFCS for each light with combo as OFF state of light. Must be one combo apart or more.
// D0: initial state (1 = on, 0 = off, -1 = random)
// D1-4: adjacent ffc ids (0 to ignore)
// D5: Target light state for puzzle solution.

ffc script FFCLightsOut {
	void run (int state, int adj1, int adj2, int adj3, int adj4, int solved_state) {
		ffc a1; 
		ffc a2; 
		ffc a3; 
		ffc a4;
		this->InitD[6]=ComboAt(CenterX(this), CenterY(this));
		Waitframe();
		if (FF_LIGHTSOUT_AUTOMATIC_ADJACENT_FFC_SETUP>0){
			Waitframe();
			int cmb=this->InitD[6];
			int adjcmb = this->InitD[6];
			while(adjcmb>0){
				adjcmb = FFLightsOutAdjacentComboFix(adjcmb, DIR_UP);
				if (adjcmb<0){
					adj1=0;
					break;
				}
				if (ComboFI(adjcmb, CF_NOBLOCKS) || Screen->ComboS[adjcmb]>0){
					adj1=0;
					break;
				}
				for (int i=1;i<=32;i++){
					ffc f = Screen->LoadFFC(i);
					if (f==this)continue;
					if (f->Script!=this->Script) continue;
					if (f->InitD[6]!=adjcmb)continue;
					a1 = f;
					adj1 = i;
					//Trace(i);
					break;
				}
				if (adj1>0)break;
			}
			adjcmb = this->InitD[6];
			while(adjcmb>0){
				adjcmb = FFLightsOutAdjacentComboFix(adjcmb, DIR_DOWN);
				if (adjcmb<0){
					adj2=0;
					break;
				}
				if (ComboFI(adjcmb, CF_NOBLOCKS) || Screen->ComboS[adjcmb]>0){
					adj2=0;
					break;
				}
				for (int i=1;i<=32;i++){
					ffc f = Screen->LoadFFC(i);
					if (f==this)continue;
					if (f->Script!=this->Script) continue;
					if (f->InitD[6]!=adjcmb)continue;
					a2 = f;
					adj2= i;
					//Trace(i);
					break;
				}
				if (adj2>0)break;
			}
			adjcmb = this->InitD[6];
			while(adjcmb>0){
				adjcmb = FFLightsOutAdjacentComboFix(adjcmb, DIR_LEFT);
				if (adjcmb<0){
					adj3=0;
					break;
				}
				if (ComboFI(adjcmb, CF_NOBLOCKS) || Screen->ComboS[adjcmb]>0){
					adj3=0;
					break;
				}
				for (int i=1;i<=32;i++){
					ffc f = Screen->LoadFFC(i);
					if (f==this)continue;
					if (f->Script!=this->Script) continue;
					if (f->InitD[6]!=adjcmb)continue;
					a3 = f;
					adj3 = i;
					//Trace(i);
					break;
				}
				if (adj3>0)break;
			}
			adjcmb = this->InitD[6];
			while(adjcmb>0){
				adjcmb = FFLightsOutAdjacentComboFix(adjcmb, DIR_RIGHT);
				if (adjcmb<0){
					adj4=0;
					break;
				}
				if (ComboFI(adjcmb, CF_NOBLOCKS) || Screen->ComboS[adjcmb]>0){
					adj4=0;
					break;
				}
				for (int i=1;i<=32;i++){
					ffc f = Screen->LoadFFC(i);
					if (f==this)continue;
					if (f->Script!=this->Script) continue;
					if (f->InitD[6]!=adjcmb)continue;
					a4 = f;
					adj4 = i;
					//Trace(i);
				}
				if (adj4>0)break;
			}
			//TraceNL();
		}		
		else{
			if(adj1 > 0) a1 = Screen->LoadFFC(adj1);
			if(adj2 > 0) a2 = Screen->LoadFFC(adj2);
			if(adj3 > 0) a3 = Screen->LoadFFC(adj3);
			if(adj4 > 0) a4 = Screen->LoadFFC(adj4);
		}		
		int origdata = this->Data;
		Waitframe();
		int c = this->InitD[6];
		if (CMB_FF_LIGHTSOUT_SOLID>0)Screen->ComboD[c]=CMB_FF_LIGHTSOUT_SOLID;
		if (state<0) state = Rand(2);
		this->InitD[6]=0;
		this->InitD[7]=state;
		bool cooldown=false;		
		if (Screen->State[ST_SECRET]) {
			this->InitD[7] = solved_state;
			if (this->InitD[7]==1){
				this->Data=origdata+1;
				this->CSet = CSET_FF_LIGHTSOUT_ON;
			}
			else{
				this->Data = origdata;
				this->CSet = CSET_FF_LIGHTSOUT_OFF;
			}
			Quit();
		}		
		while (true) {			
			if (Screen->D[SCREEN_D_FF_LIGHTSOUT_COOLDOWN] == 0) {
				for (int i=1; i<=Screen->NumLWeapons(); i++) {
					lweapon wpn = Screen->LoadLWeapon(i);
					if (wpn->ID == LW_SWORD) {
						if ( Distance(wpn->X, wpn->Y, this->X, this->Y) < 12 ) {
							Game->PlaySound(SFX_FF_LIGHTSOUT_HIT);
							this->InitD[6] = 1;
							if(adj1 > 0) a1->InitD[6] = 1;
							if(adj2 > 0) a2->InitD[6] = 1;
							if(adj3 > 0) a3->InitD[6] = 1;
							if(adj4 > 0) a4->InitD[6] = 1;
							Screen->D[SCREEN_D_FF_LIGHTSOUT_COOLDOWN] = FF_LIGHTSOUT_COOLDOWN_TIME;
							cooldown=true;
						}
					}
				}
			}
			else{
				if (cooldown) Screen->D[SCREEN_D_FF_LIGHTSOUT_COOLDOWN]--;
				if (Screen->D[SCREEN_D_FF_LIGHTSOUT_COOLDOWN]==0){
					FFLightsoutTriggerUpdate(this);
					cooldown=false;
				}
			}
			if (this->InitD[6] == 1) {
				this->InitD[6] = 0;
				if (this->InitD[7]==0)	this->InitD[7]=1;
				else this->InitD[7] = 0;				
			}
			
			if (this->InitD[7]==1){
				this->Data=origdata+1;
				this->CSet = CSET_FF_LIGHTSOUT_ON;
			}
			else{
				this->Data = origdata;
				this->CSet = CSET_FF_LIGHTSOUT_OFF;
			}
			Waitframe();
			
		}
	}
	
	//Checks triggers and trigger secrets if all color cubes moved onto correct positions with correct facing
	void FFLightsoutTriggerUpdate(ffc this){
		for (int i=1;i<=33;i++){
			if (i==33){
				Game->PlaySound(SFX_SECRET);
				Screen->TriggerSecrets();
				Screen->State[ST_SECRET] =true;
				Quit();
			}
			else {
				ffc f = Screen->LoadFFC(i);
				if (f->Script!=this->Script) continue;
				if (f->InitD[7]!=f->InitD[5])break;
			}
		}
	}
	
	//Fixed variant of AdjacentCombo function from std_extension.zh
	int FFLightsOutAdjacentComboFix(int cmb, int dir)
	{
		int combooffsets[13]={-0x10, 0x10, -1, 1, -0x11, -0x0F, 0x0F, 0x11};
		if ( cmb % 16 == 0 ) combooffsets[9] = -1;//if it's the left edge
		if ( (cmb % 16) == 15 ) combooffsets[10] = -1; //if it's the right edge
		if ( cmb < 0x10 ) combooffsets[11] = -1; //if it's the top row
		if ( cmb > 0x9F ) combooffsets[12] = -1; //if it's on the bottom row
		if ( combooffsets[9]==-1 && ( dir == DIR_LEFT || dir == DIR_LEFTUP || dir == DIR_LEFTDOWN ) ) return -1; //if the left columb
		if ( combooffsets[10]==-1 && ( dir == DIR_RIGHT || dir == DIR_RIGHTUP || dir == DIR_RIGHTDOWN ) ) return -1; //if the right column
		if ( combooffsets[11]==-1 && ( dir == DIR_UP || dir == DIR_RIGHTUP || dir == DIR_LEFTUP ) ) return -1; //if the top row
		if ( combooffsets[12]==-1 && ( dir == DIR_DOWN || dir == DIR_RIGHTDOWN || dir == DIR_LEFTDOWN ) ) return -1; //if the bottom row
		if ( cmb >= 0 && cmb < 176 ) return cmb + combooffsets[dir];
		else return -1;
	}
}