Copy to Clipboard Test

Crystal Switch and Colored (Red/Blue) Barriers Code

const int CRYSTALSWITCH_CAN_WALK_ON_TOP = 1; //If 1, Link can walk on top of raised crystal switches when they raise while under him
const int CRYSTALSWITCH_RESET_ON_F6 = 1; //If 1, switch states will reset to their defaults when F6 is pressed. Else they'll only be set when the save file is first loaded.
const int CRYSTALSWITCH_USE_BLANK_TRIGGER = 1; //If 1, the switch uses color neutral tiles when there's more than two possible color states
const int CRYSTALSWITCH_USE_FFC_GRAPHICS = 0; //If 1, the switch graphics are set to the FFC instead of the combo beneath it
const int CRYSTALSWITCH_RAISELINK = 5; //If >1 Link will be pushed up that many pixels with the block

const int CRYSTALSWITCH_NUM_COLORS = 8; //How many colors of switches are enabled
const int CRYSTALSWITCH_RISINGCOMBOS = 4; //How many combos are used in the switch rising animation
const int CRYSTALSWITCH_RISINGASPEED = 4; //A.Speed for the rising animation

const int CMB_CRYSTALSWITCH_BLOCKS = 1024; //SET TO: The first of the combos for your first set of raising/lowering blocks
const int CMB_CRYSTALSWITCH_TRIGGERS = 1088; //SET TO: The first of the combos for crystal switch triggers
const int CMB_CRYSTALSWITCH_STATICBLOCKS = 1112; //SET TO: The first of the combos for static (gray) blocks that you can walk over from 

const int CRYSTALSWITCH_OFFSET = 0; //How spaced apart switch combos are in the combo table. If 0, this is calculated automatically.

const int SFX_CRYSTALSWITCH_TRIGGER = 6; //Sound when the Crystal Switch is hit

//Array indices. Don't change.
const int CRSW_FIRSTLOAD = 0;
const int CRSW_ANIM = 1;
const int CRSW_LINKONRAISED = 2;
const int CRSW_LASTDMAP = 3;
const int CRSW_LASTSCREEN = 4;
const int CRSW_JUMPOFF = 5;
const int CRSW_STATICBLOCKANIM = 6;
const int CRSW_LSTATES = 10;
const int CRSW_SCRNDAT = 522;
int CrystalSwitch[698];

void CrystalSwitch_Init(){
	CrystalSwitch[CRSW_ANIM] = 0;
	CrystalSwitch[CRSW_LINKONRAISED] = 0;
	CrystalSwitch[CRSW_JUMPOFF] = 0;
	CrystalSwitch[CRSW_STATICBLOCKANIM] = 0;
	
	int ss[512];
	for(int i=0; i<512; i++)ss[i] = 10101010b; //Crystal switches default to every other color being raised
	
	//%FINDME CrystalSwitch Init States
	//Define special starting states for the levels in your quest here.
	//True = Raised. False = Lowered.
	//                 ss, Level, Color1, Color2, Color3, Color4, Color5, Color6, Color7, Color8
	//CS_StartingState(ss, 1,     true,   false,  true,   true,   false,  true,   true,   true);
	
	//Set switch array for the first time the quest is loaded
	if(CrystalSwitch[CRSW_FIRSTLOAD]==0 || CRYSTALSWITCH_RESET_ON_F6){
		for(int i=0; i<512; i++){
			CrystalSwitch[CRSW_LSTATES+i] = ss[i];
		}
		CrystalSwitch[CRSW_FIRSTLOAD] = 1;
	}
}

