1 #include "Timer_Control.h"
2 
3 #include "ContentManager.h"
4 #include "Debug.h"
5 #include "GameInstance.h"
6 #include "GamePolicy.h"
7 #include "Handle_Items.h"
8 #include "MapScreen.h"
9 #include "Overhead.h"
10 #include "Soldier_Control.h"
11 #include "WorldDef.h"
12 
13 #include <SDL.h>
14 #include <stdexcept>
15 
16 
17 INT32	giClockTimer = -1;
18 INT32	giTimerDiag  =  0;
19 
20 UINT32 guiBaseJA2Clock = 0;
21 
22 static BOOLEAN gfPauseClock = FALSE;
23 
24 const INT32 giTimerIntervals[NUMTIMERS] =
25 {
26 	5, // Tactical Overhead
27 	20, // NEXTSCROLL
28 	200, // Start Scroll
29 	200, // Animate tiles
30 	1000, // FPS Counter
31 	80, // PATH FIND COUNTER
32 	150, // CURSOR TIMER
33 	300, // RIGHT CLICK FOR MENU
34 	300, // LEFT
35 	300, // MIDDLE
36 	200, // TARGET REFINE TIMER
37 	150, // CURSOR/AP FLASH
38 	20, // PHYSICS UPDATE
39 	100, // FADE ENEMYS
40 	20, // STRATEGIC OVERHEAD
41 	40, // CYCLE TIME RENDER ITEM COLOR
42 	500, // NON GUN TARGET REFINE TIMER
43 	250, // IMPROVED CURSOR FLASH
44 	500, // 2nd CURSOR FLASH
45 	400, // RADARMAP BLINK AND OVERHEAD MAP BLINK SHOUDL BE THE SAME
46 	10  // Music Overhead
47 };
48 
49 // TIMER COUNTERS
50 INT32 giTimerCounters[NUMTIMERS];
51 
52 INT32 giTimerCustomizable       = 0;
53 INT32 giTimerTeamTurnUpdate     = 0;
54 
55 CUSTOMIZABLE_TIMER_CALLBACK gpCustomizableTimerCallback = 0;
56 
57 // Clock Callback event ID
58 static SDL_TimerID g_timer;
59 
60 
61 extern UINT32 guiCompressionStringBaseTime;
62 extern INT32  giFlashHighlightedItemBaseTime;
63 extern INT32  giCompatibleItemBaseTime;
64 extern INT32  giAnimateRouteBaseTime;
65 extern INT32  giPotHeliPathBaseTime;
66 extern UINT32 guiSectorLocatorBaseTime;
67 extern INT32  giCommonGlowBaseTime;
68 extern INT32  giFlashAssignBaseTime;
69 extern INT32  giFlashContractBaseTime;
70 extern UINT32 guiFlashCursorBaseTime;
71 extern INT32  giPotCharPathBaseTime;
72 
73 
TimeProc(UINT32 const interval,void *)74 static UINT32 TimeProc(UINT32 const interval, void*)
75 {
76 	if (!gfPauseClock)
77 	{
78 		guiBaseJA2Clock += BASETIMESLICE;
79 
80 		for (UINT32 i = 0; i != NUMTIMERS; i++)
81 		{
82 			UPDATECOUNTER(i);
83 		}
84 
85 		// Update some specialized countdown timers...
86 		UPDATETIMECOUNTER(giTimerTeamTurnUpdate);
87 
88 		if (gpCustomizableTimerCallback)
89 		{
90 			UPDATETIMECOUNTER(giTimerCustomizable);
91 		}
92 
93 #ifndef BOUNDS_CHECKER
94 		if (fInMapMode)
95 		{
96 			// IN Mapscreen, loop through player's team
97 			FOR_EACH_IN_TEAM(s, OUR_TEAM)
98 			{
99 				UPDATETIMECOUNTER(s->PortraitFlashCounter);
100 				UPDATETIMECOUNTER(s->PanelAnimateCounter);
101 			}
102 		}
103 		else
104 		{
105 			// Set update flags for soldiers
106 			FOR_EACH_MERC(i)
107 			{
108 				SOLDIERTYPE* const s = *i;
109 				UPDATETIMECOUNTER(s->UpdateCounter);
110 				UPDATETIMECOUNTER(s->DamageCounter);
111 				UPDATETIMECOUNTER(s->BlinkSelCounter);
112 				UPDATETIMECOUNTER(s->PortraitFlashCounter);
113 				UPDATETIMECOUNTER(s->AICounter);
114 				UPDATETIMECOUNTER(s->FadeCounter);
115 				UPDATETIMECOUNTER(s->NextTileCounter);
116 				UPDATETIMECOUNTER(s->PanelAnimateCounter);
117 			}
118 		}
119 #endif
120 	}
121 
122 	return interval;
123 }
124 
125 
InitializeJA2Clock(void)126 void InitializeJA2Clock(void)
127 {
128 	SDL_InitSubSystem(SDL_INIT_TIMER);
129 
130 	// Init timer delays
131 	for (INT32 i = 0; i != NUMTIMERS; ++i)
132 	{
133 		giTimerCounters[i] = giTimerIntervals[i];
134 	}
135 
136 	INT32 msPerTimeSlice = gamepolicy(ms_per_time_slice);
137 	if (msPerTimeSlice <= 0)
138 	{
139 		throw std::runtime_error("ms_per_time_slice must be a positive integer");
140 	}
141 	g_timer = SDL_AddTimer(msPerTimeSlice, TimeProc, 0);
142 	if (!g_timer) throw std::runtime_error("Could not create timer callback");
143 }
144 
145 
ShutdownJA2Clock(void)146 void ShutdownJA2Clock(void)
147 {
148 	SDL_RemoveTimer(g_timer);
149 }
150 
151 
PauseTime(BOOLEAN const fPaused)152 void PauseTime(BOOLEAN const fPaused)
153 {
154 	gfPauseClock = fPaused;
155 }
156 
157 
SetCustomizableTimerCallbackAndDelay(INT32 const delay,CUSTOMIZABLE_TIMER_CALLBACK const callback,BOOLEAN const replace)158 void SetCustomizableTimerCallbackAndDelay(INT32 const delay, CUSTOMIZABLE_TIMER_CALLBACK const callback, BOOLEAN const replace)
159 {
160 	if (!replace && gpCustomizableTimerCallback)
161 	{ // Replace callback but call the current callback first
162 		gpCustomizableTimerCallback();
163 	}
164 
165 	RESETTIMECOUNTER(giTimerCustomizable, delay);
166 	gpCustomizableTimerCallback = callback;
167 }
168 
169 
CheckCustomizableTimer(void)170 void CheckCustomizableTimer(void)
171 {
172 	if (!gpCustomizableTimerCallback)             return;
173 	if (!TIMECOUNTERDONE(giTimerCustomizable, 0)) return;
174 
175 	/* Set the callback to a temp variable so we can reset the global variable
176 	 * before calling the callback, so that if the callback sets up another
177 	 * instance of the timer, we don't reset it afterwards. */
178 	CUSTOMIZABLE_TIMER_CALLBACK const callback = gpCustomizableTimerCallback;
179 	gpCustomizableTimerCallback = 0;
180 	callback();
181 }
182 
183 
ResetJA2ClockGlobalTimers(void)184 void ResetJA2ClockGlobalTimers(void)
185 {
186 	UINT32 const now = GetJA2Clock();
187 
188 	guiCompressionStringBaseTime   = now;
189 	giFlashHighlightedItemBaseTime = now;
190 	giCompatibleItemBaseTime       = now;
191 	giAnimateRouteBaseTime         = now;
192 	giPotHeliPathBaseTime          = now;
193 	guiSectorLocatorBaseTime       = now;
194 
195 	giCommonGlowBaseTime           = now;
196 	giFlashAssignBaseTime          = now;
197 	giFlashContractBaseTime        = now;
198 	guiFlashCursorBaseTime         = now;
199 	giPotCharPathBaseTime          = now;
200 }
201