//Utility
//v0.3.4

void CopyArray(int src, int dest){
	for (int i = 0; i < SizeOfArray(src); i++){
		src[i] = dest[i];
	}
}
	
void CopyArrayB(int size, int src, int dest){ //SizeOfArray() does not work on Boolean arrays, which is why it's prudent to have a bboolean array and an int or float array in pairs with identical index sizes.
	for (int i = 0; i < size; i++){
		src[i] = dest[i];
	}
}


void MirrorCounter(int main, int mirror){
	Game->Counter[mirror] = Game->Counter[main];
}

void MirrorMCounter(int main, int mirror){
	Game->MCounter[mirror] = Game->MCounter[main];
}

void MirrorDCounter(int main, int mirror){
	Game->DCounter[mirror] = Game->DCounter[main];
}

ffc script playMIDI{
	void run(int midiNumber){
		Game->PlayMIDI(midiNumber);
	}
}

//ffc script playMusic{
//	void run(int filenumber, int track){ //Music files must be numbered.  May not work without hardcoding. 
//		Game->PlayEnhancedMusic(filenumber, track); //Hardcoding srting dexlared as a raw number, would work, but is unwise. 
//	}
//}

ffc script playMusic{
	void run(int filenumber, int track){ 
		int music1[]="music1filename.name";
		int music2[]="music1filename.name";
		int music3[]="music1filename.name";
		int music4[]="music1filename.name";
		int music5[]="music1filename.name";
		int music6[]="music1filename.name";
		int music7[]="music1filename.name";
		int music8[]="music1filename.name";
		int music9[]="music1filename.name";
		int music10[]="music1filename.name";
		int music11[]="music1filename.name";
		int music12[]="music1filename.name";
		int music13[]="music1filename.name";
		int music14[]="music1filename.name";
		int music15[]="music1filename.name";
		int music16[]="music1filename.name";
		int music17[]="music1filename.name";
		int music18[]="music1filename.name";
		int music19[]="music1filename.name";
		int music20[]="music1filename.name";
		int music[20]={music1,music2,music3,music4,music5,music6,music7,music8,music9,music10,music11,music12,music13,music14,music15,music16,music17,music18,music19,music20};
		//Hardcode filenames as strings, insert into array, and use input filenumber to define the array index with that string.
		//Music files must be numbered.  May not work without hardcoding. 
		Game->PlayEnhancedMusic(music[filenumber], track); //Hardcoding srting dexlared as a raw number, would work, but is unwise. 
	}
}

const int MIDI_DEFEATBOSS = 0;

