1 /***************************************************************************
2 						zen.cpp  -  description
3 							-------------------
4 	project              : OpenCity
5 	codename             : ZeN server
6 	begin                : november 26th, 2006
7 	copyright            : (C) 2006-2008 by Duong Khang NGUYEN
8 	email                : neoneurone @ gmail com
9 
10 	$Id: zen.cpp 375 2008-10-28 14:47:15Z neoneurone $
11  ***************************************************************************/
12 
13 /***************************************************************************
14  *                                                                         *
15  *   This program is free software; you can redistribute it and/or modify  *
16  *   it under the terms of the GNU General Public License as published by  *
17  *   the Free Software Foundation; either version 2 of the License, or     *
18  *   any later version.                                                    *
19  *                                                                         *
20  ***************************************************************************/
21 
22 // Useful enumerations
23 #include "opencity_direction.h"
24 #include "opencity_structure_type.h"
25 
26 // OpenCity headers
27 #include "zen.h"
28 #include "city.h"				// The heart of the project
29 #include "conf.h"				// Parser for .conf file
30 #include "agentpolice.h"		// MAS testing
31 #include "agentdemonstrator.h"
32 
33 // Global settings
34 #include "globalvar.h"
35 extern GlobalVar gVars;
36 
37 // Libraries headers
38 #include "SDL_image.h"
39 #include "binreloc.h"			// BinReloc routines from AutoPackage
40 #include "tinyxml/tinyxml.h"
41 #include "SimpleOpt.h"			// Simple command line argument parser
42 
43 // Standard headers
44 #include <cmath>				// For log10
45 #include <cstdlib>				// For getenv
46 #include <ctime>				// For time
47 
48 
49    /*=====================================================================*/
50    /*                           LOCAL     MACROS                          */
51    /*=====================================================================*/
52 #ifndef __WIN32__
53 	#include <sys/stat.h>		// mkdir
54 #else
55 // Win32 specifics
56 	#include <shlobj.h>			// Windows shell technologies
57 	#define DATADIR "C:/Program Files"
58 	#define SYSCONFDIR DATADIR
59 #endif
60 
61 // Window's settings
62 	#define OC_WINDOW_POS_X			20
63 	#define OC_WINDOW_POS_Y			20
64 	#define OC_WINDOW_WIDTH			750
65 	#define OC_WINDOW_HEIGHT		560
66 	#define OC_WINDOW_BPP_DEFAULT	32				// OC uses this by default
67 	#define OC_WINDOW_BPP_16		16
68 	#define OC_FULLSCREEN_WIDTH		1024
69 	#define OC_FULLSCREEN_HEIGHT	768
70 
71 // Exit code
72 	#define OC_CONFIG_NOT_FOUND		-1
73 	#define OC_CONFIG_PARSE_ERROR	-2
74 
75 // Settings file
76 	#define OC_CONFIG_FILE_FILENAME	"config/opencity.xml"
77 
78 // Others macros
79 	#define OC_WINDOW_NAME PACKAGE VERSION
80 	#define OC_PROGRAM_NAME			"OpenCity ZeN server application"
81 
82 
83 
84    /*=====================================================================*/
85    /*                         LOCAL    VARIABLES                          */
86    /*=====================================================================*/
87 /// The current user interface is pointed by this pointer
88 	static UI* uipCurrentUI		= NULL;
89 
90 /// Set to true when the user request to quit the program
91 	static bool boolQuit		= false;
92 	static bool bRestart		= false;
93 
94 /// Static so that the others can not access this
95 	static string sDataDir		= "";
96 	static string sSaveDir		= "";
97 	static string sConfigDir	= "";
98 
99 
100    /*=====================================================================*/
ocActive(const SDL_ActiveEvent & e)101 void ocActive( const SDL_ActiveEvent & e)
102 {
103 	OPENCITY_DEBUG( "Active event received" );
104 
105 	if (e.state & SDL_APPACTIVE) {
106 		gVars.gboolActive = (e.gain == 1);
107 	}
108 }
109 
110 
111    /*=====================================================================*/
ocQuit(const int quit_code)112 void ocQuit( const int quit_code )
113 {
114 	cout << "Quit requested, quit code is : " << quit_code
115 	     << endl
116 	     << "Bye bye !"
117 	     << endl;
118 	boolQuit = true;
119 }
120 
121 
122    /*=====================================================================*/
ocRestart()123 void ocRestart()
124 {
125 	cout << "Restart with a new city from scratch. " << endl;
126 	bRestart = true;
127 }
128 
129 
130    /*=====================================================================*/
ocProcessSDLEvents(void)131 void ocProcessSDLEvents( void )
132 {
133 	static SDL_Event event;
134 
135 // Grab all the events off the queue.
136 	while( SDL_PollEvent( &event ) ) {
137 
138 		switch( event.type ) {
139 		case SDL_ACTIVEEVENT:
140 			ocActive( event.active );
141 			break;
142 
143 		case SDL_QUIT:
144 		// Handle quit requests (like Ctrl-c).
145 			cout << "Quit requested, stoping " << OC_PROGRAM_NAME << "..." << endl;
146 			boolQuit = true;
147 			break;
148 		}
149 	}
150 }
151 
152 
153    /*=====================================================================*/
ocSetNewUI(UI * pcNewUI)154 void ocSetNewUI( UI * pcNewUI)
155 {
156 	uipCurrentUI = pcNewUI;
157 }
158 
159 
160    /*=====================================================================*/
161 string
formatPath(const string & rcsPath)162 formatPath(const string& rcsPath)
163 {
164 	string result = rcsPath;
165 
166 	if (result.size() > 0) {
167 	// Delete all quotes "
168 		string::size_type pos;
169 		while ( (pos = result.find( '\"' )) != result.npos ) {
170 		    result.erase( pos );
171 		}
172 	// Append the "/" to path
173 		if (result[ result.size()-1 ] != '/')
174 			result += '/';
175 	}
176 	else {
177 		result = "/";
178 	}
179 
180 	return result;
181 }
182 
183 
184    /*=====================================================================*/
parseArg(int argc,char * argv[])185 void parseArg(int argc, char *argv[])
186 {
187 	enum {
188 		OPT_DATADIR,
189 		OPT_CONFDIR,
190 		OPT_HELP
191 	};
192 
193 	CSimpleOpt::SOption g_rgOptions[] = {
194 		{ OPT_DATADIR,	(char*)"--datadir",		SO_REQ_SEP	},
195 		{ OPT_DATADIR,	(char*)"-dd",			SO_REQ_SEP	},
196 		{ OPT_CONFDIR,	(char*)"--confdir",		SO_REQ_SEP	},
197 		{ OPT_CONFDIR,	(char*)"-cd",			SO_REQ_SEP	},
198 		{ OPT_HELP,		(char*)"--help",		SO_NONE		},
199 		{ OPT_HELP,		(char*)"-h",			SO_NONE		},
200 		SO_END_OF_OPTIONS // END
201 	};
202 
203 	CSimpleOpt args(argc, argv, g_rgOptions, SO_O_EXACT | SO_O_NOSLASH | SO_O_SHORTARG | SO_O_CLUMP );
204 	while (args.Next()) {
205 		switch (args.LastError()) {
206 		case SO_OPT_INVALID:
207 			cout << "<OPTION> " << args.OptionText() << " unrecognized" << endl;
208 			break;
209 		case SO_OPT_MULTIPLE:
210 			cout << "<OPTION> " << args.OptionText() << " matched multiple options" << endl;
211 			break;
212 		case SO_ARG_INVALID:
213 			cout << "<OPTION> " << args.OptionText() << " does not accept any argument" << endl;
214 			break;
215 		case SO_ARG_INVALID_TYPE:
216 			cout << "<OPTION> " << args.OptionText() << " has an invalid argument format" << endl;
217 			break;
218 		case SO_ARG_MISSING:
219 			cout << "<OPTION> " << args.OptionText() << " requires an argument" << endl;
220 			break;
221 		case SO_ARG_INVALID_DATA:
222 			cout << "<OPTION> " << args.OptionText() << " has an invalid argument data" << endl;
223 			break;
224 		case SO_SUCCESS:
225 			cout << "<OPTION> " << args.OptionText() << " detected" << endl;
226 			break;
227 		}
228 
229 		// Exit the program on error
230 		if (args.LastError() != SO_SUCCESS) {
231 			cout << "Try " << argv[0] << " --help for usage information" << endl;
232 			exit( -1 );
233 		}
234 
235 		switch (args.OptionId()) {
236 		case OPT_DATADIR:
237 			sDataDir = formatPath(args.OptionArg());
238 			cout << "<OPTION> DataDir is: \"" << sDataDir << "\"" << endl;
239 			break;
240 
241 		case OPT_CONFDIR:
242 			sConfigDir = formatPath(args.OptionArg());
243 			cout << "<OPTION> ConfDir is: \"" << sConfigDir << "\"" << endl;
244 			break;
245 
246 		case OPT_HELP:
247 			cout << "Usage: " << argv[0]
248 				 << " [-dd|--datadir newDataPath] [-cd|--confdir newConfigPath]" << endl << endl;
249 			cout << "Warning: the command option overwrite the config file settings."
250 				 << endl;
251 			exit( -2 );
252 			break;
253 		} // switch
254 	} // while
255 }
256 
257 
258    /*=====================================================================*/
displayStatus(const string & str)259 void displayStatus( const string & str )
260 {
261 	cout << str << endl;
262 }
263 
264 
265    /*=====================================================================*/
serverMode()266 int serverMode()
267 {
268 // Initialize the video system in order to capture Ctrl-C !
269 	SDL_Init(SDL_INIT_VIDEO);
270 
271 // Create the mutex first
272 	gVars.gpmutexSim = SDL_CreateMutex();
273 
274 // Create the global renderer in order to use its text rendering functions
275 //	gVars.gpRenderer = new Renderer( gVars.guiCityWidth, gVars.guiCityLength );
276 
277 // AudioManager's initialization
278 //	displayStatus( "Looking for GPU freezing system... ");
279 //	gVars.gpAudioMgr = new AudioManager();
280 
281 // Create the other required global managers
282 	displayStatus( "Initializing the vibration detector..." );
283 	gVars.gpMapMaker = new MapGen::MapMaker(
284 		gVars.guiCityWidth, gVars.guiCityLength,
285 		gVars.gsGeneratorHeightMap,
286 		gVars.guiGeneratorMapType,
287 		gVars.guiGeneratorWaterType,
288 		gVars.guiGeneratorMapShapeType,
289 		gVars.guiGeneratorTreeDensityType,
290 		gVars.guiGeneratorSeed
291 	);
292 
293 	displayStatus( "Activating embedded GPS...");
294 	gVars.gpMapMgr = new Map( gVars.guiCityWidth, gVars.guiCityLength );
295 
296 //	displayStatus( "Calibrating earthquake subsystem...");
297 //	gVars.gpGraphicMgr = new GraphicManager();
298 
299 	displayStatus( "Shaking DNA mixer thread...");
300 	gVars.gpPropertyMgr = new PropertyManager();
301 
302 	displayStatus( "Mounting intergalactic hyperlink ...");
303 	gVars.gpNetworking = new Networking();
304 
305 	displayStatus( "Initializing the particle handler ...");
306 	gVars.gpMoveMgr = new MovementManager( gVars.gpGraphicMgr, gVars.gpMapMgr );
307 
308 
309 // Create a new city map
310 	City* pNewCity = new City( gVars.guiCityWidth, gVars.guiCityLength, false );
311 	if (pNewCity == NULL) {
312 		OPENCITY_FATAL( "Error while creating new city" );
313 		return (-15);
314 	}
315 
316 // Start the server
317 	boolQuit = (gVars.gpNetworking->StartServer() == OC_NET_OK) ? false : true;
318 	if (!boolQuit)
319 		displayStatus( "Online world conquero activated");
320 	else
321 		displayStatus( "Online world conquero activation has failed" );
322 
323 // The main loop
324 	while (!boolQuit) {
325 	// Run the city at the LAST_SPEED (default parameter)
326 		cout << ".";
327 		(void)gVars.gpNetworking->ProcessServerData();
328 		ocProcessSDLEvents();
329 		pNewCity->Run();
330 
331 		cout.flush();
332 		SDL_Delay( gVars.guiMsPerFrame );
333 	}
334 
335 // Stop the zen server and close the network connection
336 	(void)gVars.gpNetworking->StopServer();
337 	gVars.gpNetworking->Close();
338 
339 // WARNING: the deleting/creating order is very important !
340 	delete pNewCity;
341 
342 	delete gVars.gpMoveMgr;
343 	delete gVars.gpNetworking;
344 	delete gVars.gpPropertyMgr;
345 //	delete gVars.gpGraphicMgr;
346 	delete gVars.gpMapMgr;
347 
348 // Close the audio device then delete the audio manager
349 //	gVars.gpAudioMgr->CloseAudio();
350 //	delete gVars.gpAudioMgr;
351 
352 //	delete gVars.gpRenderer;
353 
354 // Delete the simulators' mutex now
355 	SDL_DestroyMutex( gVars.gpmutexSim );
356 
357 	gVars.gpVideoSrf = NULL;
358 	SDL_Quit();					// WARNING: Calls free() on an invalid pointer. Detected by glibc
359 	return 0;
360 }
361 
362 
363    /*=====================================================================*/
printCopyright()364 void printCopyright() {
365 // Output the copyright text
366 	cout << "Welcome to " << PACKAGE << " version " << VERSION << endl;
367 	cout << "Copyright (C) by Duong Khang NGUYEN. All rights reserved." << endl;
368 	cout << "   web  : http://www.opencity.info" << endl;
369 	cout << "   email: neoneurone @ gmail com" << endl << endl;
370 
371 	cout << "This program is released under the terms of" << endl;
372 	cout << "GNU General Public License (See the COPYING file for more details)" << endl << endl;
373 
374 	cout << "Starting " << OC_PROGRAM_NAME << "..." << endl << endl;
375 }
376 
377 
378    /*=====================================================================*/
379 /** Return the save directory.
380 	\return The pointer to the absolute directory. The caller must free
381 the pointer if it's not used anymore.
382 */
findSaveDir()383 char* findSaveDir()
384 {
385 	char* ret = NULL;
386 
387 #ifndef __WIN32__
388 // Get the home directory from the environment variable
389 	char* env = getenv("HOME");
390 	if (env != NULL) {
391 		ret = (char*)malloc( strlen(env) + 1 );
392 		strcpy( ret, env );
393 	}
394 #else
395 // Find the directory: "C:\Documents and Settings\username\Application Data"
396 // Required shell DLL version: 5.0 or later
397 // header: shlobj.h
398 // lib: shell32.lib ?
399 // dll: shell32.dll
400 
401 	TCHAR szPath[MAX_PATH];
402 
403 	if(SUCCEEDED(
404 		SHGetFolderPath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, szPath)
405 		)) {
406 		ret = (char*)malloc( strlen(szPath) + 1 );
407 		strcpy( ret, szPath );
408 	}
409 #endif
410 
411 // The required save directory does not exist, use the current directory
412 	if (ret == NULL) {
413 		ret = (char*)malloc( 2 );
414 		strcpy( ret, "." );
415 	}
416 
417 	return ret;
418 }
419 
420 
421    /*=====================================================================*/
422 /** Try to detect and set the datadir, the confdir and the savedir using
423 BinReloc library and win32 standard function
424 */
detectProgramPath()425 void detectProgramPath()
426 {
427 	char* pTemp = NULL;
428 	BrInitError brError;
429 
430 // IF the datadir is not set THEN try to get it from BinReloc routines
431 	if (sDataDir == "") {
432 	// Default system directory settings
433 		sDataDir = DATADIR;
434 
435 	// Init the BinReloc routines
436 		if (br_init(&brError) != 1) {
437 			OPENCITY_INFO(
438 				"Failed to initialized BinReloc routines to search for the datadir. " <<
439 				"The error was: " << brError
440 			);
441 		}
442 
443 	// Construct the datadir from the prefix
444 		pTemp = br_find_data_dir( sDataDir.c_str() );
445 		sDataDir = pTemp;
446 		sDataDir += "/";
447 		sDataDir += PACKAGE;
448 		sDataDir = formatPath( sDataDir );
449 		free(pTemp);
450 	}
451 
452 // IF the configdir is not set THEN try to get it from BinReloc routines
453 	if (sConfigDir == "") {
454 	// Default system directory settings
455 		sConfigDir = SYSCONFDIR;
456 
457 	// Init the BinReloc routines
458 		if (br_init(&brError) != 1) {
459 			OPENCITY_INFO(
460 				"Failed to initialized BinReloc routines to search for the confdir. " <<
461 				"The error was: " << brError
462 			);
463 		}
464 
465 	// Construct the pkgsysconfdir from the prefix
466 		pTemp = br_find_etc_dir( sConfigDir.c_str() );
467 		sConfigDir = pTemp;
468 		sConfigDir += "/";
469 		sConfigDir += PACKAGE;
470 		sConfigDir = formatPath( sConfigDir );
471 		free(pTemp);
472 	}
473 
474 // IF the save directory is not set the find it
475 	if (sSaveDir == "") {
476 		pTemp = findSaveDir();
477 		sSaveDir = pTemp;
478 		free(pTemp);
479 #ifndef __WIN32__
480 		sSaveDir += "/.opencity/";
481 		mkdir( sSaveDir.c_str(), 0755 );
482 #else
483 	// Win32 uses \ as directory separtor
484 		sSaveDir += "\\opencity\\";
485         CreateDirectory( sSaveDir.c_str(), NULL );
486     // Replace \ by /
487 	    string::size_type pos;
488 	    while ( (pos = sSaveDir.find( '\\' )) != sSaveDir.npos ) {
489 		    sSaveDir.replace( pos, 1, "/" );
490 		}
491 #endif
492 	}
493 
494 // Print out some information
495 	OPENCITY_INFO( "Detected data directory   : " << sDataDir );
496 	OPENCITY_INFO( "Detected config directory : " << sConfigDir );
497 	OPENCITY_INFO( "Detected save directory   : " << sSaveDir );
498 }
499 
500 
501    /*=====================================================================*/
502 /** Read the OpenCity's main settings file "opencity.xml"
503 	\return "" if OK, otherwise the error description
504 		0: if OK
505 		OC_CONFIG_NOT_FOUND: the config file has not been found
506 		OC_CONFIG_PARSE_ERROR: the was a parse error
507 */
readSettings()508 string readSettings()
509 {
510 	string errorString = "";
511 	TiXmlDocument settings;
512 
513 // Now try to open the config file then read it
514 	OPENCITY_INFO(
515 		"Reading XML config file: \"" << ocConfigDirPrefix(OC_CONFIG_FILE_FILENAME) << "\""
516 	);
517 
518 // Load the settings file
519 	string fn = ocConfigDirPrefix(OC_CONFIG_FILE_FILENAME);
520 	if (!settings.LoadFile(fn)) {
521 		errorString = settings.ErrorDesc();
522 		return errorString;
523 	}
524 
525 // Error testing
526 	if (settings.Error()) {
527 		errorString = settings.ErrorDesc();
528 		return errorString;
529 	}
530 
531 // Get the root element
532 	TiXmlNode* pRoot = settings.RootElement();
533 	if (pRoot == NULL) {
534 		errorString = settings.ErrorDesc();
535 		return errorString;
536 	}
537 
538 // Parse the settings
539 	TiXmlElement* pElement = pRoot->FirstChildElement();
540 	int i = 0;
541 	while (pElement != NULL)
542 	{
543 // Debug
544 //		cout << i++ << "||" << *pElement << std::endl;
545 	// "city" element, read the city's size
546 		if (pElement->ValueStr() == "city") {
547 			TiXmlElement* pChild = pElement->FirstChildElement();
548 			while (pChild != NULL) {
549 				cout << i++ << "||" << *pChild << std::endl;
550 				if (pChild->ValueStr() == "width") {
551 					pChild->QueryIntAttribute("value", (int*)&gVars.guiCityWidth);
552 				}
553 				else if (pChild->ValueStr() == "length") {
554 					pChild->QueryIntAttribute("value", (int*)&gVars.guiCityLength);
555 				}
556 				pChild = pChild->NextSiblingElement();
557 			}
558 		}
559 	// "msPerFrame" element
560 		else if (pElement->ValueStr() == "msPerFrame") {
561 			pElement->QueryIntAttribute("value", (int*)&gVars.guiMsPerFrame);
562 		}
563 	// "zenServer" element
564 		else if (pElement->ValueStr() == "zenServer") {
565 			if (pElement->GetText() != NULL)
566 				gVars.gsZenServer = pElement->GetText();
567 		}
568 
569 		pElement = pElement->NextSiblingElement();
570 	}
571 
572 	return errorString;
573 }
574 
575 
576    /*=====================================================================*/
initGlobalVar()577 void initGlobalVar()
578 {
579 // Config file and command line options
580 	gVars.gboolUseAudio				= true;
581 	gVars.gboolFullScreen			= false;
582 	gVars.gboolServerMode			= false;
583 	gVars.guiCityWidth				= OC_CITY_W;
584 	gVars.guiCityLength				= OC_CITY_L;
585 	gVars.guiMsPerFrame				= OC_MS_PER_FRAME;
586 	gVars.guiScreenWidth			= OC_WINDOW_WIDTH;
587 	gVars.guiScreenHeight			= OC_WINDOW_HEIGHT;
588 	gVars.guiVideoBpp				= OC_WINDOW_BPP_DEFAULT;
589 
590 	gVars.gsGeneratorHeightMap			= "";
591 	gVars.guiGeneratorSeed				= time(NULL);
592 	gVars.guiGeneratorMapType			= MapGen::MapMaker::PLAIN;
593 	gVars.guiGeneratorWaterType			= MapGen::MapMaker::LAKE;
594 	gVars.guiGeneratorMapShapeType		= MapGen::MapMaker::NONE;
595 	gVars.guiGeneratorTreeDensityType	= MapGen::MapMaker::SPARSE;
596 
597 	gVars.gfMsSimDelayMax			= 0;
598 	gVars.gsZenServer				= "localhost";
599 
600 // Application status
601 	gVars.gboolActive				= true;		// the application is active at start
602 
603 // The mutex that all the simulators depend on
604 	gVars.gpmutexSim				= NULL;
605 
606 // The famous renderer
607 	gVars.gpRenderer				= NULL;
608 
609 // Datamanagers
610 	gVars.gpAudioMgr				= NULL;		// global Audio Manager
611 	gVars.gpGraphicMgr				= NULL;		// global Graphic Manager
612 	gVars.gpPropertyMgr				= NULL;		// global Property Manager
613 	gVars.gpMapMaker				= NULL;		// global map maker
614 	gVars.gpMapMgr					= NULL;		// global height Map Manager
615 	gVars.gpNetworking				= NULL;		// global networking support class
616 	gVars.gpPathFinder				= NULL;		// global pathfinder class
617 	gVars.gpMoveMgr					= NULL;		// global movement manager
618 
619 // Multi-Agent System
620 	gVars.gpKernel					= NULL;		// global MAS Kernel
621 	gVars.gpEnvironment				= NULL;		// global Environement class
622 
623 // The SDL video surface
624 	gVars.gpVideoSrf				= NULL;		// global video screen surface
625 }
626 
627 
628    /*=====================================================================*/
629 #ifdef __WIN32__
630 extern "C"
631 #endif
main(int argc,char * argv[])632 int main(int argc, char *argv[])
633 {
634 // Initialize the global settings variable to the default values
635 	initGlobalVar();
636 
637 // Print out the copyright
638 	printCopyright();
639 
640 // Parse the command-line options
641 	parseArg( argc, argv );
642 
643 // Detect the main path: sDataDir and sSaveDir
644 	detectProgramPath();
645 
646 // Read the application settings from the XML settings file
647 	string errorDesc = readSettings();
648 	if (errorDesc != "") {
649 		OPENCITY_FATAL(
650 			"The was an error while loading the settings file: \"" << errorDesc << "\"" << endl
651 			<< "If the main config file \"" << OC_CONFIG_FILE_FILENAME << "\" has not been found then" << endl
652 			<< "try to specify the data directory with ""--datadir"" "
653 			<< "and the configuration directory with ""--confdir""." << endl
654 			<< "For example:" << endl
655 			<< "    " << argv[0] << " --datadir \"/absolute/path/to/opencity/data\" "
656 			<< "--confdir \"/absolute/path/to/opencity/conf\"" << endl
657 			<< "or" << endl
658 			<< "    " << argv[0] << " --datadir \"../relative/path/to/opencity/data\" "
659 			<< "--confdir \"../relative/path/to/opencity/conf\"" << endl
660 		);
661 		exit(OC_CONFIG_NOT_FOUND);
662 	}
663 
664 // Initialization of global variables
665 	uipCurrentUI = NULL;
666 	gVars.gfMsSimDelayMax = log10((OC_FLOAT)gVars.guiCityWidth*gVars.guiCityLength + 1) * OC_MS_GLOBAL_LOG_FACTOR;
667 
668 // Initialize the random number generator
669 	srand( time(NULL) );
670 
671 // Launch the server
672 	int returnCode = serverMode();
673 
674 	return returnCode;
675 }
676 
677 
678    /*=====================================================================*/
679    /*                       GLOBAL       FUNCTIONS                        */
680    /*=====================================================================*/
681 string
ocDataDirPrefix(const string & s)682 ocDataDirPrefix( const string& s )
683 {
684 	return sDataDir + s;
685 }
686 
687 
688    /*=====================================================================*/
689 string
ocConfigDirPrefix(const string & s)690 ocConfigDirPrefix( const string& s )
691 {
692 	return sConfigDir + s;
693 }
694 
695 
696    /*=====================================================================*/
697 string
ocSaveDirPrefix(const string & s)698 ocSaveDirPrefix( const string& s )
699 {
700 	return sSaveDir + s;
701 }
702 
703 
704    /*=====================================================================*/
ocStrVersion()705 string ocStrVersion()
706 {
707 	std::ostringstream oss;
708 
709 	oss << OC_VERSION << "." << OC_PATCHLEVEL << "." << OC_SUBLEVEL;
710 	return oss.str();
711 }
712 
713 
714    /*=====================================================================*/
ocLongVersion()715 long ocLongVersion()
716 {
717 	long lVersion = 0;
718 
719 	lVersion = OC_VERSION*65536 + OC_PATCHLEVEL*256 + OC_SUBLEVEL;
720 	return lVersion;
721 }
722 
723 
724 
725 
726 
727 
728 
729 
730 
731 
732 
733 
734 
735 
736 
737 
738 
739 
740 
741 
742 
743 
744 
745