Copy to Clipboard Test

[2.55] Palette Based Day/Night System Code

const int DAYNIGHT_USE_SYSTEM_CLOCK = 0; //Set to 1 to use the system clock instead of a simulated one

const int DMF_TIME_CAN_ADVANCE = DMF_SCRIPT1; //DMap flag used to flag DMaps where time advances

//Hour to start the clock on
const int DAYNIGHT_STARTING_HOUR = 8;

//Timing for sunset transitions
const int DAYNIGHT_SUNSET_START_HOUR = 16;
const int DAYNIGHT_SUNSET_MID_HOUR = 18;
const int DAYNIGHT_SUNSET_END_HOUR = 20;

//Timing for sunrise transitions
const int DAYNIGHT_SUNRISE_START_HOUR = 4;
const int DAYNIGHT_SUNRISE_MID_HOUR = 6;
const int DAYNIGHT_SUNRISE_END_HOUR = 8;

//Timing for midi change
//The mid time needs to be set because otherwise a night period of >12 hours would break
const int DAYNIGHT_MIDI_NIGHT_START_HOUR = 18;
const int DAYNIGHT_MIDI_NIGHT_MID_HOUR = 24;
const int DAYNIGHT_MIDI_NIGHT_END_HOUR = 6;

//Number of transitional palettes for the sunrise and sunset transitions. Negative numbers mean the palettes with cycle backwards
const int SUNSET_START_PALETTES = 7;
const int SUNSET_END_PALETTES = 7;

const int SUNRISE_START_PALETTES = -7;
const int SUNRISE_END_PALETTES = -7; 

//How often to increment the clock in frames
const int DAYNIGHT_TIME_INCREMENT_FRAMES = 5;
//How long in seconds, minutes, and hours to increment it by
const int DAYNIGHT_TIME_INCREMENT_SECONDS = 0;
const int DAYNIGHT_TIME_INCREMENT_MINUTES = 1;
const int DAYNIGHT_TIME_INCREMENT_HOURS = 0;

//Position for the timer onscreen (Top of the subscreen is at Y = -56)
const int DAYNIGHT_DRAW_CLOCK = 1; 
const int DAYNIGHT_CLOCK_LAYER = 7;
const int DAYNIGHT_CLOCK_X = 88;
const int DAYNIGHT_CLOCK_Y = -56;
const int DAYNIGHT_CLOCK_PLACES = 1; //0 - Hours only, 1 - Hours:Minutes, 2 - Hours:Minutes:Seconds
const int DAYNIGHT_CLOCK_HIDE_AM_PM = 0; //0 - AM and PM are visible, 1 - AM and PM are not visible, 2 - Military time

//Font, colors, and shadow type for drawing the clock
const int FONT_DAYNIGHT_CLOCK = FONT_Z1;
const int C_DAYNIGHT_CLOCK = 0x01;
const int C_DAYNIGHT_CLOCK_SHADOW = 0x0F;
const int SHD_DAYNIGHT_CLOCK_SHADOWTYPE = SHD_NORMAL; 

int DayNight[_DN_START + 512 * _DN_BLOCK];

const int _DN_HOUR = 0;
const int _DN_MINUTE = 1;
const int _DN_SECOND = 2;
const int _DN_FRAMECOUNTER = 3;
const int _DN_FIRSTLOAD = 4;

//Start index of the 2D part of the global array and block size
const int _DN_START = 16;
const int _DN_BLOCK = 8;

const int _DN_DAYPAL = 0;
const int _DN_SUNSETPAL = 1;
const int _DN_NIGHTPAL = 2;
const int _DN_SUNRISEPAL = 3;
const int _DN_MIDIDAY = 4;
const int _DN_MIDINIGHT = 5;
const int _DN_MIDICURRENT = 6;

global script DayNight_Example{
	void run(){
		DayNight_Init();
		while(true){
			DayNight_Update();
			
			Waitdraw();
			Waitframe();
		}
	}
}

void DayNight_Init(){
	unless(DayNight[_DN_FIRSTLOAD]){
		DayNight[_DN_HOUR] = DAYNIGHT_STARTING_HOUR;
		
		DayNight[_DN_FIRSTLOAD] = 1;
	}
}