void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up, bool s3up, bool s4up, bool s5up, bool s6up, bool s7up, bool s8up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
	if(s3up)
		startingStates[levelNum] |= 1<<2;
	if(s4up)
		startingStates[levelNum] |= 1<<3;
	if(s5up)
		startingStates[levelNum] |= 1<<4;
	if(s6up)
		startingStates[levelNum] |= 1<<5;
	if(s7up)
		startingStates[levelNum] |= 1<<6;
	if(s8up)
		startingStates[levelNum] |= 1<<7;
}
void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up, bool s3up, bool s4up, bool s5up, bool s6up, bool s7up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
	if(s3up)
		startingStates[levelNum] |= 1<<2;
	if(s4up)
		startingStates[levelNum] |= 1<<3;
	if(s5up)
		startingStates[levelNum] |= 1<<4;
	if(s6up)
		startingStates[levelNum] |= 1<<5;
	if(s7up)
		startingStates[levelNum] |= 1<<6;
}
void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up, bool s3up, bool s4up, bool s5up, bool s6up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
	if(s3up)
		startingStates[levelNum] |= 1<<2;
	if(s4up)
		startingStates[levelNum] |= 1<<3;
	if(s5up)
		startingStates[levelNum] |= 1<<4;
	if(s6up)
		startingStates[levelNum] |= 1<<5;
}
void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up, bool s3up, bool s4up, bool s5up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
	if(s3up)
		startingStates[levelNum] |= 1<<2;
	if(s4up)
		startingStates[levelNum] |= 1<<3;
	if(s5up)
		startingStates[levelNum] |= 1<<4;
}
void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up, bool s3up, bool s4up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
	if(s3up)
		startingStates[levelNum] |= 1<<2;
	if(s4up)
		startingStates[levelNum] |= 1<<3;
}
void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up, bool s3up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
	if(s3up)
		startingStates[levelNum] |= 1<<2;
}
void CS_StartingState(int startingStates, int levelNum, bool s1up, bool s2up){
	startingStates[levelNum] = 0;
	
	if(s1up)
		startingStates[levelNum] |= 1;
	if(s2up)
		startingStates[levelNum] |= 1<<1;
}