ffc script BossMusicEnhanced{
	void run(int midiNumber, int reg, int dur, float musicType_musicTypeVictory, float musicBoss_trkBoss, float musicVictory_trkVictory, float loopBossMusic){
		int curScreen = Game->GetCurScreen();
		int curDMAP = Game->GetCurDMap();
		int curDmap = Game->GetCurDMap();
		int dat = Game->GetScreenD(curScreen,reg);
		int stdMIDI = Game->DMapMIDI[curDMAP];
		
		int dmapMusicBuffer[512]=" ";
		Game->GetDMapMusicFilename(curDMAP, dmapMusicBuffer);
		
		int musicType = _GetHighArgument(musicType_musicTypeVictory); //xxx##.xxxx
		int musicType_Victory = _GetLowArgument(musicType_musicTypeVictory); //xxxxx.xx##
		
		int musicBoss = _GetHighArgument(musicBoss_trkBoss); //#####.xxxx
		int trkBoss = _GetLowArgument(musicBoss_trkBoss); //xxxxx.####
		
		int musicVictory = _GetHighArgument(musicVictory_trkVictory);
		int trkVictory = _GetLowArgument(musicVictory_trkVictory); //xxxxx.####
		
		int dmapTrack = Game->GetDMapMusicTrack(curDMAP);
		int mp3[]=".mp3";
		int vgm[]=".vgm";
		int nsf[]=".nsf";
		int ogg[]=".ogg";
		int s3m[]=".s3m";
		int mod[]=".mod";
		int spc[]=".spc";
		int gym[]=".gym";
		int gbs[]=".gbs";
		int it_format[]=".it";
		int xm[]=".xm";
		
		int boss_buffer[7]=" "; //two-digit number, plus four-digit extension, plus NULL.
		int victory_buffer[7]=" "; //Buffer for Victory Music Filename.
		int strBoss[2]=" "; //The two digit value of musicBoss arg.
		int strVictory[2]=" "; //The two digit value of musicVictory is stored here.
		//int bossMusic[]=" "; //Must read value from enhBoss, append .mp3 to it, and 
		
		
		///Set up Boss Music Filename String
		itoa(strBoss, musicBoss); //Copy the value of arg musicBoss into string strBoss.	
		strncpy(boss_buffer, strBoss, 2); //Copy filename (two-digit number) to buffer.
		if ( musicType == 0 ) strcat(boss_buffer, mp3); //Append datatype to buffer (MP3)
		else if ( musicType == 1 ) strcat(boss_buffer, vgm); //Append datatype to buffer ( Video Game Music format)
		else if ( musicType == 2 ) strcat(boss_buffer, nsf); //Append datatype to buffer ( NES Sound File ) 
		else if ( musicType == 3 ) strcat(boss_buffer, ogg); //Append datatype to buffer ( The Xiph.org open music format )
		else if ( musicType == 4 ) strcat(boss_buffer, s3m); //Append datatype to buffer ( ScreamTracker 3 module file )
		else if ( musicType == 5 ) strcat(boss_buffer, mod); //Append datatype to buffer ( Tracker Module file ) 
		else if ( musicType == 6 ) strcat(boss_buffer, spc); //Append datatype to buffer ( Super NES / SuFami soound file )
		else if ( musicType == 7 ) strcat(boss_buffer, gym); //Append datatype to buffer ( Genesis / Megadrive sound file )
		else if ( musicType == 8 ) strcat(boss_buffer, gbs); //Append datatype to buffer ( Gameboy sound file )
		else if ( musicType == 9 ) strcat(boss_buffer, it_format); //Append datatype to buffer ( Impulse Tracker audio file )
		else if ( musicType == 10 ) strcat(boss_buffer, xm); //Append datatype to buffer ( Triton FastTracker 2 'Extended Module' format }
		///Other formats.
		
		//Set up Victory Music Filename String
		itoa(strVictory, musicVictory); //Copy the value of arg musicVictory into string strVictory.
		strncpy(victory_buffer, strVictory, 2); //Copy filename (two-digit number) to buffer.
		if ( musicType_Victory == 0 ) strcat(boss_buffer, mp3); //Append datatype to buffer (MP3)
		else if ( musicType_Victory == 1 ) strcat(boss_buffer, vgm); //Append datatype to buffer ( Video Game Music format)
		else if ( musicType_Victory == 2 ) strcat(boss_buffer, nsf); //Append datatype to buffer ( NES Sound File ) 
		else if ( musicType_Victory == 3 ) strcat(boss_buffer, ogg); //Append datatype to buffer ( The Xiph.org open music format )
		else if ( musicType_Victory == 4 ) strcat(boss_buffer, s3m); //Append datatype to buffer ( ScreamTracker 3 module file )
		else if ( musicType_Victory == 5 ) strcat(boss_buffer, mod); //Append datatype to buffer ( Tracker Module file ) 
		else if ( musicType_Victory == 6 ) strcat(boss_buffer, spc); //Append datatype to buffer ( Super NES / SuFami soound file )
		else if ( musicType_Victory == 7 ) strcat(boss_buffer, gym); //Append datatype to buffer ( Genesis / Megadrive sound file )
		else if ( musicType_Victory == 8 ) strcat(boss_buffer, gbs); //Append datatype to buffer ( Gameboy sound file )
		else if ( musicType_Victory == 9 ) strcat(boss_buffer, it_format); //Append datatype to buffer ( Impulse Tracker audio file )
		else if ( musicType_Victory == 10 ) strcat(boss_buffer, xm); //Append datatype to buffer ( Triton FastTracker 2 'Extended Module' format }
		///Other formats.
		
		bool playingMusic;
		
		int LoopClockMethod = GetDigit(loopBossMusic, 4);
		//Convert mins and seconds.
		
		
		int BossMusicDuration;
		if ( LoopClockMethod == 0 ) {
			BossMusicDuration = MusicFrames(loopBossMusic); //Convert loopBossMusic into time. 
		}
		if ( LoopClockMethod > 0 ) {
			BossMusicDuration = _GetPartialArg(loopBossMusic,3,8); //Use the full value of loopBossMusic as frame in int.
		}
		
		if ( dat == 0 && loopBossMusic == 0 ) {
			
			Game->PlayEnhancedMusic(boss_buffer, trkBoss);
			
			if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) ) {
				Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available. 
			}
		}
		
		while(true){
			
			if ( dat == 0 && loopBossMusic == 0 ){

				//set up music loop
				for ( int q = BossMusicDuration; q >=0; q-- ){
					if ( ! playingMusic ) {
						playingMusic = true;
						Game->PlayEnhancedMusic(boss_buffer, trkBoss);
					}
					Waitframe();
				
				}
				playingMusic = false;
			}
				
			
			
			dat = Game->GetScreenD(curScreen,reg);
			if ( dat > 0 ) {
				if ( dur > 0 ) {
					Game->PlayEnhancedMusic(victory_buffer, trkVictory);
					if ( ! Game->PlayEnhancedMusic(victory_buffer, trkVictory) ) Game->PlayMIDI(MIDI_DEFEATBOSS);
					for ( int q = 0; q <= dur; q++ ) {
						Waitframe(); //Pause for duration of victory music. 
					}
				}
				Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack);
				if ( ! Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack) ) {
					Game->PlayMIDI(stdMIDI);
				}
			}
			Waitframe();
		}
		
	}
	
	int MusicSeconds(float seconds){
			int music_seconds = _GetLowArgument(seconds);
			return music_seconds * 60;
	}
		
	int MusicMinutes(float mins){
			int music_minutes = _GetHighArgument(mins);
			return music_minutes * 360;
	}
			
	int MusicFrames(float val){
		int mins = MusicMinutes(val);
		int seconds = MusicSeconds(val);
		return mins+seconds;
	}
	
	int _GetRemainderAsInt(int v) {
	    int r = (v - (v << 0)) * 10000;
	    return r;
	}

	// This function breaks up the value of an argument into individual digits. It is combined with the function GetDigit below.


	int _GetDigit(int n, int place){ //GetDigit and related functions by Gleeok
		place = Clamp(place, -4, 4);
		if(place < 0){
			n = _GetRemainderAsInt(n);
			place += 4;
		}

		int r = ((n / Pow(10, place)) % 10) << 0;
		return r;
	}

	int _GetHighArgument(int arg) {
	    return arg >> 0;
	}

	int _GetLowArgument(int arg) {
	    return (arg - (arg >> 0)) * 10000;
	}

	int _GetPartialArg(int arg, int place, int num){
		place = Clamp(place, -4, 4);
		int r;
		int adj = 1;
		for(int i = num-1; i > -1; i--){
			if(place - i < -4) continue;
			r += _GetDigit(arg, place - i) * adj;
			adj *= 10;
		}
		return r;
	}
}