void DayNight_Update(){
	int i;
	int tmpDMap;
	
	if(Game->DMapFlags[Game->GetCurDMap()]&DMF_TIME_CAN_ADVANCE){
		if(DAYNIGHT_USE_SYSTEM_CLOCK){
			DayNight[_DN_HOUR] = GetSystemTime(RTC_HOUR);
			DayNight[_DN_MINUTE] = GetSystemTime(RTC_MINUTE);
			DayNight[_DN_SECOND] = GetSystemTime(RTC_SECOND);
		}
		else{
			++DayNight[_DN_FRAMECOUNTER];
			if(DayNight[_DN_FRAMECOUNTER]>=DAYNIGHT_TIME_INCREMENT_FRAMES){
				DayNight[_DN_HOUR] += DAYNIGHT_TIME_INCREMENT_HOURS;
				DayNight[_DN_MINUTE] += DAYNIGHT_TIME_INCREMENT_MINUTES;
				DayNight[_DN_SECOND] += DAYNIGHT_TIME_INCREMENT_SECONDS;
				
				while(DayNight[_DN_SECOND]>=60){
					DayNight[_DN_SECOND] -= 60;
					++DayNight[_DN_MINUTE];
				}
				while(DayNight[_DN_MINUTE]>=60){
					DayNight[_DN_MINUTE] -= 60;
					++DayNight[_DN_HOUR];
				}
				while(DayNight[_DN_HOUR]>=25){
					DayNight[_DN_HOUR] -= 24;
				}
				
				DayNight[_DN_FRAMECOUNTER] = 0;
			}
		}
	}


	//Update the palette for the current DMap
	DayNight_UpdateDMapPalette(Game->GetCurDMap());
	//Also update for side warp and tile warp DMaps
	for(i=0; i<4; ++i){
		tmpDMap = Screen->GetSideWarpDMap(i);
		DayNight_UpdateDMapPalette(tmpDMap);
		tmpDMap = Screen->GetTileWarpDMap(i);
		DayNight_UpdateDMapPalette(tmpDMap);
	}
	
	if(DAYNIGHT_DRAW_CLOCK){
		DayNight_DrawClock();
	}
}