void CrystalSwitch_Update(){
	int i; int j; int k;
	if(Link->Action==LA_SCROLLING){
		//Wipe static block data when scrolling
		for(int i=0; i<176; i++){
			CrystalSwitch[CRSW_SCRNDAT+i] = 0;
		}
	}
	int swCMBOffset;
	if(CRYSTALSWITCH_OFFSET)
		swCMBOffset = CRYSTALSWITCH_OFFSET;
	else
		swCMBOffset = Ceiling((2+CRYSTALSWITCH_RISINGCOMBOS)*0.25)*4;
	int lv = Game->GetCurLevel();
	//TraceBint(6, 0, 0, CrystalSwitch[CRSW_LSTATES+lv]);
	int linkColl = CrystalSwitch_OnRaised(true);
	for(i=0; i<176; i++){
		int cd = Screen->ComboD[i];
		for(j=0; j<CRYSTALSWITCH_NUM_COLORS; j++){
			//Check if each combo is one of the switch combos
			if(cd>=CMB_CRYSTALSWITCH_BLOCKS+swCMBOffset*j&&cd<CMB_CRYSTALSWITCH_BLOCKS+swCMBOffset*j+2+CRYSTALSWITCH_RISINGCOMBOS){
				//Up/Down state of blocks
				int swst = ((CrystalSwitch[CRSW_LSTATES+lv]&(1<<j)))>>j;
				bool animating;
				//Whether blocks are animating
				if(CrystalSwitch[CRSW_ANIM]>0&&CrystalSwitch[CRSW_LSTATES+lv]&(1<<(j+8)))
					animating = true;
				
				//Place the combo based on raising/lowering animation
				if(animating){
					int aframe = Clamp(Floor(CrystalSwitch[CRSW_ANIM]/CRYSTALSWITCH_RISINGASPEED), 0, CRYSTALSWITCH_RISINGCOMBOS-1);
					if(swst){
						aframe = CRYSTALSWITCH_RISINGCOMBOS-1-aframe;
					}
					Screen->ComboD[i] = CMB_CRYSTALSWITCH_BLOCKS+j*swCMBOffset+1+aframe;
				}
				else{
					//Place the raised combo
					if(swst){
						Screen->ComboD[i] = CMB_CRYSTALSWITCH_BLOCKS+j*swCMBOffset+1+CRYSTALSWITCH_RISINGCOMBOS;
					}
					//Place the lowered combo
					else{
						Screen->ComboD[i] = CMB_CRYSTALSWITCH_BLOCKS+j*swCMBOffset;
					}
				}
				
				//If Link can walk on combos, alter the solidity based on that
				if(CRYSTALSWITCH_CAN_WALK_ON_TOP){
					if((!swst&&!animating)||CrystalSwitch[CRSW_LINKONRAISED])
						Screen->ComboS[i] = 0000b;
					else
						Screen->ComboS[i] = 1111b;
				}
			}
		}
		if(cd>=CMB_CRYSTALSWITCH_STATICBLOCKS&&cd<CMB_CRYSTALSWITCH_STATICBLOCKS+2+CRYSTALSWITCH_RISINGCOMBOS){
			int cd2 = cd-CMB_CRYSTALSWITCH_STATICBLOCKS;
			k = (CrystalSwitch[CRSW_SCRNDAT+i]&(0xFF<<8))>>8; //Left 8 bits: Timer. 
			
			if(CRYSTALSWITCH_CAN_WALK_ON_TOP){
				if(linkColl&(1<<9))
					CrystalSwitch[CRSW_LINKONRAISED] = 1;
			}
			
			if(k>0){
				k--;
				if(k==0){
					//Moving Down
					if(CrystalSwitch[CRSW_SCRNDAT+i]&1){
						Screen->ComboD[i] = Clamp(Screen->ComboD[i]-1, CMB_CRYSTALSWITCH_STATICBLOCKS, CMB_CRYSTALSWITCH_STATICBLOCKS+2+CRYSTALSWITCH_RISINGCOMBOS-1);
						if(Screen->ComboD[i]==CMB_CRYSTALSWITCH_STATICBLOCKS){
							k = -1; //Done animating
						}
					}
					//Moving Up
					else{
						Screen->ComboD[i] = Clamp(Screen->ComboD[i]+1, CMB_CRYSTALSWITCH_STATICBLOCKS, CMB_CRYSTALSWITCH_STATICBLOCKS+2+CRYSTALSWITCH_RISINGCOMBOS-1);
						if(Screen->ComboD[i]==CMB_CRYSTALSWITCH_STATICBLOCKS+2+CRYSTALSWITCH_RISINGCOMBOS-1){
							k = -1; //Done animating
						}
					}
					
					if(k==-1){
						k = 0;
					}
					else{
						k = CRYSTALSWITCH_RISINGASPEED;
					}
				}
				CrystalSwitch[CRSW_SCRNDAT+i] &= 0xFF;
				CrystalSwitch[CRSW_SCRNDAT+i] |= k<<8;
			}
			else{
				if(cd2==0){
					CrystalSwitch[CRSW_SCRNDAT+i] &= ~1;
				}
				else if(cd2==2+CRYSTALSWITCH_RISINGCOMBOS-1){
					CrystalSwitch[CRSW_SCRNDAT+i] |= 1;
				}
				else{
					//Moving Down
					if(CrystalSwitch[CRSW_SCRNDAT+i]&1){
						CrystalSwitch[CRSW_SCRNDAT+i] = 1;
						CrystalSwitch[CRSW_SCRNDAT+i] |= CRYSTALSWITCH_RISINGASPEED<<8;
					}
					//Moving Up
					else{
						CrystalSwitch[CRSW_SCRNDAT+i] = 0;
						CrystalSwitch[CRSW_SCRNDAT+i] |= CRYSTALSWITCH_RISINGASPEED<<8;
					}
				}
			}
			
			//If Link can walk on combos, alter the solidity based on that
			if(CRYSTALSWITCH_CAN_WALK_ON_TOP){
				if(linkColl&(1<<9))
					CrystalSwitch[CRSW_LINKONRAISED] = 1;
				if(cd2==0||CrystalSwitch[CRSW_LINKONRAISED])
					Screen->ComboS[i] = 0000b;
				else
					Screen->ComboS[i] = 1111b;
			}
		}
	}
	
	if(CRYSTALSWITCH_CAN_WALK_ON_TOP){
		if(Link->Action!=LA_SCROLLING&&!IsSideview()){
			//When entering a screen on a raised block
			if(Game->GetCurDMap()!=CrystalSwitch[CRSW_LASTDMAP]||Game->GetCurDMapScreen()!=CrystalSwitch[CRSW_LASTSCREEN]){
				if(CrystalSwitch_OnRaised(true)){
					CrystalSwitch[CRSW_LINKONRAISED] = 1;
				}
				CrystalSwitch[CRSW_LASTDMAP] = Game->GetCurDMap();
				CrystalSwitch[CRSW_LASTSCREEN] = Game->GetCurDMapScreen();
			}
			//Else detect Link stepping off a block
			else if(CrystalSwitch[CRSW_LINKONRAISED]){
				if(Link->Z==0&&Link->Action!=LA_FROZEN&&!CrystalSwitch_OnRaised(true)){
					Game->PlaySound(SFX_JUMP);
					Link->Jump = 1;
					Link->Z = 4;
					CrystalSwitch[CRSW_JUMPOFF] = 1;
					CrystalSwitch[CRSW_LINKONRAISED] = 0;
				}
				//If he's not stepping off but the block is animating, move him with it
				else if(CRYSTALSWITCH_RAISELINK){
					if(CrystalSwitch[CRSW_ANIM]>0&&!IsSideview()){
						linkColl = CrystalSwitch_OnRaised(false);
						int movement = -1;
						//Find the sum of movement up/down of the blocks Link is standing on
						for(j=0; j<CRYSTALSWITCH_NUM_COLORS; j++){
							//Check if Link is touching the block
							if(linkColl&(1<<j)){
								//Raised block
								if(CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()]&(1<<j)){
									//Is it currently animating?
									if(CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()]&(1<<(j+8))){
										if(movement==-1)
											movement = 2;
										//Cancel out conflicting movements
										else if(movement==1)
											movement = 0;
									}
									//Link is on an unmoving raised block and cannot be affected by others
									else{
										movement = 0;
									}
								}
								//Lowered block
								else{
									//Is it currently animating?
									if(CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()]&(1<<(j+8))){
										if(movement==-1)
											movement = 1;
										//Cancel out conflicting movements
										else if(movement==2)
											movement = 0;
									}
								}
							}
						}
						if(movement==-1)
							movement = 0;
						if(movement>0){
							j = CrystalSwitch[CRSW_ANIM]/(CRYSTALSWITCH_RISINGASPEED*CRYSTALSWITCH_RISINGCOMBOS)*CRYSTALSWITCH_RAISELINK;
							k = Min(CrystalSwitch[CRSW_ANIM]+1, (CRYSTALSWITCH_RISINGASPEED*CRYSTALSWITCH_RISINGCOMBOS))/(CRYSTALSWITCH_RISINGASPEED*CRYSTALSWITCH_RISINGCOMBOS)*CRYSTALSWITCH_RAISELINK;
							
							j = Abs(Round(j)-Round(k));
							for(i=0; i<j; i++){
								if(movement==2){
									if(CanWalk(Link->X, Link->Y, DIR_UP, 1, false)){
										Link->Y--;
										if(!CrystalSwitch_OnRaised(true))
											Link->Y++;
									}
								}
								else{
									if(CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)){
										Link->Y++;
										if(!CrystalSwitch_OnRaised(true))
											Link->Y--;
									}
								}
							}
						}
					}
				}
			}
		}
		else
			CrystalSwitch[CRSW_LINKONRAISED] = 0;
	}
	
	//Prevent movement while jumping off a block
	if(CrystalSwitch[CRSW_JUMPOFF]){
		if(Link->Z>0)
			NoAction();
		else
			CrystalSwitch[CRSW_JUMPOFF] = 0;
	}
	
	if(CrystalSwitch[CRSW_ANIM]>0)
		CrystalSwitch[CRSW_ANIM]--;
	else{
		CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()] &= 0xFF;
	}
}

