1 ////////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2010 by The Allacrost Project
3 //                         All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ////////////////////////////////////////////////////////////////////////////////
9 
10 /** ****************************************************************************
11 *** \file   system.cpp
12 *** \author Tyler Olsen, roots@allacrost.org
13 *** \author Andy Gardner, chopperdave@allacrost.org
14 *** \brief  Source file for system code management
15 *** ***************************************************************************/
16 
17 #ifdef _WIN32
18 	#include <direct.h>
19 	#include <stdlib.h>          // defines _MAX_PATH constant
20 	#define PATH_MAX _MAX_PATH   // redefine _MAX_PATH to be compatible with Darwin's PATH_MAX
21 #elif defined __MACH__
22 	#include <unistd.h>
23 	#include <cstdlib>
24 #elif defined __linux__
25 	#include <limits.h>
26 #endif
27 
28 // #include "gettext.h"
29 #include <libintl.h>
30 
31 #include "system.h"
32 #include "audio.h"
33 #include "script.h"
34 
35 using namespace std;
36 
37 using namespace hoa_utils;
38 using namespace hoa_audio;
39 using namespace hoa_script;
40 using namespace hoa_mode_manager;
41 
42 template<> hoa_system::SystemEngine* Singleton<hoa_system::SystemEngine>::_singleton_reference = NULL;
43 
44 namespace hoa_system {
45 
46 SystemEngine* SystemManager = NULL;
47 bool SYSTEM_DEBUG = false;
48 
49 
50 
Translate(const string & text)51 string Translate(const string& text) {
52 	// gettext is a C library so the gettext() function takes/returns a C-style char* string
53 	return string(gettext(text.c_str()));
54 }
55 
56 
57 
UTranslate(const string & text)58 ustring UTranslate(const string& text) {
59 	return MakeUnicodeString(Translate(text));
60 }
61 
62 // -----------------------------------------------------------------------------
63 // SystemTimer Class
64 // -----------------------------------------------------------------------------
65 
SystemTimer()66 SystemTimer::SystemTimer() :
67 	_state(SYSTEM_TIMER_INVALID),
68 	_auto_update(false),
69 	_duration(0),
70 	_number_loops(0),
71 	_mode_owner(NULL),
72 	_time_expired(0),
73 	_times_completed(0)
74 {}
75 
76 
77 
SystemTimer(uint32 duration,int32 loops)78 SystemTimer::SystemTimer(uint32 duration, int32 loops) :
79 	_state(SYSTEM_TIMER_INITIAL),
80 	_auto_update(false),
81 	_duration(duration),
82 	_number_loops(loops),
83 	_mode_owner(NULL),
84 	_time_expired(0),
85 	_times_completed(0)
86 {}
87 
88 
89 
~SystemTimer()90 SystemTimer::~SystemTimer() {
91 	if (_auto_update == true) {
92 		SystemManager->RemoveAutoTimer(this);
93 	}
94 }
95 
96 
97 
Initialize(uint32 duration,int32 number_loops)98 void SystemTimer::Initialize(uint32 duration, int32 number_loops) {
99 	_state = SYSTEM_TIMER_INITIAL;
100 	_duration = duration;
101 	_number_loops = number_loops;
102 	_time_expired = 0;
103 	_times_completed = 0;
104 }
105 
106 
107 
EnableAutoUpdate(GameMode * owner)108 void SystemTimer::EnableAutoUpdate(GameMode* owner) {
109 	if (_auto_update == true) {
110 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "timer already had auto update enabled" << endl;
111 		return;
112 	}
113 
114 	_auto_update = true;
115 	_mode_owner = owner;
116 	SystemManager->AddAutoTimer(this);
117 }
118 
119 
120 
EnableManualUpdate()121 void SystemTimer::EnableManualUpdate() {
122 	if (_auto_update == false) {
123 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "timer was already in manual update mode" << endl;
124 		return;
125 	}
126 
127 	SystemManager->RemoveAutoTimer(this);
128 	_auto_update = false;
129 	_mode_owner = NULL;
130 }
131 
132 
133 
Update()134 void SystemTimer::Update() {
135 	Update(SystemManager->GetUpdateTime());
136 }
137 
138 
139 
Update(uint32 time)140 void SystemTimer::Update(uint32 time) {
141 	if (_auto_update == true) {
142 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "update failed because timer is in automatic update mode" << endl;
143 		return;
144 	}
145 	if (IsRunning() == false) {
146 		return;
147 	}
148 
149 	_UpdateTimer(time);
150 }
151 
152 
153 
PercentComplete() const154 float SystemTimer::PercentComplete() const {
155 	switch (_state) {
156 		case SYSTEM_TIMER_INITIAL:
157 			return 0.0f;
158 		case SYSTEM_TIMER_RUNNING:
159 		case SYSTEM_TIMER_PAUSED:
160 			return static_cast<float>(_time_expired) / static_cast<float>(_duration);
161 		case SYSTEM_TIMER_FINISHED:
162 			return 1.0f;
163 		default:
164 			return 0.0f;
165 	}
166 }
167 
168 
169 
SetDuration(uint32 duration)170 void SystemTimer::SetDuration(uint32 duration) {
171 	if (IsInitial() == false) {
172 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "function called when the timer was not in the initial state" << endl;
173 		return;
174 	}
175 
176 	_duration = duration;
177 }
178 
179 
180 
SetNumberLoops(int32 loops)181 void SystemTimer::SetNumberLoops(int32 loops) {
182 	if (IsInitial() == false) {
183 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "function called when the timer was not in the initial state" << endl;
184 		return;
185 	}
186 
187 	_number_loops = loops;
188 }
189 
190 
191 
SetModeOwner(hoa_mode_manager::GameMode * owner)192 void SystemTimer::SetModeOwner(hoa_mode_manager::GameMode* owner) {
193 	if (IsInitial() == false) {
194 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "function called when the timer was not in the initial state" << endl;
195 		return;
196 	}
197 
198 	_mode_owner = owner;
199 }
200 
201 
202 
_AutoUpdate()203 void SystemTimer::_AutoUpdate() {
204 	if (_auto_update == false) {
205 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "tried to automatically update a timer that does not have auto updates enabled" << endl;
206 		return;
207 	}
208 	if (IsRunning() == false) {
209 		return;
210 	}
211 
212 	_UpdateTimer(SystemManager->GetUpdateTime());
213 }
214 
215 
216 
_UpdateTimer(uint32 time)217 void SystemTimer::_UpdateTimer(uint32 time) {
218 	_time_expired += time;
219 
220 	if (_time_expired >= _duration) {
221 		_times_completed++;
222 
223 		// Check if infinite looping is enabled
224 		if (_number_loops < 0) {
225 			_time_expired -= _duration;
226 		}
227 		// Check if the last loop has been completed
228 		else if (_times_completed >= static_cast<uint32>(_number_loops)) {
229 			_time_expired = 0;
230 			_state = SYSTEM_TIMER_FINISHED;
231 		}
232 		// Otherwise there are still additional loops to complete
233 		else {
234 			_time_expired -= _duration;
235 		}
236 	}
237 }
238 
239 // -----------------------------------------------------------------------------
240 // SystemEngine Class
241 // -----------------------------------------------------------------------------
242 
SystemEngine()243 SystemEngine::SystemEngine() {
244 	IF_PRINT_DEBUG(SYSTEM_DEBUG) << "constructor invoked" << endl;
245 
246 	_not_done = true;
247 	SetLanguage("en"); //Default language is English
248 }
249 
250 
251 
~SystemEngine()252 SystemEngine::~SystemEngine() {
253 	IF_PRINT_DEBUG(SYSTEM_DEBUG) << "destructor invoked" << endl;
254 }
255 
256 
257 
SingletonInitialize()258 bool SystemEngine::SingletonInitialize() {
259 	// Initialize the gettext library
260 	setlocale(LC_ALL, "");
261 	setlocale(LC_NUMERIC, "C");
262 
263 	#if defined(_WIN32) || defined(__MACH__)
264 		char buffer[PATH_MAX];
265 		// Get the current working directory.
266 		string cwd(getcwd(buffer, PATH_MAX));
267 		cwd.append("/translations/");
268 		bindtextdomain("allacrost", cwd.c_str());
269 		bind_textdomain_codeset("allacrost", "UTF-8");
270 		textdomain("allacrost");
271 	#elif (defined(__linux__) || defined(__FreeBSD__)) && !defined(RELEASE_BUILD)
272 		// Look for translation files in LOCALEDIR only if they are not available in the
273 		// current directory.
274 		if (!ifstream("dat/config/settings.lua")) {
275 			bindtextdomain(PACKAGE, LOCALEDIR);
276 			bind_textdomain_codeset(PACKAGE, "UTF-8");
277 			textdomain(PACKAGE);
278 		}
279 		else {
280 			char buffer[PATH_MAX];
281 			// Get the current working directory.
282 			string cwd(getcwd(buffer, PATH_MAX));
283 			cwd.append("/txt/");
284 			bindtextdomain(PACKAGE, cwd.c_str());
285 			bind_textdomain_codeset(PACKAGE, "UTF-8");
286 			textdomain(PACKAGE);
287 		}
288 	#else
289 		bindtextdomain(PACKAGE, LOCALEDIR);
290 		bind_textdomain_codeset(PACKAGE, "UTF-8");
291 		textdomain(PACKAGE);
292 	#endif
293 
294 	// Called here to set the default English language to use nice quote characters.
295 	SetLanguage("en@quot");
296 
297 	return true;
298 }
299 
300 
301 
InitializeTimers()302 void SystemEngine::InitializeTimers() {
303 	_last_update = SDL_GetTicks();
304 	_update_time = 1; // Set to non-zero, otherwise bad things may happen...
305 	_hours_played = 0;
306 	_minutes_played = 0;
307 	_seconds_played = 0;
308 	_milliseconds_played = 0;
309 	_auto_system_timers.clear();
310 }
311 
312 
313 
AddAutoTimer(SystemTimer * timer)314 void SystemEngine::AddAutoTimer(SystemTimer* timer) {
315 	if (timer == NULL) {
316 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "function received NULL argument" << endl;
317 		return;
318 	}
319 	if (timer->IsAutoUpdate() == false) {
320 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "timer did not have auto update feature enabled" << endl;
321 		return;
322 	}
323 
324 // 	pair<set<SystemTimer*>::iterator, bool> return_value;
325 	if (_auto_system_timers.insert(timer).second == false) {
326 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "timer already existed in auto system timer container" << endl;
327 	}
328 }
329 
330 
331 
RemoveAutoTimer(SystemTimer * timer)332 void SystemEngine::RemoveAutoTimer(SystemTimer* timer) {
333 	if (timer == NULL) {
334 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "function received NULL argument" << endl;
335 		return;
336 	}
337 	if (timer->IsAutoUpdate() == false) {
338 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "timer did not have auto update feature enabled" << endl;
339 	}
340 
341 	if (_auto_system_timers.erase(timer) == 0) {
342 		IF_PRINT_WARNING(SYSTEM_DEBUG) << "timer was not found in auto system timer container" << endl;
343 	}
344 }
345 
346 
347 
UpdateTimers()348 void SystemEngine::UpdateTimers() {
349 	// ----- (1): Update the update game timer
350 	uint32 tmp = _last_update;
351 	_last_update = SDL_GetTicks();
352 	_update_time = _last_update - tmp;
353 
354 	// ----- (2): Update the game play timer
355 	_milliseconds_played += _update_time;
356 	if (_milliseconds_played >= 1000) {
357 		_seconds_played += _milliseconds_played / 1000;
358 		_milliseconds_played = _milliseconds_played % 1000;
359 		if (_seconds_played >= 60) {
360 			_minutes_played += _seconds_played / 60;
361 			_seconds_played = _seconds_played % 60;
362 			if (_minutes_played >= 60) {
363 				_hours_played += _minutes_played / 60;
364 				_minutes_played = _minutes_played % 60;
365 			}
366 		}
367 	}
368 
369 	// ----- (3): Update all SystemTimer objects
370 	for (set<SystemTimer*>::iterator i = _auto_system_timers.begin(); i != _auto_system_timers.end(); i++)
371 		(*i)->_AutoUpdate();
372 }
373 
374 
375 
ExamineSystemTimers()376 void SystemEngine::ExamineSystemTimers() {
377 	GameMode* active_mode = ModeManager->GetTop();
378 	GameMode* timer_mode = NULL;
379 
380 	for (set<SystemTimer*>::iterator i = _auto_system_timers.begin(); i != _auto_system_timers.end(); i++) {
381 		timer_mode = (*i)->GetModeOwner();
382 		if (timer_mode == NULL)
383 			continue;
384 
385 		if (timer_mode == active_mode)
386 			(*i)->Run();
387 		else
388 			(*i)->Pause();
389 	}
390 }
391 
392 
393 
SetLanguage(std::string lang)394 void SystemEngine::SetLanguage(std::string lang) {
395 	_language = lang;
396 
397 	/// @TODO, implement a cross-platform wrapper for setenv in utils code
398 	#ifdef _WIN32
399 		SetEnvironmentVariable("LANGUAGE", _language.c_str());
400 	#else
401 		setenv("LANGUAGE", _language.c_str(), 1);
402 	#endif
403 }
404 
405 
406 
WaitForThread(Thread * thread)407 void SystemEngine::WaitForThread(Thread * thread) {
408 #if (THREAD_TYPE == SDL_THREADS)
409 	SDL_WaitThread(thread, NULL);
410 #endif
411 }
412 
413 
414 
CreateSemaphore(int max)415 Semaphore * SystemEngine::CreateSemaphore(int max) {
416 #if (THREAD_TYPE == SDL_THREADS)
417 	return SDL_CreateSemaphore(max);
418 #endif
419 }
420 
421 
422 
DestroySemaphore(Semaphore * s)423 void SystemEngine::DestroySemaphore(Semaphore * s) {
424 #if (THREAD_TYPE == SDL_THREADS)
425 	SDL_DestroySemaphore(s);
426 #endif
427 }
428 
429 
430 
LockThread(Semaphore * s)431 void SystemEngine::LockThread(Semaphore * s) {
432 #if (THREAD_TYPE == SDL_THREADS)
433 	SDL_SemWait(s);
434 #endif
435 }
436 
437 
438 
UnlockThread(Semaphore * s)439 void SystemEngine::UnlockThread(Semaphore * s) {
440 #if (THREAD_TYPE == SDL_THREADS)
441 	SDL_SemPost(s);
442 #endif
443 }
444 
445 } // namespace hoa_system
446