Copy to Clipboard Test

Magnets and Iron Beams puzzle Code

const int CMB_IRON_BEAM_SOLID = 1; //ID of combo used to mimic solidity. It must be fully solid and fully transparent.



const int SFX_IRON_BEAM_MOVE = 50; //Sound to play when moving a block.

const int SFX_IRON_BEAM_STUCK = 16;//Sound to play when block gets stuck.



const int SFX_MAGNET_PICK = 4;//Sound to play,when liftable combo is picked.

const int SFX_MAGNET_PLACE = 16;//Sound to play,when liftable combo is placed.



const int CT_MAGNET_LIFTABLE = 142;//Combo that is defined as liftable magnet

const int CT_MAGNET_SWITCH = 143;//Combo that is defined as static magnet



const int CF_IRON_BEAM_TRAP = 98; //Combo Flag for magnetic floor. If any part of Iron beam slides over this combo, it stops moving and is no longer movable.



//Magnets and Iron Beams puzzle

//You have a couple of differently oriented horseshoe-shaped magnets. A path forward is barricaded by super-heavy iron beams, so heavy, that even Gods cannot push them.

//You can lift and place magnets. if you place a magnet in such a way, that his poles point at iron beam via straight, unobstructed line,

//the beam starts moving torwards magnet, until either hit a solid combo, or touch a magnet itself, which causes both beam and magnet to be completely stuck and immobile.

//

//Set ip 4 consecutive magnet combos: up-down-left-right. You can set up 5th one for 4-way magnet.

//Compile and assign 3 FFC scripts.

//

//IronBeam 

//EffectWidth and EffectHeight used

//D0 - >0 -disable magnet locking 

//D1 - land all iron beams with this argument set to >0 onto flags #66 to trigger secrets 

//

//PickPlaceMagnets

//Place invicible FFC anywhere in the screen.

//D0 - ID of 1st combo in sequence for magnets. 0 to use FFC`s combo

//

//StaticMagnetSwitch Attracts iron beams, when activated either by standing on and pressing EX1, or just stepped on.

//Place invicible FFC anywhere in the screen.

//D0 - ID of 1st combo in sequence for magnets. 0 to use FFC`s combo

//D1 - 0 - Ex1 activated, 1 - step activated. 



ffc script IronBeam{

	void run (int lockmagnet, int secrets){

		this->EffectWidth = this->TileWidth*16;

		this->EffectHeight = this->TileHeight*16;

		int origdata= this->Data;

		int pos = ComboAt (this->X+1, this->Y+1);

		int ucmb[16];

		int ucset[16];

		for (int i=0;i<16;i++){

			ucmb[i] = CMB_IRON_BEAM_SOLID;

			ucset[i] = this->CSet;

		}

		IBeamPushReplaceCombosUnderFFC(this, ucmb, ucset);

		this->InitD[7] = -1;

		int movecounter = 0;

		for (int i=0;i<176;i++){

			if (ComboFI(i, CF_BLOCKTRIGGER))Screen->ComboF[i] = CF_BLOCKTRIGGER;

		}

		while(true){

			if (movecounter==0){

				if (this->InitD[7]>=0){

					if (IBeamCanBePushed(this) && !EnemiesAlive()){

						Game->PlaySound(SFX_IRON_BEAM_MOVE);

						movecounter = 8;

						IBeamPushReplaceCombosUnderFFC(this, ucmb, ucset);

					}

					else this->InitD[7]=-1;;

				}

			}

			else{

				NoAction();

				movecounter--;

				if (this->InitD[7]==DIR_UP) this->Y-=2;

				if (this->InitD[7]==DIR_DOWN) this->Y+=2;

				if (this->InitD[7]==DIR_LEFT) this->X-=2;

				if (this->InitD[7]==DIR_RIGHT) this->X+=2;

				if (movecounter==0){

					if (IBeamCanBePushed(this)){

						if (IBeamLandOnTrap(this)){

							IBeamPushReplaceCombosUnderFFC(this, ucmb, ucset);

							Game->PlaySound(SFX_IRON_BEAM_STUCK);

							Quit();

						}

						else movecounter=8;

					}

					else{

						IBeamPushReplaceCombosUnderFFC(this, ucmb, ucset);

						this->InitD[7]=-1;

						if (secrets>0)IronBeamTriggerUpdate(this);

						if (this->InitD[6]>0){

							Game->PlaySound(SFX_IRON_BEAM_STUCK);

							Quit();

						}

					}

				}

			}

			//debugValue(FFCNum(this), this->InitD[7]);

			Waitframe();

		}

	}

}