//Return sum of all bits for blocks Link is standing on
int CrystalSwitch_OnRaised(bool onlyRaised){
	int swCMBOffset;
	if(CRYSTALSWITCH_OFFSET)
		swCMBOffset = CRYSTALSWITCH_OFFSET;
	else
		swCMBOffset = Ceiling((2+CRYSTALSWITCH_RISINGCOMBOS)*0.25)*4;
	int ret;
	bool blockLowering;
	for(int x=0; x<2; x++){
		for(int y=0; y<2; y++){
			int cd = Screen->ComboD[ComboAt(Link->X+2+x*12, Link->Y+10+y*4)];
			//Check if Link is on colored blocks
			for(int j=0; j<CRYSTALSWITCH_NUM_COLORS; j++){
				if(cd>=CMB_CRYSTALSWITCH_BLOCKS+swCMBOffset*j&&cd<CMB_CRYSTALSWITCH_BLOCKS+swCMBOffset*j+2+CRYSTALSWITCH_RISINGCOMBOS){
					if(onlyRaised){
						int lstate = CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()];
						//Animated combos
						if(lstate&(1<<(j+8))){
							//Lowered, raising
							if(lstate&(1<<j)){
								ret |= (1<<j);
							}
							//Raised, lowering, last frame
							else if(CrystalSwitch[CRSW_LINKONRAISED]&&CrystalSwitch[CRSW_ANIM]==1){
								blockLowering = true;
							}
							else{
								ret |= (1<<j);
							}
								
						}
						else if(lstate&(1<<j)){
							ret |= (1<<j);
						}
					}
					else{
						ret |= (1<<j);
					}
				}
			}
			//Check if Link is on gray blocks
			if(cd>=CMB_CRYSTALSWITCH_STATICBLOCKS&&cd<CMB_CRYSTALSWITCH_STATICBLOCKS+2+CRYSTALSWITCH_RISINGCOMBOS){
				int cd2 = cd-CMB_CRYSTALSWITCH_STATICBLOCKS;
				if(onlyRaised){
					if(cd2==0){
						//blockLowering = true;
					}
					else{
						ret |= 1<<9;
					}
				}
				else{
					ret |= (1<<9);
				}
			}
		}
	}
	
	//Unset on block variable if Link is standing on a block during its last lowering frame
	if(ret==0&&blockLowering){
		CrystalSwitch[CRSW_LINKONRAISED] = 0;
		return 1<<15; //Return a value just to prevent the hopping code from running. 
	}
	return ret;
}