void DayNight_UpdateDMapPalette(int whichDMap){
	int h = DayNight[_DN_HOUR];
	int m = DayNight[_DN_MINUTE];
	int s = DayNight[_DN_SECOND];
	
	int curTime;
	int chunkTime;
	int newPal;
	int newMid;

	int i = _DN_START+_DN_BLOCK*whichDMap;
	//Updating Palettes
	if(DayNight[i+_DN_DAYPAL]){
		//Day
		if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_END_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_START_HOUR, 0, 0)<0){
			newPal = DayNight[i+_DN_DAYPAL];
		}
		//Start of sunset
		else if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_START_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_MID_HOUR, 0, 0)<0){
			if(Abs(SUNSET_START_PALETTES)>0){
				curTime = Abs(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_START_HOUR, 0, 0));
				chunkTime = Abs(DayNight_GetTimeDifference(DAYNIGHT_SUNSET_START_HOUR, 0, 0, DAYNIGHT_SUNSET_MID_HOUR, 0, 0))/(Abs(SUNSET_START_PALETTES)+1);
				newPal = DayNight[i+_DN_DAYPAL]+Sign(SUNSET_START_PALETTES)*Floor(curTime/chunkTime);
			}
			else{
				newPal = DayNight[i+_DN_SUNSETPAL];
			}
		}
		//End of sunset
		else if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_MID_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_END_HOUR, 0, 0)<0){
			if(Abs(SUNSET_END_PALETTES)>0){
				curTime = Abs(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_MID_HOUR, 0, 0));
				chunkTime = Abs(DayNight_GetTimeDifference(DAYNIGHT_SUNSET_MID_HOUR, 0, 0, DAYNIGHT_SUNSET_END_HOUR, 0, 0))/(Abs(SUNSET_END_PALETTES)+1);
				newPal = DayNight[i+_DN_SUNSETPAL]+Sign(SUNSET_END_PALETTES)*Floor(curTime/chunkTime);
			}
			else{
				newPal = DayNight[i+_DN_SUNSETPAL];
			}
		}
		//Night
		else if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNSET_END_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_START_HOUR, 0, 0)<0){
			newPal = DayNight[i+_DN_NIGHTPAL];
		}
		//Start of sunrise
		else if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_START_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_MID_HOUR, 0, 0)<0){
			if(Abs(SUNRISE_START_PALETTES)>0){
				curTime = Abs(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_START_HOUR, 0, 0));
				chunkTime = Abs(DayNight_GetTimeDifference(DAYNIGHT_SUNRISE_START_HOUR, 0, 0, DAYNIGHT_SUNRISE_MID_HOUR, 0, 0))/(Abs(SUNRISE_START_PALETTES)+1);
				newPal = DayNight[i+_DN_NIGHTPAL]+Sign(SUNRISE_START_PALETTES)*Floor(curTime/chunkTime);
			}
			else{
				newPal = DayNight[i+_DN_SUNRISEPAL];
			}
		}
		//End of sunrise
		else if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_MID_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_END_HOUR, 0, 0)<0){
			if(Abs(SUNRISE_END_PALETTES)>0){
				curTime = Abs(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_SUNRISE_MID_HOUR, 0, 0));
				chunkTime = Abs(DayNight_GetTimeDifference(DAYNIGHT_SUNRISE_MID_HOUR, 0, 0, DAYNIGHT_SUNRISE_END_HOUR, 0, 0))/(Abs(SUNRISE_END_PALETTES)+1);
				newPal = DayNight[i+_DN_SUNRISEPAL]+Sign(SUNRISE_END_PALETTES)*Floor(curTime/chunkTime);
			}
			else{
				newPal = DayNight[i+_DN_SUNRISEPAL];
			}
		}
		
		if(newPal!=0){
			if(Game->DMapPalette[whichDMap]!=newPal)
				Game->DMapPalette[whichDMap] = newPal;
		}
	}
	//Updating Music
	if(DayNight[i+_DN_MIDIDAY]!=0){
		//Night
		if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_MIDI_NIGHT_START_HOUR, 0, 0)>0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_MIDI_NIGHT_MID_HOUR, 0, 0)<=0){
			newMid = DayNight[i+_DN_MIDINIGHT];
		}
		else if(DayNight_GetTimeDifference(h, m, s, DAYNIGHT_MIDI_NIGHT_MID_HOUR, 0, 0)>=0&&DayNight_GetTimeDifference(h, m, s, DAYNIGHT_MIDI_NIGHT_END_HOUR, 0, 0)<0){
			newMid = DayNight[i+_DN_MIDINIGHT];
		}
		//Day
		else{
			newMid = DayNight[i+_DN_MIDIDAY];
		}
		
		//If the midi has changed, update things
		if(newMid!=DayNight[i+_DN_MIDICURRENT]){
			//Updating midi
			if(newMid>0){
				Game->DMapMIDI[whichDMap] = newMid;
				if(whichDMap==Game->GetCurDMap())
					Game->PlayMIDI(newMid);
			}
			//Updating enhanced music
			else if(newMid<0){
				int enhMusic = Floor(Abs(newMid));
				int enhTrack = (Abs(newMid)-enhMusic)*10000;
				int buf[256];
				GetMessage(enhMusic, buf);
				Game->SetDMapEnhancedMusic(whichDMap, buf, enhTrack);
				if(Game->GetCurDMap()==whichDMap)
					Game->PlayEnhancedMusic(buf, enhTrack);
			}
			
			DayNight[i+_DN_MIDICURRENT] = newMid;
		}
	}
}

int DayNight_GetTimeDifference(int h1, int m1, int s1, int h2, int m2, int s2){
	--h1; --h2;
	int hDiff = h1-h2;
	int mDiff = m1-m2;
	int sDiff = s1-s2;
	
	while(hDiff>=12)
		hDiff -= 24;
	while(hDiff<=-12)
		hDiff += 24;

	return hDiff*3600+mDiff*60+sDiff;
}