ffc script PickPlaceMagnets{

	void run (int origcmb){

	if (origcmb==0)origcmb=this->Data;

		int carrycmb=0;

		int carrycset=0;

		int cmb = ComboAt(CenterLinkX(), CenterLinkY());

		while(true){

			cmb = ComboAt(CenterLinkX(), CenterLinkY());

			if (Link->PressEx1){

				if (carrycmb==0 && !ComboFI(cmb, CF_NOBLOCKS)  &&  Screen->ComboT[cmb]==CT_MAGNET_LIFTABLE){

					Game->PlaySound(SFX_MAGNET_PICK);

					carrycmb=Screen->ComboD[cmb];

					carrycset = Screen->ComboC[cmb];

					Screen->ComboD[cmb]=Screen->UnderCombo;

					Screen->ComboC[cmb]=Screen->UnderCSet;

				}

				else if (!ComboFI(cmb, CF_NOBLOCKS) && Screen->ComboT[cmb]!=CT_MAGNET_LIFTABLE && carrycmb>0){

					Game->PlaySound(SFX_MAGNET_PLACE);

					Screen->ComboD[cmb]=carrycmb;

					Screen->ComboC[cmb]=carrycset;

					carrycmb=0;

					carrycset = 0;

					int dir = Screen->ComboD[cmb] - origcmb;

					if (dir==4){

						for (int i=0;i<4;i++){

							int mx = ComboX(cmb);

							int my = ComboY(cmb);

							while(true){

								if (i==DIR_UP){

									my-=16;

									if (my<0) break;

								}

								if (i==DIR_DOWN){

									my+=16;

									if (my>=176)break;

								}

								if (i==DIR_LEFT){

									mx-=16;

									if (mx<0)break;

								}

								if (i==DIR_RIGHT){

									mx+=16;

									if (mx>=256)break;

								}

								int mcmb = ComboAt(mx,my);

								if (Screen->ComboD[mcmb]==CMB_IRON_BEAM_SOLID){

									int str[] = "IronBeam";

									int scr = Game->GetFFCScript(str);

									for (int j=1;j<=32;j++){

										ffc f = Screen->LoadFFC(j);

										if (f->Script!=scr)continue;

										if (RectCollision(mx+1, my+1, mx+2, my+2, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){

											f->InitD[7]=OppositeDir(i);

											while(f->Script==scr && f->InitD[7]>=0)WaitNoAction();

											break;

										}

									}

									break;

								}

								else if (Screen->ComboS[mcmb]>0)break;

							}

						}

					}

					else{

						int mx = ComboX(cmb);

						int my = ComboY(cmb);

						while(true){

							if (dir<0 || dir>3){

								break;

							}

							if (dir==DIR_UP){

								my-=16;

								if (my<0) break;

							}

							if (dir==DIR_DOWN){

								my+=16;

								if (my>=176)break;

							}

							if (dir==DIR_LEFT){

								mx-=16;

								if (mx<0)break;

							}

							if (dir==DIR_RIGHT){

								mx+=16;

								if (mx>=256)break;

							}

							int mcmb = ComboAt(mx,my);

							if (Screen->ComboD[mcmb]==CMB_IRON_BEAM_SOLID){

								int str[] = "IronBeam";

								int scr = Game->GetFFCScript(str);

								for (int i=1;i<=32;i++){

									ffc f = Screen->LoadFFC(i);

									if (f->Script!=scr)continue;

									if (RectCollision(mx+1, my+1, mx+2, my+2, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){

										f->InitD[7]=OppositeDir(dir);

										break;

									}

								}

								break;

							}

							else if (Screen->ComboS[mcmb]>0)break;

						}

					}

				}

			}

			if (carrycmb>0)Screen->FastCombo(3, Link->X, Link->Y-8, carrycmb, carrycset, OP_OPAQUE);

			Waitframe();

		}

	}

}



//Stores and replaces combos under FFC to mimic solidity.

void IBeamPushReplaceCombosUnderFFC(ffc this, int ucmb, int ucset){

	int x1 = this->X+1;

	int y1 = this->Y+1;

	int x2 = x1+this->EffectWidth-2;

	int y2 = y1+this->EffectHeight-2;

	int arr=0;

	for (int i=0;i<176;i++){

		int cx1 = ComboX(i);

		int cy1 = ComboY(i);

		int cx2 = cx1+15;

		int cy2 = cy1+15;

		if (!RectCollision(x1,y1,x2,y2,cx1,cy1,cx2,cy2))continue;

		int rcmb = Screen->ComboD[i];

		int rcset = Screen->ComboC[i];

		Screen->ComboD[i] = ucmb[arr];

		Screen->ComboC[i] = ucset[arr];

		ucmb[arr] = rcmb;

		ucset[arr]=rcset;

		arr++;

	}

}



bool IBeamLandOnTrap(ffc this){

	int x1 = this->X+1;

	int y1 = this->Y+1;

	int x2 = x1+this->EffectWidth-2;

	int y2 = y1+this->EffectHeight-2;

	for (int i=0;i<176;i++){

		if (!ComboFI(i,CF_IRON_BEAM_TRAP)) continue;

		int cx1 = ComboX(i);

		int cy1 = ComboY(i);

		int cx2 = cx1+15;

		int cy2 = cy1+15;

		if (RectCollision(x1,y1,x2,y2,cx1,cy1,cx2,cy2)) return true;

	}

	return false;

}



//Returns true, if block can be pushed in the given direction

bool IBeamCanBePushed(ffc this){

	int dir = this->InitD[7];

	int x1 = 0;

	int y1 = 0;

	int x2 = 0;

	int y2 = 0;

	int comboS=0;

	if (dir==DIR_UP){

		x1 = this->X+1;

		y1 = this->Y-15;

		x2 = this->X+this->EffectWidth-2;

		y2 = this->Y-1;

	}

	if (dir==DIR_DOWN){

		x1 = this->X+1;

		y1 = this->Y+ this->EffectHeight+1;

		x2 = this->X+this->EffectWidth-2;

		y2 = y1+14;

	}

	if (dir==DIR_LEFT){

		x1 = this->X-14;

		y1 = this->Y+1;

		x2 = this->X-1;

		y2 = y1+this->EffectHeight-3;

	}

	if (dir==DIR_RIGHT){

		x1 = this->X+this->EffectWidth+1;

		y1 = this->Y+1;

		x2 = x1+14;

		y2 = y1+this->EffectHeight-3;

	}

	for (int i=0;i<176;i++){

		int cx1 = ComboX(i);

		int cy1 = ComboY(i);

		int cx2 = cx1+15;

		int cy2 = cy1+15;

		if (!RectCollision(x1,y1,x2,y2,cx1,cy1,cx2,cy2))continue;

		if (ComboFI(i, CF_NOBLOCKS)) comboS=1;

		if (Screen->ComboT[i]==CT_MAGNET_LIFTABLE){

			if (this->InitD[0]==0){

				Screen->ComboF[i]= CF_NOBLOCKS;

				this->InitD[6]=1;

				int str[] = "PickPlaceMagnets";

				int scr = Game->GetFFCScript(str);

					for (int r=1;r<=32;r++){

					ffc p = Screen->LoadFFC(r);

					if (p->Script!=scr)continue;

					int changecmb = p->InitD[0];

					if (changecmb==0)changecmb = p->Data;

					if (Screen->ComboD[i]!=changecmb+4)Screen->ComboD[i]=changecmb+OppositeDir(dir);

				}

			}

			comboS=1;

		}

		if (Screen->ComboT[i]==CT_MAGNET_SWITCH){

			if (this->InitD[0]==0){

				Screen->ComboF[i]= CF_NOBLOCKS;

				this->InitD[6]=1;

				int str[] = "StaticMagnetSwitch";

				int scr = Game->GetFFCScript(str);

					for (int r=1;r<=32;r++){

					ffc p = Screen->LoadFFC(r);

					if (p->Script!=scr)continue;

					int changecmb = p->InitD[0];

					if (changecmb==0)changecmb = p->Data;

					if (Screen->ComboD[i]!=changecmb+4)Screen->ComboD[i]=changecmb+OppositeDir(dir);

				}

			}

			comboS=1;

		}

		if (Screen->ComboS[i]>0)comboS=1;

		if(Screen->LayerMap(1)>0) comboS |= GetLayerComboS(1, i);

		if(Screen->LayerMap(2)>0) comboS |= GetLayerComboS(2, i);

	}

	if(comboS>0)return false;

	return true;

}				



//Checks, if all pushblocks are on triggers and triggers secrets, if it`s true;

void IronBeamTriggerUpdate(ffc f){

	f->InitD[5]=1;

	for (int i=0;i<16;i++){

		int x = f->X+(i%4)*16;

		if (x>(f->X+f->EffectWidth-1)) continue;

		int y = f->Y+Floor(i/4)*16;

		if (y>(f->Y+f->EffectHeight-1)) continue;

		int cmb = ComboAt(x+1,y+1);

		if (!ComboFI(cmb, CF_BLOCKTRIGGER)) f->InitD[5]=0;

	}

	int str[] = "IronBeam";

	int scr = Game->GetFFCScript(str);

	for(int i=1;i<=33;i++){

		if (Screen->State[ST_SECRET]) break;

		if (i==33){

			Game->PlaySound(SFX_SECRET);

			Screen->TriggerSecrets();

			Screen->State[ST_SECRET]=true;

			break;

		}

		ffc n = Screen->LoadFFC(i);

		if (n->Script!=scr)continue;

		if (n->InitD[1]==0)continue;

		if (n->InitD[5] == 0) break;

	}

}



//Static Magnets. Cannot be moved, only activated by stepping on, and, if needed, press Ex1.



ffc script StaticMagnetSwitch{

	void run (int origcmb, int step){

	if (origcmb==0)origcmb=this->Data;

		int cmb = ComboAt(CenterLinkX(), CenterLinkY());

		while(true){

			int cmb = ComboAt(CenterLinkX(), CenterLinkY());

			if (Screen->ComboT[cmb]==CT_MAGNET_SWITCH &&(step>0 || Link->PressEx1)&& !MagnetActive()){

				int dir = Screen->ComboD[cmb] - origcmb;

				if (dir==4){

					for (int i=0;i<4;i++){

						int mx = ComboX(cmb);

						int my = ComboY(cmb);

						while(true){

							if (i==DIR_UP){

								my-=16;

								if (my<0) break;

							}

							if (i==DIR_DOWN){

								my+=16;

								if (my>=176)break;

							}

							if (i==DIR_LEFT){

								mx-=16;

								if (mx<0)break;

							}

							if (i==DIR_RIGHT){

								mx+=16;

								if (mx>=256)break;

							}

							int mcmb = ComboAt(mx,my);

							if (Screen->ComboD[mcmb]==CMB_IRON_BEAM_SOLID){

								int str[] = "IronBeam";

								int scr = Game->GetFFCScript(str);

								for (int j=1;j<=32;j++){

									ffc f = Screen->LoadFFC(j);

									if (f->Script!=scr)continue;

									if (RectCollision(mx+1, my+1, mx+2, my+2, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){

										f->InitD[7]=OppositeDir(i);

										while(f->Script==scr && f->InitD[7]>=0)WaitNoAction();

										break;

									}

								}

								break;

							}

							else if (Screen->ComboS[mcmb]>0)break;

						}

					}

				}

				else{

					int mx = ComboX(cmb);

					int my = ComboY(cmb);

					while(true){

						if (dir<0 || dir>3){

							break;

						}

						if (dir==DIR_UP){

							my-=16;

							if (my<0) break;

						}

						if (dir==DIR_DOWN){

							my+=16;

							if (my>=176)break;

						}

						if (dir==DIR_LEFT){

							mx-=16;

							if (mx<0)break;

						}

						if (dir==DIR_RIGHT){

							mx+=16;

							if (mx>=256)break;

						}

						int mcmb = ComboAt(mx,my);

						if (Screen->ComboD[mcmb]==CMB_IRON_BEAM_SOLID){

							int str[] = "IronBeam";

							int scr = Game->GetFFCScript(str);

							for (int i=1;i<=32;i++){

								ffc f = Screen->LoadFFC(i);

								if (f->Script!=scr)continue;

								if (RectCollision(mx+1, my+1, mx+2, my+2, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){

									f->InitD[7]=OppositeDir(dir);

									break;

								}

							}

							break;

						}

						else if (Screen->ComboS[mcmb]>0)break;

					}

				}

			}

			Waitframe();

		}

	}

}



bool MagnetActive(){

	int str[] = "IronBeam";

	int scr = Game->GetFFCScript(str);

	for (int i=1;i<=32;i++){

		ffc f = Screen->LoadFFC(i);

		if (f->Script!=scr)continue;

		if (f->InitD[7]>=0) return true;

	}

	return false;

}



//Remote controlled Magnet. Attracts iron beams, when activated by Switch FFC script.

//Requires MagnetDrag.z and Switch.z

//Set ip 4 consecutive magnet combos: up-down-left-right. You can set up 5th one for 4-way magnet.

//Place invicible FFC at magnet position.

//D0 - ID of 1st combo in sequence for magnets. 0 to use FFC`s combo

//D1 - ID of FFC with Switch script.  



ffc script RemoteMagnetSwitch{

	void run (int origcmb, int ffcid){

	if (origcmb==0)origcmb=this->Data;

		int cmb = ComboAt(CenterX(this), CenterY(this));

		while(true){

			ffc n = Screen->LoadFFC(ffcid);

			if (SwitchState(n, this) && !MagnetActive()){

				int dir = Screen->ComboD[cmb] - origcmb;

				if (dir==4){

					for (int i=0;i<4;i++){

						int mx = ComboX(cmb);

						int my = ComboY(cmb);

						while(true){

							if (i==DIR_UP){

								my-=16;

								if (my<0) break;

							}

							if (i==DIR_DOWN){

								my+=16;

								if (my>=176)break;

							}

							if (i==DIR_LEFT){

								mx-=16;

								if (mx<0)break;

							}

							if (i==DIR_RIGHT){

								mx+=16;

								if (mx>=256)break;

							}

							int mcmb = ComboAt(mx,my);

							if (Screen->ComboD[mcmb]==CMB_IRON_BEAM_SOLID){

								int str[] = "IronBeam";

								int scr = Game->GetFFCScript(str);

								for (int j=1;j<=32;j++){

									ffc f = Screen->LoadFFC(j);

									if (f->Script!=scr)continue;

									if (RectCollision(mx+1, my+1, mx+2, my+2, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){

										f->InitD[7]=OppositeDir(i);

										while(f->Script==scr && f->InitD[7]>=0)WaitNoAction();

										break;

									}

								}

								break;

							}

							else if (Screen->ComboS[mcmb]>0)break;

						}

					}

				}

				else{

					int mx = ComboX(cmb);

					int my = ComboY(cmb);

					while(true){

						if (dir<0 || dir>3){

							break;

						}

						if (dir==DIR_UP){

							my-=16;

							if (my<0) break;

						}

						if (dir==DIR_DOWN){

							my+=16;

							if (my>=176)break;

						}

						if (dir==DIR_LEFT){

							mx-=16;

							if (mx<0)break;

						}

						if (dir==DIR_RIGHT){

							mx+=16;

							if (mx>=256)break;

						}

						int mcmb = ComboAt(mx,my);

						if (Screen->ComboD[mcmb]==CMB_IRON_BEAM_SOLID){

							int str[] = "IronBeam";

							int scr = Game->GetFFCScript(str);

							for (int i=1;i<=32;i++){

								ffc f = Screen->LoadFFC(i);

								if (f->Script!=scr)continue;

								if (RectCollision(mx+1, my+1, mx+2, my+2, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){

									f->InitD[7]=OppositeDir(dir);

									break;

								}

							}

							break;

						}

						else if (Screen->ComboS[mcmb]>0)break;

					}

				}

			}

			Waitframe();

		}

	}

}