//D0-D3: Switch colors (1-8) to toggle. 0 for none.
//D6: If >0, forces the switch to use a custom pair of combos. Based on the state of D0. Raised combo, followed by lowered.
//D7: Special behaviors
//		0 - Standard operations. D0-D4 toggle between lowered and raised.
//		1 - Lower D0, raise all others
//		2 - Cycle between lowered color, raise all others
ffc script CrystalSwitch_Trigger{
	void run(int toggleA, int toggleB, int toggleC, int toggleD, int d4, int d5, int forceCombo, int specialBehavior){
		if(toggleA==toggleB){
			if(toggleA==0&&toggleB==0){
				toggleA = 1;
				toggleB = 2;
			}
			else
				toggleB = toggleA+1;
		}
		if(toggleA>0)
			toggleA = Clamp(toggleA-1, 0, CRYSTALSWITCH_NUM_COLORS-1);
		else
			toggleA = -1;
		if(toggleB>0)
			toggleB = Clamp(toggleB-1, 0, CRYSTALSWITCH_NUM_COLORS-1);
		else
			toggleB = -1;
		if(toggleC>0)
			toggleC = Clamp(toggleC-1, 0, CRYSTALSWITCH_NUM_COLORS-1);
		else
			toggleC = -1;
		if(toggleD>0)
			toggleD = Clamp(toggleD-1, 0, CRYSTALSWITCH_NUM_COLORS-1);
		else
			toggleD = -1;
		
		int toggleCount;
		if(toggleA>-1)
			toggleCount++;
		if(toggleB>-1)
			toggleCount++;
		if(toggleC>-1)
			toggleCount++;
		if(toggleD>-1)
			toggleCount++;
		
		
		int pos = ComboAt(this->X+8, this->Y+8);
		this->X = ComboX(pos);
		this->Y = ComboY(pos);
		
		lweapon lastTrigger[1];
		this->Data = 0;
		
		int strikeCooldown;
		while(true){
			int lstate = CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()];
			
			int loweredState = -1;
			//Find the first state that's lowered
			if(loweredState==-1){
				if(!(lstate&(1<<toggleA)))
					loweredState = toggleA;
			}
			if(loweredState==-1){
				if(!(lstate&(1<<toggleB)))
					loweredState = toggleB;
			}
			if(loweredState==-1){
				if(!(lstate&(1<<toggleC)))
					loweredState = toggleC;
			}
			if(loweredState==-1){
				if(!(lstate&(1<<toggleD)))
					loweredState = toggleD;
			}
			
			bool canHit = true;
			//In Special Behavior 1: The switch cannot be hit if A is already lowered
			if(specialBehavior==1&&!(lstate&(1<<toggleA)))
				canHit = false;
			if(CrystalSwitch_CheckCollision(this, lastTrigger)){
				if(strikeCooldown==0&&canHit&&CrystalSwitch[CRSW_ANIM]==0){
					Game->PlaySound(SFX_CRYSTALSWITCH_TRIGGER);
					
					int linkColl = CrystalSwitch_OnRaised(false)&0xFF; //Function returns sum of all bits for blocks Link is on
					
					int newState = 0; //Flag which block states are being changed
					int newStateMask = 0; //Mask used for combining new states with the existing level states
					
					//Raise all, lower A
					if(specialBehavior==1){
						newStateMask |= 1<<toggleA;
						if(toggleB>-1){
							newState |= 1<<toggleB;
							newStateMask |= 1<<toggleB;
						}
						if(toggleC>-1){
							newState |= 1<<toggleC;
							newStateMask |= 1<<toggleC;
						}
						if(toggleD>-1){
							newState |= 1<<toggleD;
							newStateMask |= 1<<toggleD;
						}
					}
					//Alternate A-D lowered
					else if(specialBehavior==2){
						int nextState = toggleA;
						if(loweredState==toggleA){
							if(toggleB>-1)
								nextState = toggleB;
							else if(toggleC>-1)
								nextState = toggleC;
							else if(toggleD>-1)
								nextState = toggleD;
						}
						if(loweredState==toggleB){
							if(toggleC>-1)
								nextState = toggleC;
							else if(toggleD>-1)
								nextState = toggleD;
							else if(toggleA>-1)
								nextState = toggleA;
						}
						if(loweredState==toggleC){
							if(toggleD>-1)
								nextState = toggleD;
							else if(toggleA>-1)
								nextState = toggleA;
							else if(toggleB>-1)
								nextState = toggleB;
						}
						if(loweredState==toggleD){
							if(toggleA>-1)
								nextState = toggleA;
							else if(toggleB>-1)
								nextState = toggleB;
							else if(toggleC>-1)
								nextState = toggleC;
						}
						
						if(toggleA>-1){
							newState |= 1<<toggleA;
							newStateMask |= 1<<toggleA;
						}
						if(toggleB>-1){
							newState |= 1<<toggleB;
							newStateMask |= 1<<toggleB;
						}
						if(toggleC>-1){
							newState |= 1<<toggleC;
							newStateMask |= 1<<toggleC;
						}
						if(toggleD>-1){
							newState |= 1<<toggleD;
							newStateMask |= 1<<toggleD;
						}
						
						newState &= ~(1<<nextState);
					}
					//Toggle all
					else{
						if(toggleA>-1){
							if(!(lstate&(1<<toggleA)))
								newState |= 1<<toggleA;
							newStateMask |= 1<<toggleA;
						}
						if(toggleB>-1){
							if(!(lstate&(1<<toggleB)))
								newState |= 1<<toggleB;
							newStateMask |= 1<<toggleB;
						}
						if(toggleC>-1){
							if(!(lstate&(1<<toggleC)))
								newState |= 1<<toggleC;
							newStateMask |= 1<<toggleC;
						}
						if(toggleD>-1){
							if(!(lstate&(1<<toggleD)))
								newState |= 1<<toggleD;
							newStateMask |= 1<<toggleD;
						}
					}
					
					if(CRYSTALSWITCH_CAN_WALK_ON_TOP){
						if(!IsSideview()&&(linkColl&newState)){
							CrystalSwitch[CRSW_LINKONRAISED] = 1;
						}
					}
					
					int astate = (((lstate&0xFF)^newState)&newStateMask)<<8; //Find bits that have changed to determine which combos should animate
					
					lstate &= ~newStateMask; //Unset bits affected by new state
					lstate |= newState; //Combine new state with the current one
					
					lstate &= 0xFF; //Clear old animation data
					lstate |= astate; //Set new animation bits
					
					CrystalSwitch[CRSW_LSTATES+Game->GetCurLevel()] = lstate;
					
					CrystalSwitch[CRSW_ANIM] = CRYSTALSWITCH_RISINGCOMBOS*CRYSTALSWITCH_RISINGASPEED;
					strikeCooldown = 20;
				}
			}
			
			int switchColor = 0;
			if(loweredState>-1)
				switchColor = 4+loweredState*2;
			if(specialBehavior==1){
				if(lstate&(1<<toggleA))
					switchColor = 4+toggleA*2;
				else
					switchColor = 4+toggleA*2+1;
			}
			if(toggleCount>2){
				if(specialBehavior==0&&CRYSTALSWITCH_USE_BLANK_TRIGGER){
					if(lstate&(1<<toggleA))
						switchColor = 1;
					else
						switchColor = 0;
				} 
			}
			
			int switchCMB = CMB_CRYSTALSWITCH_TRIGGERS+switchColor;
			if(forceCombo){
				if(lstate&(1<<toggleA))
					switchCMB = forceCombo+1;
				else
					switchCMB = forceCombo;
			}
			
			if(CRYSTALSWITCH_USE_FFC_GRAPHICS)
				this->Data = switchCMB;
			else
				Screen->ComboD[pos] = switchCMB;
			
			if(strikeCooldown>0)
				strikeCooldown--;
			Waitframe();
		}
	}
	bool CrystalSwitch_CheckCollision(ffc this, lweapon lastTrigger){
		bool excludedTypes[41];
		//Define all weapon types that can't hit the switch here
		excludedTypes[LW_CANEOFBYRNA] = true;
		excludedTypes[LW_BOMB] = true;
		excludedTypes[LW_SBOMB] = true;
		excludedTypes[LW_FIRE] = true;
		excludedTypes[LW_WHISTLE] = true;
		excludedTypes[LW_BAIT] = true;
		excludedTypes[LW_MAGIC] = true;
		excludedTypes[LW_WIND] = true;
		excludedTypes[LW_REFMAGIC] = true;
		excludedTypes[LW_REFFIREBALL] = true;
		excludedTypes[LW_SPARKLE] = true;
		excludedTypes[LW_FIRESPARKLE] = true;
		
		for(int i=Screen->NumLWeapons(); i>=1; i--){
			lweapon l = Screen->LoadLWeapon(i);
			if(l!=lastTrigger[0]){
				if(!excludedTypes[l->ID]&&l->CollDetection&&l->DeadState==WDS_ALIVE){
					if(Collision(this, l)){
						lastTrigger[0] = l;
						if(l->ID==LW_BRANG||l->ID==LW_HOOKSHOT)
							l->DeadState = WDS_BOUNCE;
						else if(l->ID==LW_ARROW)
							l->DeadState = WDS_ARROW;
						else if(l->ID==LW_BEAM)
							l->DeadState = WDS_BEAMSHARDS;
						else if(l->ID==LW_MAGIC||l->ID==LW_REFMAGIC||l->ID==LW_REFROCK||l->ID==LW_REFFIREBALL)
							l->DeadState = 0;
						return true;
					}
				}
			}
		}
		return false;
	}
}

global script CrystalSwitch_Example{
	void run(){
		CrystalSwitch_Init();
		while(true){
			CrystalSwitch_Update();
			Waitdraw();
			Waitframe();
		}
	}
}