void DayNight_DrawClock(){
	int h = DayNight[_DN_HOUR]-1;
	int m = DayNight[_DN_MINUTE];
	int s = DayNight[_DN_SECOND];
	
	int militaryTimeOffset;
	if(DAYNIGHT_CLOCK_HIDE_AM_PM==2){
		militaryTimeOffset = -1;
		if(h>11)
			militaryTimeOffset = 11;
	}
	
	int clockStr[12] = "00:00:00 AM";
	
	clockStr[0] = '0'+Floor(((h%12)+1+militaryTimeOffset)/10);
	clockStr[1] = '0'+(((h%12)+1+militaryTimeOffset)%10);
	clockStr[3] = '0'+Floor(m/10);
	clockStr[4] = '0'+(m%10);
	clockStr[6] = '0'+Floor(s/10);
	clockStr[7] = '0'+(s%10);
	
	int clrPos;
	switch(DAYNIGHT_CLOCK_PLACES){
		case 2:
			clrPos = 8;
			break;
		case 1: 
			clrPos = 5;
			break;
		default:
			clrPos = 2;
	}
	
	clockStr[clrPos] = ' ';
	if(DAYNIGHT_CLOCK_HIDE_AM_PM)
		clockStr[clrPos] = 0;
	clockStr[clrPos+1] = 'A';
	if((Floor(h/12)>0||h==11)&&h!=23){
		clockStr[clrPos+1] = 'P';
	}
	clockStr[clrPos+2] = 'M';
	clockStr[clrPos+3] = 0;
	
	Screen->DrawString(DAYNIGHT_CLOCK_LAYER, DAYNIGHT_CLOCK_X, DAYNIGHT_CLOCK_Y, FONT_DAYNIGHT_CLOCK, C_DAYNIGHT_CLOCK, -1, TF_NORMAL, clockStr, 128, SHD_DAYNIGHT_CLOCK_SHADOWTYPE, C_DAYNIGHT_CLOCK_SHADOW);
}

//Place this FFC to configure Day/Night settings for the current DMap
//D0: Which DMap to configure settings for (-1 for the current DMap)
//D1: Palette for daytime
//D2: Palette for sunset
//D3: Palette for nighttime
//D4: Palette for sunrise
//D5: Midi for daytime music (negative for enhanced music, using a ZQuest string)
//D6: Midi for nighttime music (negative for enhanced music, using a ZQuest string)
ffc script DayNight_ConfigureDMap{
	void run(int whichDMap, int dayPal, int sunsetPal, int nightPal, int sunrisePal, int dayMusic, int nightMusic){
		if(whichDMap<0)
			whichDMap = Game->GetCurDMap();
		
		int i = _DN_START+_DN_BLOCK*whichDMap;
		
		DayNight[i+_DN_DAYPAL] = dayPal;
		DayNight[i+_DN_SUNSETPAL] = sunrisePal;
		DayNight[i+_DN_NIGHTPAL] = nightPal;
		DayNight[i+_DN_SUNRISEPAL] = sunrisePal;
		DayNight[i+_DN_MIDIDAY] = dayMusic;
		DayNight[i+_DN_MIDINIGHT] = nightMusic;
	}
}