ffc script EnhancedBossMusic{
	void run(int midiNumber, int reg, int dur, int musicType, int musicBoss, int trkBoss, int musicVictory, int trkVictory){
		int curScreen = Game->GetCurScreen();
		int curDMAP = Game->GetCurDMap();
		int curDmap = Game->GetCurDMap();
		int dat = Game->GetScreenD(curScreen,reg);
		int stdMIDI = Game->DMapMIDI[curDMAP];
		
		int dmapMusicBuffer[512]=" ";
		Game->GetDMapMusicFilename(curDMAP, dmapMusicBuffer);
		
		int dmapTrack = Game->GetDMapMusicTrack(curDMAP);
		int mp3[]=".mp3";
		int vgm[]=".vgm";
		int nsf[]=".nsf";
		int boss_buffer[7]=" "; //two-digit number, plus four-digit extension, plus NULL.
		int victory_buffer[7]=" "; //Buffer for Victory Music Filename.
		int strBoss[2]=" "; //The two digit value of musicBoss arg.
		int strVictory[2]=" "; //The two digit value of musicVictory is stored here.
		//int bossMusic[]=" "; //Must read value from enhBoss, append .mp3 to it, and 
		
		
		///Set up Boss Music Filename String
		itoa(strBoss, musicBoss); //Copy the value of arg musicBoss into string strBoss.	
		strncpy(boss_buffer, strBoss, 2); //Copy filename (two-digit number) to buffer.
		if ( musicType == 0 ) strcat(boss_buffer, mp3); //Append datatype to buffer.
		else if ( musicType == 1 ) strcat(boss_buffer, vgm); //Append datatype to buffer.
		else if ( musicType == 2 ) strcat(boss_buffer, nsf); //Append datatype to buffer.
		///Other formats.
		
		//Set up Victory Music Filename String
		itoa(strVictory, musicVictory); //Copy the value of arg musicVictory into string strVictory.
		strncpy(victory_buffer, musicVictory, 2); //Copy filename (two-digit number) to buffer.
		if ( musicType == 0 ) strcat(victory_buffer, mp3); //Append datatype to buffer.
		else if ( musicType == 1 ) strcat(victory_buffer, vgm); //Append datatype to buffer.
		else if ( musicType == 2 ) strcat(victory_buffer, nsf); //Append datatype to buffer.
		///Other formats.
		
		
		if ( dat == 0 ) {
			
			Game->PlayEnhancedMusic(boss_buffer, trkBoss);
			if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) ) {
				Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available. 
			}
		}
		
		while(true){
			dat = Game->GetScreenD(curScreen,reg);
			if ( dat > 0 ) {
				if ( dur > 0 ) {
					Game->PlayEnhancedMusic(victory_buffer, trkVictory);
					if ( ! Game->PlayEnhancedMusic(victory_buffer, trkVictory) ) Game->PlayMIDI(MIDI_DEFEATBOSS);
					for ( int q = 0; q <= dur; q++ ) {
						Waitframe(); //Pause for duration of victory music. 
					}
				}
				Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack);
				if ( ! Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack) ) {
					Game->PlayMIDI(stdMIDI);
				}
			}
			Waitframe();
		}
	}
}


