1 /***************************************************************************
2 						main.cpp  -  description
3 							-------------------
4 	project              : OpenCity
5 	codename             : Delphine
6 	begin                : may 28th, 2003
7 	copyright            : (C) 2003-2008 by Duong Khang NGUYEN
8 	email                : neoneurone @ gmail com
9 
10 	details              :
11 			This is a game project which targets the ultimate city
12 		simulation just like like xxxCity or something like that :)
13 
14 	$Id: main.cpp 425 2009-11-01 16:38:58Z neoneurone $
15  ***************************************************************************/
16 
17 /***************************************************************************
18  *                                                                         *
19  *   This program is free software; you can redistribute it and/or modify  *
20  *   it under the terms of the GNU General Public License as published by  *
21  *   the Free Software Foundation; either version 2 of the License, or     *
22  *   any later version.                                                    *
23  *                                                                         *
24  ***************************************************************************/
25 
26 //========================================================================
27 /**
28 	\mainpage OpenCity source code documentation
29 	\section intro Introduction
30 		OpenCity is another 3D city simulator. It's certainly not the best
31 	city simulation nor the best eye candy game out there but we love it
32 	because it's our city simulation and we can do anything we want with
33 	it.
34 
35 	\section reuse Code reuse
36 		If you are reading this page, we believe that you are interested
37 	in the tricks behind the scene. And we think that you are happy to know
38 	that our city simulation is made with portability and object oriented
39 	programming technics in mind. It means that you can reuse few parts of
40 	OpenCity source code. At the moment, you can reuse the classes
41 	AudioManager, Conf, ModelLoader, and MapGen::MapMaker without major
42 	modifications.
43 
44 	\author Duong-Khang NGUYEN (email: neoneurone gmail com)
45 	\author Frédéric RODRIGO
46 */
47 
48 // Useful enumerations
49 #include "opencity_direction.h"
50 #include "opencity_structure_type.h"
51 
52 // OpenCity headers
53 #include "main.h"
54 #include "city.h"				// The project core
55 #include "conf.h"				// Parser for .conf file
56 #include "agentpolice.h"		// MAS testing
57 #include "agentdemonstrator.h"
58 
59 // Global settings
60 #include "globalvar.h"
61 extern GlobalVar gVars;
62 
63 // Libraries headers
64 #include "SDL_image.h"
65 #include "binreloc.h"			// BinReloc routines from AutoPackage
66 #include "tinyxml.h"
67 #include "SimpleOpt.h"			// Simple command line argument parser
68 
69 // Standard headers
70 #include <cmath>				// For log10
71 #include <cstdlib>				// For getenv
72 #include <sstream>
73 #include <ctime>				// For time
74 
75 // Test XPath
76 #include "property.h"
77 #include "propertymanager2.h"
78 
79 // Test Sharp Plus Framework
80 #include "framework/System/CString.h"
81 #include "framework/System/Information/Software/CSdl.h"
82 
83 
84    /*=====================================================================*/
85    /*                           LOCAL     MACROS                          */
86    /*=====================================================================*/
87 #ifndef __WIN32__
88 	#include <sys/stat.h>		// mkdir
89 #else
90 // Win32 specifics
91 	#include <windows.h>		// MessageBox
92 	#include <shlobj.h>			// Windows shell technologies
93 	#define DATADIR "C:/Program Files"
94 	#define SYSCONFDIR DATADIR
95 #endif
96 
97 // Window's settings
98 	#define OC_WINDOW_POS_X			20
99 	#define OC_WINDOW_POS_Y			20
100 	#define OC_WINDOW_WIDTH			750
101 	#define OC_WINDOW_HEIGHT		560
102 	#define OC_WINDOW_BPP_DEFAULT	0			///< Use the current video bpp
103 	#define OC_FULLSCREEN_WIDTH		1024
104 	#define OC_FULLSCREEN_HEIGHT	768
105 
106 // Exit code. This is not an exhaustive list.
107 	#define OC_ERROR_NOT_FOUND			-1		///< Config files not found
108 	#define OC_ERROR_PARSE_CONFIG		-2		///< Config parsing error
109 	#define OC_ERROR_ARGUMENT			-3		///< Command line argument error
110 
111 	#define OC_ERROR_MEMORY				-10		///< Out of memory
112 
113 	#define OC_ERROR_SDL_INIT			-20		///< SDL initialization failed
114 	#define OC_ERROR_SDL_DOUBLEBUFFER	-21		///< Video double buffer unsupported
115 	#define OC_ERROR_SDL_ACCELERATED	-22		///< Accelerated display unsupported
116 	#define OC_ERROR_SDL_VIDEORESIZE	-23		///< Unable to resize the window
117 	#define OC_ERROR_SDL_FULLSCREEN		-24		///< Unable to go fullscreen
118 	#define OC_ERROR_SDL_OPENGL			-25		///< Unable to load OpenGL library dynamically
119 
120 // Settings file
121 	#define OC_CONFIG_FILE_FILENAME		"config/opencity.xml"
122 
123 // Others macros
124 	#define OC_WINDOW_NAME PACKAGE VERSION
125 	#define OC_PROGRAM_NAME				"OpenCity standalone/client application"
126 
127 
128 
129    /*=====================================================================*/
130    /*                         LOCAL    VARIABLES                          */
131    /*=====================================================================*/
132 /// The current user interface is pointed by this pointer
133 	static UI* uipCurrentUI		= NULL;
134 
135 /// Set to true when the user request to quit the program
136 	static bool bQuit			= false;
137 	static bool bRestart		= false;
138 
139 /// Flags we will pass into SDL_SetVideoMode.
140 	static int iVideoFlag		= SDL_OPENGL;
141 
142 /// The paths are static so that the others can not access this
143 	static string sDataDir		= "";
144 	static string sSaveDir		= "";
145 	static string sConfigDir	= "";
146 
147 /// Set to true if OpenGL version string is requested from command line
148 	static bool bGLVersion		= false;
149 
150 
151    /*=====================================================================*/
ocQuit(const int quit_code)152 void ocQuit( const int quit_code )
153 {
154 	cout << endl
155 		 << "Quit requested, quit code is : " << quit_code
156 	     << endl
157 	     << "Bye bye !"
158 	     << endl;
159 	bQuit = true;
160 }
161 
162 
163    /*=====================================================================*/
ocRestart()164 void ocRestart()
165 {
166 	cout << "Restart with a new city from scratch. " << endl;
167 	bRestart = true;
168 }
169 
170 
171    /*=====================================================================*/
ocSetNewUI(UI * pcNewUI)172 void ocSetNewUI( UI * pcNewUI)
173 {
174 	uipCurrentUI = pcNewUI;
175 }
176 
177 
178    /*=====================================================================*/
ocKeyboard(const SDL_KeyboardEvent & rcEvent)179 void ocKeyboard( const SDL_KeyboardEvent& rcEvent )
180 {
181 	if (uipCurrentUI != NULL) {
182 		uipCurrentUI->Keyboard( rcEvent );
183 	}
184 }
185 
186 
187    /*=====================================================================*/
ocMouseButton(const SDL_MouseButtonEvent & rcEvent)188 void ocMouseButton( const SDL_MouseButtonEvent& rcEvent )
189 {
190 	if (uipCurrentUI != NULL) {
191 		uipCurrentUI->MouseButton( rcEvent );
192 	}
193 }
194 
195 
196    /*=====================================================================*/
ocMouseMotion(const SDL_MouseMotionEvent & motionEvent)197 void ocMouseMotion( const SDL_MouseMotionEvent& motionEvent )
198 {
199 	if (uipCurrentUI != NULL) {
200 		uipCurrentUI->MouseMotion( motionEvent );
201 	}
202 }
203 
204 
205    /*=====================================================================*/
ocResize(const SDL_ResizeEvent & rcsResizeEvent)206 void ocResize( const SDL_ResizeEvent& rcsResizeEvent)
207 {
208 #ifndef __WIN32__
209 // Linux needs this whereas Win32 does not
210 // Set the new window's size
211 	if( SDL_SetVideoMode(
212 		rcsResizeEvent.w, rcsResizeEvent.h,
213 		gVars.guiVideoBpp, iVideoFlag ) == 0 ) {
214 		OPENCITY_FATAL( "Video mode reset failed: " << SDL_GetError( ) );
215 		exit( OC_ERROR_SDL_VIDEORESIZE );
216 	}
217 	gVars.gpVideoSrf = SDL_GetVideoSurface();
218 #endif
219 
220 // Save the new screen size
221 	gVars.guiScreenWidth = rcsResizeEvent.w;
222 	gVars.guiScreenHeight = rcsResizeEvent.h;
223 
224 	if (uipCurrentUI != NULL) {
225 		uipCurrentUI->Resize( rcsResizeEvent );
226 	}
227 }
228 
229 
230    /*=====================================================================*/
ocActive(const SDL_ActiveEvent & e)231 void ocActive( const SDL_ActiveEvent & e)
232 {
233 //	OPENCITY_DEBUG( "Active event received" );
234 
235 	if (e.state & SDL_APPACTIVE) {
236 		gVars.gboolActive = (e.gain == 1);
237 	}
238 }
239 
240 
241    /*=====================================================================*/
ocExpose(const SDL_ExposeEvent & rcsExposeEvent)242 void ocExpose( const SDL_ExposeEvent& rcsExposeEvent )
243 {
244 	if (uipCurrentUI != NULL) {
245 		uipCurrentUI->Expose( rcsExposeEvent );
246 	}
247 }
248 
249 
250    /*=====================================================================*/
ocProcessSDLEvents(void)251 void ocProcessSDLEvents( void )
252 {
253 	static SDL_Event event;
254 
255 // Grab all the events off the queue.
256 	while( SDL_PollEvent( &event ) ) {
257 
258 		switch( event.type ) {
259 		case SDL_KEYDOWN:
260 		case SDL_KEYUP:
261 			ocKeyboard( event.key );
262 			break;
263 
264 		case SDL_MOUSEMOTION:
265 			ocMouseMotion( event.motion );
266 			break;
267 
268 		case SDL_MOUSEBUTTONDOWN:
269 		case SDL_MOUSEBUTTONUP:
270 			ocMouseButton( event.button );
271 			break;
272 
273 		case SDL_VIDEORESIZE:
274 			ocResize( event.resize );
275 			break;
276 
277 		case SDL_ACTIVEEVENT:
278 			ocActive( event.active );
279 			break;
280 
281 		case SDL_VIDEOEXPOSE:
282 			ocExpose( event.expose );
283 			break;
284 
285 		case SDL_QUIT:
286 		// Handle quit requests (like Ctrl-c).
287 			cout << endl << "Quit requested, stoping " << OC_PROGRAM_NAME << "..." << endl;
288 			bQuit = true;
289 			break;
290 		}
291 	}
292 }
293 
294 
295    /*=====================================================================*/
initSDL()296 static int initSDL()
297 {
298 // Initialization of the SDL library
299 	OPENCITY_DEBUG( "SDL Initialization" );
300 
301 // Test Sharp Plus Framework
302 	OPENCITY_INFO( "SDL compile-time version: " << System::Information::Software::Sdl::GetCompiletimeVersion() );
303 	OPENCITY_INFO( "SDL run-time version: " << System::Information::Software::Sdl::GetRuntimeVersion() );
304 
305 // First, initialize SDL's video subsystem.
306 	if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
307 		// Failed, exit.
308 		OPENCITY_FATAL( "SDL video initialization failed: " << SDL_GetError() );
309 		return OC_ERROR_SDL_INIT;
310 	}
311 
312 // Set the window's caption
313 	SDL_WM_SetCaption( PACKAGE " " VERSION, NULL );
314 	SDL_WM_SetIcon( IMG_Load(ocDataDirPrefix("graphism/icon/OpenCity32.png").c_str()), NULL );
315 
316 // Set the SDL_GL_DOUBLEBUFFER attribute for smoother rendering
317 	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
318 
319 // Set the SDL_GL_ACCELERATED_VISUAL attribute if enabled
320 // Note: This can lead to software rendering on Windows system with recent ATI Catalyst driver.
321 	if (gVars.gboolAcceleratedVisual == true)
322 	{
323 		SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
324 	}
325 
326 // Get the OpenGL driver name
327 	const char* glDriver;
328 	if (gVars.gsOpenGLDriver != "") {
329 		OPENCITY_INFO( "Loading OpenGL driver: " << gVars.gsOpenGLDriver );
330 		glDriver = gVars.gsOpenGLDriver.c_str();
331 	}
332 	else {
333 		OPENCITY_INFO( "Loading default OpenGL driver..." );
334 		glDriver = NULL;
335 	}
336 
337 // Dynamically load the default OpenGL implementation library
338 	if (SDL_GL_LoadLibrary(glDriver) < 0) {
339 		OPENCITY_FATAL( "Failed to load OpenGL library: " << SDL_GetError() );
340 		return OC_ERROR_SDL_OPENGL;
341 	}
342 
343 // Will we go for fullscreen ?
344 	if (gVars.gboolFullScreen == true) {
345 		iVideoFlag |= SDL_FULLSCREEN;
346 
347 	// Use the current desktop video resolution
348 		gVars.guiScreenWidth	= 0;
349 		gVars.guiScreenHeight	= 0;
350 	}
351 	else {
352 		iVideoFlag |= SDL_RESIZABLE;
353 	}
354 
355 // OK, go for the video settings now
356 	gVars.gpVideoSrf = SDL_SetVideoMode( gVars.guiScreenWidth, gVars.guiScreenHeight, gVars.guiVideoBpp, iVideoFlag );
357 	if ( gVars.gpVideoSrf == NULL ) {
358 	// This could happen for a variety of reasons, including DISPLAY
359 	// not being set, the specified resolution not being available, etc.
360 		OPENCITY_ERROR(
361 			"Initialization of " << gVars.guiVideoBpp <<
362 			" bpp video mode failed: " << SDL_GetError()
363 		);
364 		return OC_ERROR_SDL_INIT;
365 	}
366 	else {
367 		OPENCITY_INFO(
368 			"Using " << (uint)gVars.gpVideoSrf->w <<
369 			"x" << (uint)gVars.gpVideoSrf->h <<
370 			" at " << (uint)gVars.gpVideoSrf->format->BitsPerPixel << " bpp"
371 		);
372 
373 	// Store the fullscreen resolution for later use
374 		if (gVars.gboolFullScreen == true) {
375 			gVars.guiScreenWidth	= (uint)gVars.gpVideoSrf->w;
376 			gVars.guiScreenHeight	= (uint)gVars.gpVideoSrf->h;
377 		}
378 	}
379 
380 // Retrieve the video driver name
381 	#define BUFFER_SIZE 256
382 	char myBuffer[BUFFER_SIZE];
383 	if (SDL_VideoDriverName(myBuffer, BUFFER_SIZE) != NULL) {
384 		OPENCITY_INFO( "Current video driver: " << myBuffer );
385 	}
386 	else {
387 		OPENCITY_ERROR( "Failed to retrieve the video driver name" );
388 	}
389 
390 // Display the OpenGL version string
391 	if (bGLVersion == true) {
392 		OPENCITY_INFO( "GL vendor: "	 << glGetString( GL_VENDOR ) );
393 		OPENCITY_INFO( "GL renderer: "	 << glGetString( GL_RENDERER ) );
394 		OPENCITY_INFO( "GL version: "	 << glGetString( GL_VERSION ) );
395 		OPENCITY_INFO( "GL extensions: " << glGetString( GL_EXTENSIONS ) );
396 	}
397 
398 // Is doublebuffer feature available ?
399 	int iValue = 0;
400 	SDL_GL_GetAttribute( SDL_GL_DOUBLEBUFFER, &iValue );
401 	if ( iValue == 0 ) {
402 		OPENCITY_FATAL( "Video double buffer unsupported" );
403 		return OC_ERROR_SDL_DOUBLEBUFFER;
404 	}
405 	else {
406 		OPENCITY_INFO( "Video double buffer supported" );
407 	}
408 
409 // Is GL accelerated display available ?
410 	if (gVars.gboolAcceleratedVisual == true)
411 	{
412 		SDL_GL_GetAttribute( SDL_GL_ACCELERATED_VISUAL, &iValue );
413 		if ( iValue == 0 ) {
414 			OPENCITY_FATAL( "Accelerated visual unsupported" );
415 			return OC_ERROR_SDL_ACCELERATED;
416 		}
417 		else {
418 			OPENCITY_INFO( "Accelerated visual supported" );
419 		}
420 	}
421 
422 	return 0;
423 }
424 
425 
426    /*=====================================================================*/
formatPath(const string & rcsPath)427 static string formatPath(const string& rcsPath)
428 {
429 	string result = rcsPath;
430 
431 	if (result.size() > 0) {
432 	// Delete all quotes "
433 		string::size_type pos;
434 		while ( (pos = result.find( '\"' )) != result.npos ) {
435 		    result.erase( pos );
436 		}
437 	// Append the "/" to path
438 		if (result[ result.size()-1 ] != '/')
439 			result += '/';
440 	}
441 	else {
442 		result = "/";
443 	}
444 
445 	return result;
446 }
447 
448 
449    /*=====================================================================*/
parseArg(int argc,char * argv[])450 static int parseArg(int argc, char *argv[])
451 {
452 // Command-line options definition
453 	enum {
454 		OPT_GL_VERSION,
455 		OPT_GL_DRIVER,
456 		OPT_FULL_SCREEN,
457 		OPT_NO_AUDIO,
458 		OPT_DATA_DIR,
459 		OPT_CONF_DIR,
460 		OPT_GENERATOR_HEIGHT_MAP,
461 		OPT_GENERATOR_SEED,
462 		OPT_GENERATOR_MAP,
463 		OPT_GENERATOR_WATER,
464 		OPT_GENERATOR_MAP_SHAPE,
465 		OPT_GENERATOR_TREE_DENSITY,
466 		OPT_HELP
467 	};
468 
469 	CSimpleOpt::SOption g_rgOptions[] = {
470 		{ OPT_GL_VERSION,				(char*)"--gl-version",				SO_NONE		},
471 		{ OPT_GL_VERSION,				(char*)"-glv",						SO_NONE		},
472 		{ OPT_GL_DRIVER,				(char*)"--gl-driver",				SO_REQ_SEP	},
473 		{ OPT_GL_DRIVER,				(char*)"-gld",						SO_REQ_SEP	},
474 		{ OPT_FULL_SCREEN,				(char*)"--full-screen",				SO_NONE		},
475 		{ OPT_FULL_SCREEN,				(char*)"-fs",						SO_NONE		},
476 		{ OPT_NO_AUDIO,					(char*)"--no-audio",				SO_NONE		},
477 		{ OPT_NO_AUDIO,					(char*)"-na",						SO_NONE		},
478 		{ OPT_DATA_DIR,					(char*)"--data-dir",				SO_REQ_SEP	},
479 		{ OPT_DATA_DIR,					(char*)"-dd",						SO_REQ_SEP	},
480 		{ OPT_CONF_DIR,					(char*)"--conf-dir",				SO_REQ_SEP	},
481 		{ OPT_CONF_DIR,					(char*)"-cd",						SO_REQ_SEP	},
482 		{ OPT_GENERATOR_HEIGHT_MAP,		(char*)"--generator-height-map",	SO_REQ_SEP	},
483 		{ OPT_GENERATOR_SEED,			(char*)"--generator-seed",			SO_REQ_SEP	},
484 		{ OPT_GENERATOR_MAP,			(char*)"--generator-map",			SO_REQ_SEP	},
485 		{ OPT_GENERATOR_WATER,			(char*)"--generator-water",			SO_REQ_SEP	},
486 		{ OPT_GENERATOR_MAP_SHAPE,		(char*)"--generator-map-shape",		SO_REQ_SEP	},
487 		{ OPT_GENERATOR_TREE_DENSITY,	(char*)"--generator-tree-density",	SO_REQ_SEP	},
488 		{ OPT_HELP,						(char*)"--help",					SO_NONE		},
489 		{ OPT_HELP,						(char*)"-h",						SO_NONE		},
490 		SO_END_OF_OPTIONS // END
491 	};
492 
493 // SimpleOpt parser initialization
494 	CSimpleOpt args(argc, argv, g_rgOptions, SO_O_EXACT | SO_O_NOSLASH | SO_O_SHORTARG | SO_O_CLUMP );
495 	int i = 0;
496 	while (args.Next()) {
497 		switch (args.LastError()) {
498 		case SO_OPT_INVALID:
499 			OPENCITY_OPTION( "" << args.OptionText() << " unrecognized" );
500 			break;
501 		case SO_OPT_MULTIPLE:
502 			OPENCITY_OPTION( "" << args.OptionText() << " matched multiple options" );
503 			break;
504 		case SO_ARG_INVALID:
505 			OPENCITY_OPTION( "" << args.OptionText() << " does not accept any argument" );
506 			break;
507 		case SO_ARG_INVALID_TYPE:
508 			OPENCITY_OPTION( "" << args.OptionText() << " has an invalid argument format" );
509 			break;
510 		case SO_ARG_MISSING:
511 			OPENCITY_OPTION( "" << args.OptionText() << " requires an argument" );
512 			break;
513 		case SO_ARG_INVALID_DATA:
514 			OPENCITY_OPTION( "" << args.OptionText() << " has an invalid argument data" );
515 			break;
516 		case SO_SUCCESS:
517 			OPENCITY_OPTION( "" << args.OptionText() << " detected" );
518 			break;
519 		} // switch (args.LastError())
520 
521 		// Exit the program on error
522 		if (args.LastError() != SO_SUCCESS) {
523 			OPENCITY_OPTION( "Try " << argv[0] << " --help for more usage information" );
524 			exit( OC_ERROR_ARGUMENT );
525 		}
526 
527 		switch (args.OptionId()) {
528 		case OPT_GL_VERSION:
529 			bGLVersion = true;
530 			break;
531 
532 		case OPT_GL_DRIVER:
533 			gVars.gsOpenGLDriver = args.OptionArg();
534 			break;
535 
536 		case OPT_FULL_SCREEN:
537 			gVars.gboolFullScreen = true;
538 			break;
539 
540 		case OPT_NO_AUDIO:
541 			gVars.gboolUseAudio = false;
542 			break;
543 
544 		case OPT_DATA_DIR:
545 			sDataDir = formatPath(args.OptionArg());
546 			OPENCITY_OPTION( "The data directory is: \"" << sDataDir << "\"" );
547 			break;
548 
549 		case OPT_CONF_DIR:
550 			sConfigDir = formatPath(args.OptionArg());
551 			OPENCITY_OPTION( "The configuration directory is: \"" << sConfigDir << "\"" );
552 			break;
553 
554 		case OPT_GENERATOR_HEIGHT_MAP:
555 			gVars.gsGeneratorHeightMap = args.OptionArg();
556 			break;
557 
558 		case OPT_GENERATOR_SEED:
559 			i = atoi( args.OptionArg() ); // return 0 as error value
560 			if (i != 0 || ( i == 0 && strcmp(args.OptionArg(), "0") == 0 )) {
561 				gVars.guiGeneratorSeed = i;
562 			}
563 			else {
564 				OPENCITY_INFO(
565 					"Argument provided to --generator-seed must be an integer. The default value is used instead."
566 				);
567 			}
568 			break;
569 
570 		case OPT_GENERATOR_MAP:
571 			i = atoi( args.OptionArg() ); // return 0 as error value
572 			if (i != 0 || ( i == 0 && strcmp(args.OptionArg(), "0") == 0 )) {
573 				gVars.guiGeneratorMapType = MapGen::MapMaker::MAP_TYPE(i);
574 			}
575 			else {
576 				OPENCITY_INFO(
577 					"Argument provided to --generator-map must be an integer. The default value is used instead."
578 				);
579 			}
580 			break;
581 
582 		case OPT_GENERATOR_WATER:
583 			i = atoi( args.OptionArg() ); // return 0 as error value
584 			if (i != 0 || ( i == 0 && strcmp(args.OptionArg(), "0") == 0 )) {
585 				gVars.guiGeneratorWaterType = MapGen::MapMaker::WATER_TYPE(i);
586 			}
587 			else {
588 				OPENCITY_INFO(
589 					"Argument provided to --generator-water must be an integer. The default value is used instead." );
590 			}
591 			break;
592 
593 		case OPT_GENERATOR_MAP_SHAPE:
594 			i = atoi( args.OptionArg() ); // return 0 as error value
595 			if (i != 0 || ( i == 0 && strcmp(args.OptionArg(), "0") == 0 )) {
596 				gVars.guiGeneratorMapShapeType = MapGen::MapMaker::MAP_SHAPE_TYPE(i);
597 			}
598 			else {
599 				OPENCITY_INFO(
600 					"Argument provided to --generator-map-shape must be an integer. The default value is used instead."
601 				);
602 			}
603 			break;
604 
605 		case OPT_GENERATOR_TREE_DENSITY:
606 			i = atoi( args.OptionArg() ); // return 0 as error value
607 			if (i != 0 || ( i == 0 && strcmp(args.OptionArg(), "0") == 0 )) {
608 				gVars.guiGeneratorTreeDensityType = MapGen::MapMaker::TREE_DENSITY_TYPE(i);
609 			}
610 			else {
611 				OPENCITY_INFO(
612 					"Argument provided to --generator-tree-density must be an integer. The default value is used instead."
613 				);
614 			}
615 			break;
616 
617 		case OPT_HELP:
618 			cout << "Usage: " << argv[0]
619 				<< " [-fs|--full-screen] [-glv|--gl-version] [-gld|--gl-driver openGLDriverName]"
620 				<< " [-dd|--data-dir newDataPath] [-cd|--conf-dir newConfigPath]"
621 				<< " [-na|--no-audio] [--generator-height-map heightMapPicture |"
622 				<< " (--generator-seed seed [--generator-map MAP-TYPE] [--generator-water WATER-TYPE]"
623 				<< " [--generator-map-shape MAP-SHAPE-TYPE] [--generator-tree-density TREE-DENSITY-TYPE])]"
624 				<< endl << endl
625 				<< "Where the map generator constants are: " << endl
626 				<< "   MAP-TYPE         : 0=plain (default), 1=hill, 2=mountain" << endl
627 				<< "   TREE-DENSITY-TYPE: 0=sparse (default), 1=normal, 2=dense" << endl
628 				<< "   MAP-SHAPE-TYPE   : 0=none (default), 1=island, 2=volcano, 3=crater" << endl
629 				<< "   WATER-TYPE       : 0=dry, 1=lake (default), 2=coast" << endl
630 				<< endl;
631 			cout << "Warning: the command option overwrite the config file settings."
632 				<< endl;
633 			exit( OC_ERROR_ARGUMENT );
634 			break;
635 		}	// switch (args.OptionId())
636 	} // while (args.Next())
637 
638 	return 0;
639 }
640 
641 
642    /*=====================================================================*/
displaySplash()643 static void displaySplash()
644 {
645 	#define OC_SPLASH_CLEAR_COLOR		.15, .4, .25, 1.0
646 
647 	glClearColor( OC_SPLASH_CLEAR_COLOR );
648 	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
649 	gVars.gpRenderer->DisplaySplash();
650 }
651 
652 
653    /*=====================================================================*/
displayStatus(const string & str)654 static void displayStatus( const string & str )
655 {
656 	assert( gVars.gpRenderer != NULL );
657 
658 	uint x, y;
659 
660 	displaySplash();
661 
662 // Center the text on the screen
663 	x = (gVars.gpVideoSrf->w - str.size()*10)/2;
664 	y = (gVars.gpVideoSrf->h - 140) / 2;
665 	gVars.gpRenderer->DisplayText( x, y, OC_BLUE_COLOR, str );
666 	SDL_GL_SwapBuffers();
667 }
668 
669 
670    /*=====================================================================*/
clientMode()671 static int clientMode()
672 {
673 // Initialize SDL
674 	if (gVars.gpVideoSrf == NULL) {
675 		int errorCode = initSDL();
676 		if (errorCode != 0) {
677 			return errorCode;
678 		}
679 	}
680 
681 
682 // Create the mutex first
683 	gVars.gpmutexSim = SDL_CreateMutex();
684 
685 
686 // Load OpenGL extensions
687 	gVars.gpExtensionMgr = new ExtensionManager();
688 	if (gVars.gpExtensionMgr == NULL or !gVars.gpExtensionMgr->Load()) {
689 		OPENCITY_FATAL( "Failed to load OpenGL extensions" );
690 		SDL_Quit();
691 
692 #ifdef __WIN32__
693 		MessageBox(
694 			NULL,
695 			"Failed to load OpenGL extensions. Please start a new \
696 thread about your errror in the forum at http://www.opencity.info. Don't \
697 forget to include the output from stdout.txt and stderr.txt files. They're \
698 located in OpenCity executable directory.",
699 			"OpenGL extensions loading error",
700 			MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_APPLMODAL
701 		);
702 #endif
703 
704 		return OC_ERROR_SDL_OPENGL;
705 	}
706 
707 
708 // Create the global renderer in order to use its text rendering functions
709 	gVars.gpRenderer = new Renderer( gVars.guiCityWidth, gVars.guiCityLength );
710 
711 
712 // AudioManager's initialization
713 	displayStatus( "Looking for GPU freezing system... ");
714 	gVars.gpAudioMgr = new AudioManager();
715 
716 	if ( gVars.gpAudioMgr == NULL ) {
717 		OPENCITY_FATAL( "Error while creating the audio manager" );
718 		return OC_ERROR_MEMORY;
719 	} else
720 	if ( (gVars.gboolUseAudio == true)
721 	  and (gVars.gpAudioMgr->OpenAudio() != OC_ERR_FREE))
722 	{
723 	// try to open the audio device IF we have successfully created an audio object
724 		OPENCITY_INFO( "Audio open error ! OpenCity continues happily." );
725 	}
726 
727 
728 // Load musics and sounds
729 	displayStatus( "Warming up central processing unit...");
730 	gVars.gpAudioMgr->LoadMusicList( ocDataDirPrefix(OC_MUSIC_LIST_FILENAME), ocDataDirPrefix("") );
731 	OPENCITY_INFO( "Loaded " << gVars.gpAudioMgr->GetNumberMusic() << " musics." );
732 	gVars.gpAudioMgr->LoadSoundList( ocDataDirPrefix(OC_SOUND_LIST_FILENAME), ocDataDirPrefix("") );
733 	OPENCITY_INFO( "Loaded " << gVars.gpAudioMgr->GetNumberSound() << " sounds." );
734 
735 
736 // Create the other required global managers
737 	displayStatus( "Initializing the vibration detector..." );
738 	gVars.gpMapMaker = new MapGen::MapMaker(
739 		gVars.guiCityWidth, gVars.guiCityLength,
740 		gVars.gsGeneratorHeightMap,
741 		gVars.guiGeneratorMapType,
742 		gVars.guiGeneratorWaterType,
743 		gVars.guiGeneratorMapShapeType,
744 		gVars.guiGeneratorTreeDensityType,
745 		gVars.guiGeneratorSeed
746 	);
747 
748 	displayStatus( "Activating embedded GPS...");
749 	gVars.gpMapMgr = new Map( gVars.guiCityWidth, gVars.guiCityLength );
750 
751 	displayStatus( "Calibrating earthquake subsystem...");
752 	gVars.gpGraphicMgr = new GraphicManager();
753 
754 	displayStatus( "Shaking DNA mixer thread...");
755 	gVars.gpPropertyMgr = new PropertyManager();
756 
757 	displayStatus( "Mounting intergalactic hyperlink ...");
758 	gVars.gpNetworking = new Networking();
759 
760 	displayStatus( "Initializing the particle handler ...");
761 	gVars.gpMoveMgr = new MovementManager( gVars.gpGraphicMgr, gVars.gpMapMgr );
762 
763 
764 // The pointer of our new city
765 	City* pNewCity = new City( gVars.guiCityWidth, gVars.guiCityLength );
766 	if (pNewCity == NULL) {
767 		OPENCITY_FATAL( "Error while creating new city" );
768 		return OC_ERROR_MEMORY;
769 	}
770 	displayStatus( "Almost done...");
771 
772 
773 // FIXME: buggy MAS
774 /*
775 // Create the necessary classes for the Multi-Agent System
776 	gVars.gpKernel = new Kernel();
777 	gVars.gpEnvironment = new Environment(
778 		gVars.guiCityWidth, gVars.guiCityLength, pNewCity->GetLayer( OC_LAYER_BUILDING ), gVars.gpKernel );
779 
780 	new AgentPolice(*gVars.gpKernel, *gVars.gpEnvironment, 1, 2);
781 	new AgentPolice(*gVars.gpKernel, *gVars.gpEnvironment, 3, 4);
782 	new AgentDemonstrator(*gVars.gpKernel, *gVars.gpEnvironment, 4, 2);
783 */
784 
785 	while (!bQuit) {
786 	// Process input events
787 		ocProcessSDLEvents();
788 
789 	// Restart with a new city from scratch
790 	// WARNING: code duplication
791 		if (bRestart) {
792 		// Lock the simulator
793 			SDL_LockMutex( gVars.gpmutexSim );
794 
795 		// Remove all moving objects
796 			gVars.gpMoveMgr->Remove();
797 
798 			delete pNewCity;
799 			delete gVars.gpMapMgr;
800 			delete gVars.gpMapMaker;
801 
802 			gVars.guiGeneratorSeed = time(NULL);
803 			gVars.gpMapMaker = new MapGen::MapMaker(
804 				gVars.guiCityWidth, gVars.guiCityLength,
805 				gVars.gsGeneratorHeightMap,
806 				gVars.guiGeneratorMapType,
807 				gVars.guiGeneratorWaterType,
808 				gVars.guiGeneratorMapShapeType,
809 				gVars.guiGeneratorTreeDensityType,
810 				gVars.guiGeneratorSeed
811 			);
812 			gVars.gpMapMgr = new Map( gVars.guiCityWidth, gVars.guiCityLength );
813 			pNewCity = new City( gVars.guiCityWidth, gVars.guiCityLength );
814 			if (pNewCity == NULL) {
815 				OPENCITY_FATAL( "Error while creating new city" );
816 				return OC_ERROR_MEMORY;
817 			}
818 			gVars.gpRenderer->bHeightChange = true;
819 			gVars.gpRenderer->bMinimapChange = true;
820 
821 		// Unlock the simulator
822 			SDL_UnlockMutex( gVars.gpmutexSim );
823 
824 			bRestart = false;
825 		}
826 
827 	// Process city's task
828 		pNewCity->Run();
829 		//gVars.gpKernel->live();
830 
831 	// IF the application is not iconified THEN update the display
832 		if (gVars.gboolActive)
833 			pNewCity->Display();
834 
835 #undef OC_PRINT_FPS
836 #ifndef OC_PRINT_FPS
837 		SDL_Delay( gVars.guiMsPerFrame );
838 #else
839 		static Uint32 uiNumberTick = SDL_GetTicks();
840 		static uint uiNumberFrame = 0;
841 
842 		uiNumberFrame++;
843 		if ((SDL_GetTicks() - uiNumberTick) > 5000) {
844 			cout << uiNumberFrame << " frames per 5 seconds = "
845 					<< uiNumberFrame / 5 << " FPS" << endl;
846 			uiNumberTick = SDL_GetTicks();
847 			uiNumberFrame = 0;
848 		}
849 		SDL_Delay( gVars.guiMsPerFrame );
850 #endif
851 	} // while (!bQuit)
852 
853 	//delete gVars.gpEnvironment;
854 	//delete gVars.gpKernel;
855 
856 
857 // Close the network connection
858 	gVars.gpNetworking->Close();
859 
860 // WARNING: the deleting/creating order is very important !
861 	delete pNewCity;
862 
863 	delete gVars.gpMoveMgr;
864 	delete gVars.gpNetworking;
865 	delete gVars.gpPropertyMgr;
866 	delete gVars.gpGraphicMgr;
867 	delete gVars.gpMapMgr;
868 	delete gVars.gpMapMaker;
869 
870 // close the audio device then delete the audio manager
871 	gVars.gpAudioMgr->CloseAudio();
872 	delete gVars.gpAudioMgr;
873 
874 	delete gVars.gpRenderer;
875 	delete gVars.gpExtensionMgr;
876 
877 // delete the simulators' mutex now
878 	SDL_DestroyMutex( gVars.gpmutexSim );
879 
880 //	SDL_FreeSurface( gVars.gpVideoSrf ); // This is not recommended by SDL documentation
881 	gVars.gpVideoSrf = NULL;
882 
883 	SDL_Quit();					// WARNING: Calls free() on an invalid pointer. Detected by glibc
884 
885 	return 0;
886 }
887 
888 
889    /*=====================================================================*/
printCopyright()890 static void printCopyright() {
891 // Output the copyright text
892 	cout << "Welcome to " << PACKAGE << "-" << ocStrVersion() << endl;
893 	cout << "Copyright (C) by Duong Khang NGUYEN. All rights reserved." << endl;
894 	cout << "   web  : http://www.opencity.info" << endl;
895 	cout << "   email: neoneurone @ gmail com" << endl << endl;
896 
897 	cout << "This program is released under the terms of" << endl;
898 	cout << "GNU General Public License (See the COPYING file for more details)" << endl << endl;
899 
900 	cout << "Starting " << OC_PROGRAM_NAME << "..." << endl << endl;
901 }
902 
903 
904    /*=====================================================================*/
905 /** Return the save directory.
906 	\return The pointer to the absolute directory. The caller must free
907 the pointer if it's not used anymore.
908 */
findSaveDir()909 static char* findSaveDir()
910 {
911 	char* ret = NULL;
912 
913 #ifndef __WIN32__
914 // Get the home directory from the environment variable
915 	char* env = getenv("HOME");
916 	if (env != NULL) {
917 		ret = (char*)malloc( strlen(env) + 1 );
918 		strcpy( ret, env );
919 	}
920 #else
921 // Find the directory: "C:\Documents and Settings\username\Application Data"
922 // Required shell DLL version: 5.0 or later
923 // header: shlobj.h
924 // lib: shell32.lib ?
925 // dll: shell32.dll
926 
927 	TCHAR szPath[MAX_PATH];
928 
929 	if(SUCCEEDED(
930 		SHGetFolderPath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, szPath)
931 		)) {
932 		ret = (char*)malloc( strlen(szPath) + 1 );
933 		strcpy( ret, szPath );
934 	}
935 #endif
936 
937 // The required save directory does not exist, use the current directory
938 	if (ret == NULL) {
939 		ret = (char*)malloc( 2 );
940 		strcpy( ret, "." );
941 	}
942 
943 	return ret;
944 }
945 
946 
947    /*=====================================================================*/
948 /** Try to detect and set the datadir, the confdir and the savedir using
949 BinReloc library and win32 standard function
950 */
detectProgramPath()951 static void detectProgramPath()
952 {
953 	char* pTemp = NULL;
954 	BrInitError brError;
955 
956 // IF the datadir is not set THEN try to get it from BinReloc routines
957 	if (sDataDir == "") {
958 	// Default system directory settings
959 		sDataDir = DATADIR;
960 
961 	// Init the BinReloc routines
962 		if (br_init(&brError) != 1) {
963 			OPENCITY_INFO(
964 				"Failed to initialized BinReloc routines to search for the datadir. " <<
965 				"The error was: " << brError
966 			);
967 		}
968 
969 	// Construct the datadir from the prefix
970 		pTemp = br_find_data_dir( sDataDir.c_str() );
971 		sDataDir = pTemp;
972 		sDataDir += "/";
973 		sDataDir += PACKAGE;
974 		sDataDir = formatPath( sDataDir );
975 		free(pTemp);
976 	}
977 
978 // IF the configdir is not set THEN try to get it from BinReloc routines
979 	if (sConfigDir == "") {
980 	// Default system directory settings
981 		sConfigDir = SYSCONFDIR;
982 
983 	// Init the BinReloc routines
984 		if (br_init(&brError) != 1) {
985 			OPENCITY_INFO(
986 				"Failed to initialized BinReloc routines to search for the confdir. " <<
987 				"The error was: " << brError
988 			);
989 		}
990 
991 	// Construct the pkgsysconfdir from the prefix
992 		pTemp = br_find_etc_dir( sConfigDir.c_str() );
993 		sConfigDir = pTemp;
994 		sConfigDir += "/";
995 		sConfigDir += PACKAGE;
996 		sConfigDir = formatPath( sConfigDir );
997 		free(pTemp);
998 	}
999 
1000 // IF the save directory is not set the find it
1001 	if (sSaveDir == "") {
1002 		pTemp = findSaveDir();
1003 		sSaveDir = pTemp;
1004 		free(pTemp);
1005 #ifndef __WIN32__
1006 		sSaveDir += "/.opencity/";
1007 		mkdir( sSaveDir.c_str(), 0755 );
1008 #else
1009 	// Win32 uses \ as directory separtor
1010 		sSaveDir += "\\opencity\\";
1011         CreateDirectory( sSaveDir.c_str(), NULL );
1012     // Replace \ by /
1013 	    string::size_type pos;
1014 	    while ( (pos = sSaveDir.find( '\\' )) != sSaveDir.npos ) {
1015 		    sSaveDir.replace( pos, 1, "/" );
1016 		}
1017 #endif
1018 	}
1019 
1020 // Print out some information
1021 	OPENCITY_INFO( "Detected data directory   : " << sDataDir );
1022 	OPENCITY_INFO( "Detected config directory : " << sConfigDir );
1023 	OPENCITY_INFO( "Detected save directory   : " << sSaveDir );
1024 }
1025 
1026 
1027    /*=====================================================================*/
1028 /** Read the OpenCity's main settings file "opencity.xml"
1029 	\return "" if OK, otherwise the error description
1030 		0: if OK
1031 		OC_ERROR_NOT_FOUND: the config file has not been found
1032 		OC_ERROR_PARSE_CONFIG: there was a parse error
1033 */
readSettings()1034 static string readSettings()
1035 {
1036 	string errorString = "";
1037 	TiXmlDocument settings;
1038 
1039 // Now try to open the config file then read it
1040 	OPENCITY_INFO(
1041 		"Reading XML config file: \"" << ocConfigDirPrefix(OC_CONFIG_FILE_FILENAME) << "\""
1042 	);
1043 
1044 // Load the settings file
1045 	string fn = ocConfigDirPrefix(OC_CONFIG_FILE_FILENAME);
1046 	if (!settings.LoadFile(fn)) {
1047 		errorString = settings.ErrorDesc();
1048 		return errorString;
1049 	}
1050 
1051 // Error testing
1052 	if (settings.Error()) {
1053 		errorString = settings.ErrorDesc();
1054 		return errorString;
1055 	}
1056 
1057 // Get the root element
1058 	TiXmlNode* pRoot = settings.RootElement();
1059 	if (pRoot == NULL) {
1060 		errorString = settings.ErrorDesc();
1061 		return errorString;
1062 	}
1063 
1064 // Parse the settings
1065 	TiXmlElement* pElement = pRoot->FirstChildElement();
1066 	const char* str = NULL;
1067 	while (pElement != NULL)
1068 	{
1069 // Debug
1070 //		cout << i++ << "||" << *pElement << std::endl;
1071 	// "fullscreen" element
1072 		if (pElement->ValueStr() == "fullscreen") {
1073 			str = pElement->Attribute("enable");
1074 			if (str != NULL && strcmp(str, "true") == 0) {
1075 				gVars.gboolFullScreen |= true;
1076 			}
1077 			else {
1078 				gVars.gboolFullScreen |= false;
1079 			}
1080 
1081 			// IF fullscreen mode enabled THEN read size
1082 			if (gVars.gboolFullScreen) {
1083 				TiXmlElement* pChild = pElement->FirstChildElement();
1084 				while (pChild != NULL) {
1085 					if (pChild->ValueStr() == "width") {
1086 						pChild->QueryIntAttribute("value", (int*)&gVars.guiScreenWidth);
1087 					}
1088 					else if (pChild->ValueStr() == "height") {
1089 						pChild->QueryIntAttribute("value", (int*)&gVars.guiScreenHeight);
1090 					}
1091 					pChild = pChild->NextSiblingElement();
1092 				}
1093 			}
1094 		}
1095 	// "acceleratedVisual" element
1096 		else if (pElement->ValueStr() == "acceleratedVisual") {
1097 			str = pElement->Attribute("enable");
1098 
1099 		// Eventually ignore relative command-line option.
1100 			if (str != NULL && strcmp(str, "true") == 0) {
1101 				gVars.gboolAcceleratedVisual = true;
1102 			} else {
1103 				gVars.gboolAcceleratedVisual = false;
1104 			}
1105 		}
1106 	// "audio" element
1107 		else if (pElement->ValueStr() == "audio") {
1108 			str = pElement->Attribute("enable");
1109 			if (str != NULL && strcmp(str, "true") == 0) {
1110 				gVars.gboolUseAudio &= true;
1111 			} else {
1112 				gVars.gboolUseAudio &= false;
1113 			}
1114 		}
1115 	// "city" element, read the city's size
1116 		else if (pElement->ValueStr() == "city") {
1117 			TiXmlElement* pChild = pElement->FirstChildElement();
1118 			while (pChild != NULL) {
1119 // Debug
1120 //				cout << i++ << "||" << *pChild << std::endl;
1121 				if (pChild->ValueStr() == "width") {
1122 					pChild->QueryIntAttribute("value", (int*)&gVars.guiCityWidth);
1123 				}
1124 				else if (pChild->ValueStr() == "length") {
1125 					pChild->QueryIntAttribute("value", (int*)&gVars.guiCityLength);
1126 				}
1127 				pChild = pChild->NextSiblingElement();
1128 			}
1129 		}
1130 	// "msPerFrame" element
1131 		else if (pElement->ValueStr() == "msPerFrame") {
1132 			pElement->QueryIntAttribute("value", (int*)&gVars.guiMsPerFrame);
1133 		}
1134 	// "zenServer" element
1135 		else if (pElement->ValueStr() == "zenServer") {
1136 			if (pElement->GetText() != NULL)
1137 				gVars.gsZenServer = pElement->GetText();
1138 		}
1139 
1140 		pElement = pElement->NextSiblingElement();
1141 	}
1142 
1143 	return errorString;
1144 }
1145 
1146 
1147    /*=====================================================================*/
initGlobalVar()1148 static void initGlobalVar()
1149 {
1150 // Config file and command line options
1151 	gVars.gboolUseAudio				= true;
1152 	gVars.gboolAcceleratedVisual	= false;
1153 	gVars.gboolFullScreen			= false;
1154 	gVars.gboolServerMode			= false;
1155 	gVars.guiCityWidth				= OC_CITY_W;
1156 	gVars.guiCityLength				= OC_CITY_L;
1157 	gVars.guiMsPerFrame				= OC_MS_PER_FRAME;
1158 	gVars.guiScreenWidth			= OC_WINDOW_WIDTH;
1159 	gVars.guiScreenHeight			= OC_WINDOW_HEIGHT;
1160 	gVars.guiVideoBpp				= OC_WINDOW_BPP_DEFAULT;
1161 	gVars.gsOpenGLDriver			= "";
1162 
1163 	gVars.gsGeneratorHeightMap			= "";
1164 	gVars.guiGeneratorSeed				= time(NULL);
1165 	gVars.guiGeneratorMapType			= MapGen::MapMaker::PLAIN;
1166 	gVars.guiGeneratorWaterType			= MapGen::MapMaker::LAKE;
1167 	gVars.guiGeneratorMapShapeType		= MapGen::MapMaker::NONE;
1168 	gVars.guiGeneratorTreeDensityType	= MapGen::MapMaker::SPARSE;
1169 
1170 	gVars.gfMsSimDelayMax			= 0;
1171 	gVars.gsZenServer				= "localhost";
1172 
1173 // Application status
1174 	gVars.gboolActive				= true;		// the application is active at start
1175 
1176 // The mutex that all the simulators depend on
1177 	gVars.gpmutexSim				= NULL;
1178 
1179 // The famous renderer
1180 	gVars.gpRenderer				= NULL;
1181 
1182 // Datamanagers
1183 	gVars.gpAudioMgr				= NULL;		// global Audio Manager
1184 	gVars.gpGraphicMgr				= NULL;		// global Graphic Manager
1185 	gVars.gpPropertyMgr				= NULL;		// global Property Manager
1186 	gVars.gpMapMaker				= NULL;		// global map maker
1187 	gVars.gpMapMgr					= NULL;		// global height Map Manager
1188 	gVars.gpNetworking				= NULL;		// global networking support class
1189 	gVars.gpPathFinder				= NULL;		// global pathfinder class
1190 	gVars.gpMoveMgr					= NULL;		// global movement manager
1191 
1192 // Multi-Agent System
1193 	gVars.gpKernel					= NULL;		// global MAS Kernel
1194 	gVars.gpEnvironment				= NULL;		// global Environement class
1195 
1196 // The SDL video surface
1197 	gVars.gpVideoSrf				= NULL;		// global video screen surface
1198 }
1199 
1200 
1201    /*=====================================================================*/
1202 //#ifdef __WIN32__
1203 //extern "C"
1204 //#endif
main(int argc,char * argv[])1205 int main(int argc, char *argv[])
1206 {
1207 // Initialize the global settings variable to the default values
1208 	initGlobalVar();
1209 
1210 // Print out the copyright
1211 	printCopyright();
1212 
1213 // Parse the command-line options
1214 	int returnCode = parseArg( argc, argv );
1215 	if (returnCode != 0) {
1216 		return returnCode;
1217 	}
1218 
1219 // Detect the main path: sDataDir and sSaveDir
1220 	detectProgramPath();
1221 
1222 // Read the application settings from the XML settings file
1223 	string errorDesc = readSettings();
1224 	if (errorDesc != "") {
1225 		OPENCITY_FATAL(
1226 			"There was an error while loading the settings file: \"" << errorDesc << "\"" << endl
1227 			<< "If the main config file \"" << OC_CONFIG_FILE_FILENAME << "\" has not been found then" << endl
1228 			<< "try to specify the data directory with ""--data-dir"" "
1229 			<< "and the configuration directory with ""--conf-dir""." << endl
1230 			<< "For example:" << endl
1231 			<< "    " << argv[0] << " --data-dir \"/absolute/path/to/opencity/data\" "
1232 			<< "--conf-dir \"/absolute/path/to/opencity/conf\"" << endl
1233 			<< "or" << endl
1234 			<< "    " << argv[0] << " --data-dir \"../relative/path/to/opencity/data\" "
1235 			<< "--conf-dir \"../relative/path/to/opencity/conf\"" << endl
1236 		);
1237 		exit(OC_ERROR_NOT_FOUND);
1238 	}
1239 
1240 // Test XPath
1241 // 	PropertyManager2* pPropertyMgr = new PropertyManager2();
1242 // 	const Property* myProperty = pPropertyMgr->Get( 1 );
1243 // 	OPENCITY_DEBUG( "Build cost 1: " << myProperty->uiDestroyCost );
1244 // 	const Property* myProperty2 = pPropertyMgr->Get( "graphism/residential/little_house/little_house.ac" );
1245 // 	OPENCITY_DEBUG( "Build cost 2: " << myProperty2->uiIncome );
1246 // 	delete pPropertyMgr;
1247 // 	abort();
1248 
1249 // Initialization of global variables
1250 	uipCurrentUI = NULL;
1251 	gVars.gfMsSimDelayMax = log10((OC_FLOAT)gVars.guiCityWidth*gVars.guiCityLength + 1) * OC_MS_GLOBAL_LOG_FACTOR;
1252 
1253 // Initialize the random number generator
1254 	srand( time(NULL) );
1255 
1256 // Launch the game
1257 	returnCode = clientMode();
1258 
1259 	return returnCode;
1260 }
1261 
1262 
1263    /*=====================================================================*/
1264    /*                       GLOBAL       FUNCTIONS                        */
1265    /*=====================================================================*/
1266 string
ocDataDirPrefix(const string & s)1267 ocDataDirPrefix( const string& s )
1268 {
1269 	return sDataDir + s;
1270 }
1271 
1272 
1273    /*=====================================================================*/
1274 string
ocConfigDirPrefix(const string & s)1275 ocConfigDirPrefix( const string& s )
1276 {
1277 	return sConfigDir + s;
1278 }
1279 
1280 
1281    /*=====================================================================*/
1282 string
ocSaveDirPrefix(const string & s)1283 ocSaveDirPrefix( const string& s )
1284 {
1285 	return sSaveDir + s;
1286 }
1287 
1288 
1289    /*=====================================================================*/
ocStrVersion()1290 string ocStrVersion()
1291 {
1292 	std::ostringstream oss;
1293 
1294 	oss << OC_VERSION << "." << OC_PATCHLEVEL << "." << OC_SUBLEVEL;
1295 	return oss.str();
1296 }
1297 
1298 
1299    /*=====================================================================*/
ocLongVersion()1300 long ocLongVersion()
1301 {
1302 	long lVersion = 0;
1303 
1304 	lVersion = OC_VERSION*65536 + OC_PATCHLEVEL*256 + OC_SUBLEVEL;
1305 	return lVersion;
1306 }
1307