//Place down on a screen to change warps based on the time of day
//D0: If 0, change a tile warp, if 1 change a side warp
//D1: Which warp to change:
//		0 - A
//		1 - B
//		2 - C
//		3 - D
//D2: Starting time for the warp change (decimal places are used for minutes)
//D3: Ending time for the warp change (decimal places are used for minutes)
//D4: Which DMap to warp to (-1 to leave unchanged)
//D5: Which screen to warp to (in decimal) (-1 to leave unchanged)
ffc script DayNight_ChangeWarp{
	void run(int tileOrSideWarp, int warpID, int startTime, int endTime, int whichDMap, int whichScreen){
		warpID = Clamp(warpID, 0, 3);
		
		int startingDMap;
		int startingScreen;
		if(tileOrSideWarp){
			startingDMap = Screen->GetSideWarpDMap(warpID);
			startingScreen = Screen->GetSideWarpScreen(warpID);
		}
		else{
			startingDMap = Screen->GetTileWarpDMap(warpID);
			startingScreen = Screen->GetTileWarpScreen(warpID);
		}
		int newDMap = startingDMap;
		int newScreen = startingScreen;
		if(whichDMap>-1)
			newDMap = whichDMap;
		if(whichScreen>-1)
			newScreen = whichScreen;
		
		int startHour = Clamp(Floor(startTime), 1, 24);
		int startMinute = Clamp(Floor(((startTime-startHour)*100)), 0, 59);
		
		int endHour = Clamp(Floor(endTime), 1, 24);
		int endMinute = Clamp(Floor(((endTime-endHour)*100)), 0, 59);
		
		bool useNew;
		bool wasNew;
		
		int h; int m; int s;
		while(true){
			h = DayNight[_DN_HOUR];
			m = DayNight[_DN_MINUTE];
			s = DayNight[_DN_SECOND];
			if(DayNight_GetTimeDifference(h, m, s, startHour, startMinute, 0)>0&&DayNight_GetTimeDifference(h, m, s, endHour, endMinute, 0)<0){
				useNew = true;
			}
			else{
				useNew = false;
			}
			
			if(useNew&&!wasNew){
				if(tileOrSideWarp){
					Screen->SetSideWarp(warpID, newScreen, newDMap, Screen->GetSideWarpType(warpID));
				}
				else{
					Screen->SetTileWarp(warpID, newScreen, newDMap, Screen->GetTileWarpType(warpID));
				}
				wasNew = true;
			}
			else if(!useNew&&wasNew){
				if(tileOrSideWarp){
					Screen->SetSideWarp(warpID, startingScreen, startingDMap, Screen->GetSideWarpType(warpID));
				}
				else{
					Screen->SetTileWarp(warpID, startingScreen, startingDMap, Screen->GetTileWarpType(warpID));
				}
				wasNew = false;
			}
			
			Waitframe();
		}
	}
}

//Place down on a screen to trigger screen secrets based on the time of day
//D0: Starting time for the secret (decimal places are used for minutes)
//D1: Ending time for the secret (decimal places are used for minutes)
//D2: Set to 1 if the secret is permanent
//D3: Sound to play when the secret triggers
ffc script DayNight_TriggerSecrets{
	void run(int startTime, int endTime, int perm, int sfx){
		int h = DayNight[_DN_HOUR];
		int m = DayNight[_DN_MINUTE];
		int s = DayNight[_DN_SECOND];
		
		int startHour = Clamp(Floor(startTime), 1, 24);
		int startMinute = Clamp(Floor(((startTime-startHour)*100)), 0, 59);
		
		int endHour = Clamp(Floor(endTime), 1, 24);
		int endMinute = Clamp(Floor(((endTime-endHour)*100)), 0, 59);
		
		bool triggered;
		if(DayNight_GetTimeDifference(h, m, s, startHour, startMinute, 0)>0&&DayNight_GetTimeDifference(h, m, s, endHour, endMinute, 0)<0){
			triggered = true;
		}
		else{
			triggered = false;
		}
		
		if(triggered){
			Screen->TriggerSecrets();
			if(perm)
				Screen->State[ST_SECRET] = true;
			Quit();
		}
		
		while(true){
			h = DayNight[_DN_HOUR];
			m = DayNight[_DN_MINUTE];
			s = DayNight[_DN_SECOND];
			
			if(DayNight_GetTimeDifference(h, m, s, startHour, startMinute, 0)>0&&DayNight_GetTimeDifference(h, m, s, endHour, endMinute, 0)<0){
				triggered = true;
			}
			else{
				triggered = false;
			}
			
			if(triggered){
			Screen->TriggerSecrets();
			if(perm)
				Screen->State[ST_SECRET] = true;
			if(sfx>0)
				Game->PlaySound(sfx);
			Quit();
		}
			
			Waitframe();
		}
	}
}

//This script sets the clock to a certain time when you enter the screen, for use in cutscenes
//D0: Hour
//D1: Minute
//D2: Second
ffc script DayNight_SetTime{
	void run(int hours, int minutes, int seconds){
		DayNight[_DN_HOUR] = Clamp(hours, 1, 24);
		DayNight[_DN_MINUTE] = Clamp(minutes, 0, 59);
		DayNight[_DN_SECOND] = Clamp(seconds, 0, 59);
	}
}