ffc script BossMusic{
	void run(int midiNumber, int reg, int dur){
		int curScreen = Game->GetCurScreen();
		int dat = Game->GetScreenD(curScreen,reg);
		if ( dat == 0 ) {
			Game->PlayMIDI(midiNumber);
		}
		int curDMap = Game->GetCurDMap();
		int stdMIDI = Game->DMapMIDI[curDMap];
		while(true){
			dat = Game->GetScreenD(curScreen,reg);
			if ( dat > 0 ) {
				if ( dur > 0 ) {
					Game->PlayMIDI(MIDI_DEFEATBOSS);
					for ( int q = 0; q <= dur; q++ ) {
						Waitframe();
					}
				}
				Game->PlayMIDI(stdMIDI);
			}
			Waitframe();
		}
	}
}



///Used to check if any given pointer is on screen. Move pointers to X = 32768 to effectively kill them.
 bool isOnScreen(item i){
	if( i->isValid() && i->X != 32768 ) {
		return true;
	}
	return false;
}

 bool isOnScreen(ffc f){
	if( f->Data > 0 && f->X != 32768 ) {
		return true;
	}
	return false;
}

 bool isOnScreen(npc n){
	if( n->isValid() && n->X != 32768 ) {
		return true;
	}
	return false;
}

 bool isOnScreen(eweapon e){
	if( e->isValid() && e->X != 32768 ) {
		return true;
	}
	return false;
}

bool isOnScreen(lweapon l){
	if( l->isValid() && l->X != 32768 ) {
		return true;
	}
	return false;
}

//Puts an artifical limit of ( limit ) for on-screen enemies. 
//Any enemy spawned (other than Fairy NPCs) will be removed, if it exceeds the limit imposed. 
//void LimitEnemies(int limit){
//	if ( Screen->NumNPCs() >= limit ) {
//		for ( int q = Screen->NumNPCs(); q > limit; q-- ){
//			npc n = Screen->LoadNPC(q);
//			if ( n->Type != NPCT_FAIRY ) {
//				Remove(n);
//			}
//		}
//	}
//}

//Puts an artifical limit of ( limit ) for on-screen enemies. 
//Any enemy spawned (other than Fairy NPCs) will be removed, if it exceeds the limit imposed. 
void LimitEnemies(int limit){
	if ( Screen->NumNPCs() >= limit ) {
		int pass = 1;
		for ( int q = 1; q <=Screen->NumNPCs(); q++ ){
			npc n = Screen->LoadNPC(q);
			if ( n->Type == NPCT_FAIRY || n->Type == NPCT_GUY || n->Type == NPCT_PROJECTILE 
				|| n->Type == NPCT_SPINTILE || n->Type == NPCT_NONE || n->Type == NPCT_TRAP ) {
				continue;
			}
			
			if ( pass > limit ) {
				Remove(n);
			}
			pass++;
		}
	}
}


///Need version that passes enemies by type as excludes, or as 'specific includes' (onlt remove enemies of that type. 