1 /***************************************************************************
2 						city.cpp  -  description
3 							-------------------
4 	begin                : may 28th, 2003
5 	copyright            : (C) 2003-2008 by Duong Khang NGUYEN
6 	email                : neoneurone @ gmail com
7 
8 	$Id: city.cpp 448 2010-05-09 15:18:32Z neoneurone $
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   any later version.                                                    *
17  *                                                                         *
18  ***************************************************************************/
19 
20 // Useful enumerations
21 #include "opencity_direction.h"
22 #include "opencity_structure_type.h"
23 
24 // OpenCity headers
25 #include "city.h"
26 #include "vehicle.h"
27 #include "mainsim.h"				// Simulator
28 #include "structure.h"
29 #include "buildinglayer.h"
30 #include "guibar.h"					// RCI bar
31 #include "guibutton.h"				// Tool button
32 #include "guilabel.h"				// Status label
33 #include "guicontainer.h"			// GUI control container
34 #include "agentpolice.h"
35 #include "agentdemonstrator.h"
36 #include "agentrobber.h"
37 
38 // Global settings
39 #include "globalvar.h"
40 extern GlobalVar gVars;
41 
42 // Standard headers
43 #include <sstream>					// For text output with data conversion
44 
45 using namespace std;
46 
47 // Local defines
48 #define OC_ACTION_FACTOR 10
49 #define GUIBUTTON_POSITION_TOOL		85, 4, 24, 24
50 
51 
52    /*=====================================================================*/
City(const uint width,const uint length,const bool bGUIEnabled)53 City::City
54 (
55 	const uint width,
56 	const uint length,
57 	const bool bGUIEnabled
58 ):
59 _bGUIEnabled( bGUIEnabled ),
60 _bStatusVisible( true ),
61 _uiIncome( 0 ),
62 _liCityFund( OC_FUND_START ),
63 _uiPopulation( 0 ),
64 
65 _uiDay( 1 ),
66 _uiMonth( 1 ),
67 _uiYear( 0 ),
68 
69 _uiWidth( width ),
70 _uiLength( length ),
71 
72 _bLMBPressed( false ),
73 _eCurrentLayer( OC_LAYER_BUILDING ),
74 _eSpeed( OC_SPEED_NORMAL ),
75 _eCurrentTool( OC_TOOL_NONE ),
76 
77 _pctrMenu( NULL )
78 {
79 	OPENCITY_DEBUG( "City ctor - default parameters" );
80 
81 // Set the windows's WH
82 	_iWinWidth = gVars.guiScreenWidth;
83 	_iWinHeight = gVars.guiScreenHeight;
84 
85 // Registering our call-back interface for SDL events' treatment
86 	ocSetNewUI( this );
87 
88 // Keyboard bool table's initialization
89 	int i;
90 	for (i = 0; i < KEY_NUMBER; i++)
91 		_abKeyPressed[i] = false;
92 
93 // Initialize the statistics
94 	Ressource res = {0, 0, 0, 0, 0, 0, 0, 0};
95 	for (i = 0; i < OC_MAX_RESSOURCE_RECORD; i++) {
96 		_dqRessource.push_back(res);
97 	}
98 
99 // Layers' initialization
100 	_apLayer[ OC_LAYER_BUILDING ] = new BuildingLayer( *this );
101 	gVars.gpMapMgr->SetLayer( _apLayer[OC_LAYER_BUILDING] );
102 
103 // Put few trees on the building layer
104 	_CreateTree();
105 
106 // Pathfinder initialization
107 	gVars.gpPathFinder = new PathFinder(
108 		gVars.gpmutexSim,
109 		(BuildingLayer*)_apLayer[ OC_LAYER_BUILDING ],
110 		gVars.gpMapMgr,
111 		_uiWidth, _uiLength );
112 
113 // Simulators' initialization
114 	_CreateSimulator();
115 
116 	if (_bGUIEnabled) {
117 	// Debug toolcircle
118 		boolPathGo = false;
119 		uiPathStartW = 0; uiPathStartH = 0;
120 		uiPathStopW = 0; uiPathStopH = 0;
121 		_pctrPath = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ));
122 		pbtnPathStart = new GUIButton( 20,  20,  30, 30, ocDataDirPrefix( "graphism/gui/raise" ));
123 		pbtnPathStop1 = new GUIButton( 60,  0,   30, 30, ocDataDirPrefix( "graphism/gui/lower" ));
124 		pbtnPathStop2 = new GUIButton( 100, 20,  30, 30, ocDataDirPrefix( "graphism/gui/lower" ));
125 		pbtnTestBuilding = new GUIButton(  20,  70, 30, 30, ocDataDirPrefix( "graphism/gui/residential" ));
126 		_pctrPath->Add( pbtnPathStart );
127 		_pctrPath->Add( pbtnPathStop1 );
128 		_pctrPath->Add( pbtnPathStop2 );
129 		_pctrPath->Add( pbtnTestBuilding );
130 		pvehicle = NULL;
131 
132 	// Create the GUI
133 		_CreateGUI();
134 	}
135 }
136 
137 
138    /*=====================================================================*/
~City()139 City::~City()
140 {
141 	OPENCITY_DEBUG( "City dtor" );
142 
143 	if (_bGUIEnabled) {
144 	// Delete the GUI
145 		_DeleteGUI();
146 
147 	// testing, delete the pathfinder
148 		delete _pctrPath;
149 		delete pbtnTestBuilding;
150 		delete pbtnPathStart;
151 		delete pbtnPathStop1;
152 		delete pbtnPathStop2;
153 	}
154 
155 // delete all the simulators
156 	_DeleteSimulator();
157 
158 // Delete the pathfinder
159 	delete gVars.gpPathFinder;
160 	gVars.gpPathFinder = NULL;
161 
162 // delete only the OC_LAYER_BUILDING instead of delete [] _apLayer
163 	delete _apLayer[ OC_LAYER_BUILDING ];
164 	_apLayer[ OC_LAYER_BUILDING ] = NULL;
165 
166 // this must be done AFTER deleting the layers
167 //	delete gVars.gpMapMgr;
168 }
169 
170 
171    /*=====================================================================*/
172 void
SaveTo(std::fstream & rfs)173 City::SaveTo( std::fstream& rfs )
174 {
175 	OPENCITY_DEBUG( __PRETTY_FUNCTION__ << "saving" );
176 
177 // Save the data
178 	rfs << _uiIncome << std::ends;
179 	rfs << _liCityFund << std::ends;
180 	rfs << _uiPopulation << std::ends;
181 	rfs << _uiDay << std::ends;
182 	rfs << _uiMonth << std::ends;
183 	rfs << _uiYear << std::ends;
184 	rfs << _uiWidth << std::ends;
185 	rfs << _uiLength << std::ends;
186 
187 // Store the ressource statistics
188 	Ressource res;
189 	int i;
190 	for (i = 0; i < OC_MAX_RESSOURCE_RECORD; i++) {
191 		res = _dqRessource[i];
192 
193 		rfs << res.fund << std::ends;
194 		rfs << res.population << std::ends;
195 		rfs << res.r << std::ends;
196 		rfs << res.c << std::ends;
197 		rfs << res.i << std::ends;
198 		rfs << res.w << std::ends;
199 		rfs << res.e << std::ends;
200 		rfs << res.g << std::ends;
201 	}
202 }
203 
204 
205    /*=====================================================================*/
206 void
LoadFrom(std::fstream & rfs)207 City::LoadFrom( std::fstream& rfs )
208 {
209 	OPENCITY_DEBUG( __PRETTY_FUNCTION__ << "loading" );
210 
211 // Load the data
212 	rfs >> _uiIncome; rfs.ignore();
213 	rfs >> _liCityFund; rfs.ignore();
214 	rfs >> _uiPopulation; rfs.ignore();
215 	rfs >> _uiDay; rfs.ignore();
216 	rfs >> _uiMonth; rfs.ignore();
217 	rfs >> _uiYear; rfs.ignore();
218 	rfs >> _uiWidth; rfs.ignore();
219 	rfs >> _uiLength; rfs.ignore();
220 
221 // Load the ressource statistics
222 	Ressource res;
223 	int i;
224 	for (i = 0; i < OC_MAX_RESSOURCE_RECORD; i++) {
225 		rfs >> res.fund; rfs.ignore();
226 		rfs >> res.population; rfs.ignore();
227 		rfs >> res.r; rfs.ignore();
228 		rfs >> res.c; rfs.ignore();
229 		rfs >> res.i; rfs.ignore();
230 		rfs >> res.w; rfs.ignore();
231 		rfs >> res.e; rfs.ignore();
232 		rfs >> res.g; rfs.ignore();
233 
234 		_dqRessource[i] = res;
235 	}
236 }
237 
238 
239    /*=====================================================================*/
SetCurrentLayer(OPENCITY_CITY_LAYER enumNewLayer)240 void City::SetCurrentLayer( OPENCITY_CITY_LAYER enumNewLayer )
241 {}
242 
243 
244    /*=====================================================================*/
Run()245 void City::Run()
246 {
247 	static uint uiNumberFrame = 0;
248 
249 // Send the movement manager the move order
250 	gVars.gpMoveMgr->Move();
251 
252 // IF the audio is enable THEN autoplay the background music
253 // TODO: optimize this
254 	if (gVars.gboolUseAudio && !gVars.gpAudioMgr->PlayingMusic()) {
255 		gVars.gpAudioMgr->PlayNextMusic();
256 	}
257 
258 // Do not process further if we are in pause mode
259 	if (_eSpeed == OC_SPEED_PAUSE)
260 		return;
261 
262 // IF not new day THEN return
263 	if ( ++uiNumberFrame*gVars.guiMsPerFrame <= OC_MS_PER_DAY )
264 		return;
265 
266 // New day
267 	uint r = _pMSim->GetValue(Simulator::OC_RESIDENTIAL);
268 	uint c = _pMSim->GetValue(Simulator::OC_COMMERCIAL);
269 	uint i = _pMSim->GetValue(Simulator::OC_INDUSTRIAL);
270 
271 	if ( ++_uiDay > 30 ) {
272 	// New month
273 		_uiDay = 1;
274 
275 	// Calculate the current population
276 		_uiPopulation = r + c/2 + i/3;
277 
278 		if ( ++_uiMonth > 12 ) {
279 		// New year
280 			_uiMonth = 1;
281 			_uiYear++;
282 
283 			_DoBill( OC_INCOME );
284 			_RecordRessource();
285 		}
286 		else {
287 			_DoBill( OC_MAINTENANCE_COST );
288 		}
289 	}
290 	uiNumberFrame = 0;
291 
292 // IF the GUI is not enabled THEN do not update it
293 	if (!_bGUIEnabled)
294 		return;
295 
296 // Update the GUI information every 3 days
297 	if ( _uiDay%3 == 0 ) {
298 		uint initialValue = 0;
299 
300 	// Update the RCI bar value
301 		initialValue = (r+c+i) + 1;
302 		_pbarResidence->SetInitialValue( initialValue );
303 		_pbarCommerce->SetInitialValue( initialValue );
304 		_pbarIndustry->SetInitialValue( initialValue );
305 		_pbarResidence->SetValue( r );
306 		_pbarCommerce->SetValue( c );
307 		_pbarIndustry->SetValue( i );
308 
309 	// Update the power bar value
310 		initialValue = _pMSim->GetMaxValue(Simulator::OC_ELECTRIC) + 1;
311 		_pbarPower->SetInitialValue( initialValue );
312 		uint p = _pMSim->GetValue(Simulator::OC_ELECTRIC) > 0 ? _pMSim->GetValue(Simulator::OC_ELECTRIC) : 0;
313 		_pbarPower->SetValue( p );
314 
315 	// Request the renderer to update the minimap
316 		gVars.gpRenderer->bMinimapChange = true;
317 	}
318 }
319 
320 
321    /*=====================================================================*/
Display()322 void City::Display()
323 {
324 	static ostringstream ossStatus;
325 	static bool boolKeyDown;
326 	static int iMouseX, iMouseY;
327 
328 
329 // Process key events such as: up, down, left, right etc..
330 	boolKeyDown = _HandleKeyPressed();
331 
332 // IF the mouse reach the border of the screen, translate the map
333 // NOTE: unused at the moment because it disturbs the GUI
334 //	_HandleMouseXY();
335 
336 // NOTE: We can move the following part to City::uiMouseMotion
337 // however, in this case City::uiMouseMotion is called each time
338 // when the mouse moves, and this is no good.
339 // The user is dragging
340 	if ((_bLMBPressed == true) && (_eCurrentTool != OC_TOOL_NONE )) {
341 	// IF the user is dragging with the left mouse button THEN
342 		if ( SDL_GetMouseState( &iMouseX, &iMouseY ) & SDL_BUTTON(1) ) {
343 			gVars.gpRenderer->GetSelectedWLFrom(
344 				iMouseX, iMouseY,
345 				_uiMapW2, _uiMapL2,
346 				gVars.gpMapMgr, _apLayer[ _eCurrentLayer ] );
347 
348 		// draw the map with the highlighted area
349 			gVars.gpRenderer->DisplayHighlight(
350 				gVars.gpMapMgr, _apLayer[ _eCurrentLayer ],
351 				_uiMapW1, _uiMapL1,
352 				_uiMapW2, _uiMapL2,
353 				_eCurrentTool );
354 
355 			goto cityrun_swap;
356 		}
357 	}
358 
359 // Display the screen as usual
360 	gVars.gpRenderer->Display( gVars.gpMapMgr, _apLayer[ _eCurrentLayer ] );
361 
362 cityrun_swap:
363 // Display build preview
364 	_BuildPreview();
365 
366 // Display the city's funds
367 	ossStatus.str("");
368 	ossStatus << _liCityFund;
369 	_plblFund->SetText( ossStatus.str() );
370 
371 // Display the city population
372 	ossStatus.str("");
373 	ossStatus << _uiPopulation;
374 	_plblPopulation->SetText( ossStatus.str() );
375 
376 // display the date
377 	ossStatus.str("");
378 	ossStatus << _uiDay << "/" << _uiMonth << "/" << _uiYear;
379 	_plblDate->SetText( ossStatus.str() );
380 
381 
382 // Display all the contained movements
383 //	gVars.gpMoveMgr->Move();		// called by Run()
384 	gVars.gpMoveMgr->Display();
385 
386 // FIXME: buggy MAS environment
387 //	gVars.gpEnvironment->displayAgent();
388 
389 // Display the status bar
390 	_pctrStatus->Display();
391 
392 // Display the current container
393 	_pctr->Display();
394 
395 // Display the menu
396 	if (_pctrMenu != NULL)
397 		_pctrMenu->Display();
398 
399 // Swap the buffers and update the screen
400 	SDL_GL_SwapBuffers();
401 }
402 
403 
404    /*=====================================================================*/
405 Layer*
GetLayer(OPENCITY_CITY_LAYER enumLayer) const406 City::GetLayer( OPENCITY_CITY_LAYER enumLayer ) const
407 {
408 	return _apLayer[ enumLayer ];
409 }
410 
411 
412    /*=====================================================================*/
413 const void
GetWL(uint & w,uint & l) const414 City::GetWL(
415 	uint & w, uint & l ) const
416 {
417 	w = _uiWidth;
418 	l = _uiLength;
419 }
420 
421 
422    /*=====================================================================*/
423    /*                    BASE CLASS 'UI' IMPLEMENTATION                   */
424    /*=====================================================================*/
425 
426 
427 
428    /*=====================================================================*/
Keyboard(const SDL_KeyboardEvent & rcEvent)429 void City::Keyboard( const SDL_KeyboardEvent& rcEvent )
430 {
431 //	OPENCITY_DEBUG( "Keydown event received" );
432 
433 // SDL_KEYDOWN or SDL_PRESSED
434 	if (rcEvent.type == SDL_KEYDOWN) {
435 	// test if ALT is pressed
436 		if (rcEvent.keysym.mod & KMOD_ALT) {
437 			_abKeyPressed[KEY_ALT] = true;
438 		}
439 
440 	// key symbols treatment
441 		switch (rcEvent.keysym.sym) {
442 		case SDLK_PAGEUP:
443 			_abKeyPressed[KEY_PAGEUP] = true;
444 			break;
445 		case SDLK_PAGEDOWN:
446 			_abKeyPressed[KEY_PAGEDOWN] = true;
447 			break;
448 
449 		case SDLK_UP:
450 			_abKeyPressed[KEY_UP] = true;
451 			break;
452 		case SDLK_DOWN:
453 			_abKeyPressed[KEY_DOWN] = true;
454 			break;
455 		case SDLK_RIGHT:
456 			_abKeyPressed[KEY_RIGHT] = true;
457 			break;
458 		case SDLK_LEFT:
459 			_abKeyPressed[KEY_LEFT] = true;
460 			break;
461 
462 	// Establish a connection to OCZen
463 		case SDLK_z:
464 			OPENCITY_NET_CODE netCode;
465 			netCode = gVars.gpNetworking->Open( gVars.gsZenServer );
466 			switch (netCode) {
467 				case OC_NET_CLIENT_CONNECTED:
468 					OPENCITY_INFO( "OpenCity is already connected to a server." );
469 					break;
470 				case OC_NET_CLIENT_ACCEPTED:
471 					OPENCITY_INFO( "The connection request has been accepted." );
472 					break;
473 				case OC_NET_CLIENT_REJECTED:
474 					OPENCITY_INFO( "The connection request has been rejected. Is the server full ?" );
475 					break;
476 				default:
477 					OPENCITY_INFO( "The connection to \"" << gVars.gsZenServer << "\" has failed." );
478 			}
479 			break;
480 
481 		case SDLK_n:	// set the tool to "None"
482 			_SetCurrentTool(  OC_TOOL_NONE );
483 			break;
484 		case SDLK_r:	// set tool for "zone residential"
485 			_SetCurrentTool( OC_TOOL_ZONE_RES );
486 			break;
487 		case SDLK_c:	// set tool for "zone commercial"
488 			_SetCurrentTool( OC_TOOL_ZONE_COM );
489 			break;
490 		case SDLK_i:	// set tool for "zone industrial"
491 			_SetCurrentTool( OC_TOOL_ZONE_IND );
492 			break;
493 
494 		case SDLK_p:	// set tool for "building road"
495 			_SetCurrentTool( OC_TOOL_ROAD );
496 			break;
497 		case SDLK_l:	// set tool for building electric lines
498 			_SetCurrentTool( OC_TOOL_ELINE );
499 			break;
500 		case SDLK_e:	// set tool for building electric plants
501 			_SetCurrentTool( OC_TOOL_EPLANT_NUCLEAR );
502 			break;
503 
504 		case SDLK_u:	// height up
505 			_SetCurrentTool( OC_TOOL_HEIGHT_UP );
506 			break;
507 		case SDLK_d:	// height down
508 			_SetCurrentTool( OC_TOOL_HEIGHT_DOWN );
509 			break;
510 		case SDLK_q:	//query tool
511 			_SetCurrentTool( OC_TOOL_QUERY );
512 			break;
513 		case SDLK_x:	// destroy
514 			_SetCurrentTool( OC_TOOL_DESTROY );
515 			break;
516 
517 
518 		case SDLK_b:	// toggle structures on/off
519 			gVars.gpRenderer->ToggleStructure();
520 			break;
521 		case SDLK_f:	// toggle wireframe on/off
522 			gVars.gpRenderer->ToggleWireFrame();
523 			break;
524 		case SDLK_g:	// toggle grid on/off
525 			gVars.gpRenderer->ToggleGrid();
526 			break;
527 		case SDLK_k:	// toggle compass on/off
528 		// Do not mess up the menu
529 			if (_pctrMenu != NULL)
530 				break;
531 
532 			_bStatusVisible = !_bStatusVisible;
533 			gVars.gpRenderer->ToggleCompass();
534 			if (_bStatusVisible)
535 				_pctrStatus->Set( OC_GUIMAIN_VISIBLE );
536 			else
537 				_pctrStatus->Unset( OC_GUIMAIN_VISIBLE );
538 			break;
539 		case SDLK_o:	// toggle projection mode
540 			gVars.gpRenderer->ToggleProjection();
541 			break;
542 		case SDLK_t:	// toggle terrain display
543 			gVars.gpRenderer->ToggleTerrain();
544 			break;
545 		case SDLK_w:	// toggle water display
546 			gVars.gpRenderer->ToggleWater();
547 			break;
548 
549 
550 		case SDLK_INSERT: // zoom in
551 			_abKeyPressed[KEY_INSERT] = true;
552 			break;
553 		case SDLK_DELETE: // zoom out
554 			_abKeyPressed[KEY_DELETE] = true;
555 			break;
556 
557 
558 	// manipulating the music player
559 		case SDLK_GREATER:
560 			gVars.gpAudioMgr->PlayNextMusic();
561 			break;
562 		case SDLK_LESS:
563 			gVars.gpAudioMgr->PlayPreviousMusic();
564 			break;
565 		case SDLK_s:
566 			gVars.gpAudioMgr->ToggleSound();
567 			break;
568 		case SDLK_m:
569 			gVars.gpAudioMgr->ToggleMusic();
570 			break;
571 
572 
573 	// Save and load
574 		case SDLK_F2:
575 			_Save( ocSaveDirPrefix( "opencity.save" ) );
576 			break;
577 		case SDLK_F6:
578 			_Load( ocSaveDirPrefix( "opencity.save" ) );
579 			break;
580 
581 
582 		case SDLK_h:
583 			gVars.gpRenderer->Home();
584 			break;
585 
586 
587 		case SDLK_ESCAPE:	// Open/close the main menu
588 			if (_pctrMenu == NULL) {
589 				_LoadMenu();
590 			}
591 			else {
592 				_UnloadMenu();
593 			}
594 			break;
595 
596 #ifndef NDEBUG
597 	// Testing PathFinder
598 		case SDLK_a:
599 			_pctr->ResetAttribute( OC_GUIMAIN_CLICKED | OC_GUIMAIN_MOUSEOVER );
600 
601 		// Toggle Main <-> Pathfinding toolcircle
602 			if (_pctr == _pctrPath ) {
603 				_pctr = _pctrMain;
604 			}
605 			else {
606 				_pctr = _pctrPath;
607 			}
608 			if ( _pctr->IsSet( OC_GUIMAIN_VISIBLE ) == false ) {
609 				_pctr->Set( OC_GUIMAIN_VISIBLE );
610 			}
611 			break;
612 
613 	// MAS test toolcircle
614 		case SDLK_v:
615 			_pctr->ResetAttribute( OC_GUIMAIN_CLICKED | OC_GUIMAIN_MOUSEOVER );
616 
617 		// Toggle Main <-> MAS toolcircle
618 			if ( _pctr == _pctrMAS ) {
619 				_pctr = _pctrMain;
620 			}
621 			else {
622 				_pctr = _pctrMAS;
623 			}
624 			if ( _pctr->IsSet( OC_GUIMAIN_VISIBLE ) == false ) {
625 				_pctr->Set( OC_GUIMAIN_VISIBLE );
626 			}
627 			break;
628 #endif
629 
630 		default:
631 			break;
632 		}
633 	}
634 // SDL_KEYUP or SDL_RELEASED
635 	else {
636 	// test if ALT is released
637 		if (!(rcEvent.keysym.mod & KMOD_ALT)) {
638 			_abKeyPressed[KEY_ALT] = false;
639 		}
640 
641 	// other key symbols treatment
642 		switch (rcEvent.keysym.sym) {
643 
644 		case SDLK_PAGEUP:
645 			_abKeyPressed[KEY_PAGEUP] = false;
646 			break;
647 		case SDLK_PAGEDOWN:
648 			_abKeyPressed[KEY_PAGEDOWN] = false;
649 			break;
650 
651 		case SDLK_UP:
652 			_abKeyPressed[KEY_UP] = false;
653 			break;
654 		case SDLK_DOWN:
655 			_abKeyPressed[KEY_DOWN] = false;
656 			break;
657 		case SDLK_RIGHT:
658 			_abKeyPressed[KEY_RIGHT] = false;
659 			break;
660 		case SDLK_LEFT:
661 			_abKeyPressed[KEY_LEFT] = false;
662 			break;
663 
664 		case SDLK_INSERT: // zoom in
665 			_abKeyPressed[KEY_INSERT] = false;
666 			break;
667 		case SDLK_DELETE: // zoom out
668 			_abKeyPressed[KEY_DELETE] = false;
669 			break;
670 
671 		default:
672 			break;
673 		} // switch
674 	} // key released
675 
676 }
677 
678 
679    /*=====================================================================*/
680 void
MouseMotion(const SDL_MouseMotionEvent & rcEvent)681 City::MouseMotion( const SDL_MouseMotionEvent& rcEvent )
682 {
683 //	OPENCITY_DEBUG("Mouse moved");
684 
685 // We process the menu first
686 	if (_pctrMenu != NULL) {
687 		_pctrMenu->MouseMotion( rcEvent );
688 	}
689 	else {
690 		_pctr->MouseMotion( rcEvent );
691 		_pctrStatus->MouseMotion( rcEvent );
692 	}
693 }
694 
695 
696    /*=====================================================================*/
697 void
MouseButton(const SDL_MouseButtonEvent & rcsMBE)698 City::MouseButton( const SDL_MouseButtonEvent& rcsMBE )
699 {
700 //	OPENCITY_DEBUG("Mouse button event received" );
701 
702 // IF the menu is opened THEN process the mouse click on the menu and return
703 	if (_pctrMenu != NULL ) {
704 		_pctrMenu->MouseButton( rcsMBE );
705 		if ( _pctrMenu->GetClick() != 0 ) {
706 			_HandleMenuClick();
707 			_bLMBPressed = false;
708 		}
709 		return;
710 	}
711 
712 // Process the mouse click on the status bar
713 	_pctrStatus->MouseButton( rcsMBE );
714 	if ( _pctrStatus->GetClick() != 0 ) {
715 		_HandleStatusClick();
716 		_bLMBPressed = false;
717 		return;
718 	}
719 
720 // Process the click concerning the GUI
721 	_pctr->MouseButton( rcsMBE );
722 	if ( _pctr->GetClick() != 0 ) {
723 		_HandleGUIClick();
724 		_bLMBPressed = false;
725 		return;
726 	}
727 
728 // The user didn't click on a GUI object so we look for clicks on the map
729 	switch (rcsMBE.state) {
730 		case SDL_PRESSED: {
731 			_bLMBPressed = false;
732 			if ((rcsMBE.button == SDL_BUTTON_LEFT)
733 				and
734 				(gVars.gpRenderer->GetSelectedWLFrom(
735 					rcsMBE.x, rcsMBE.y, _uiMapW1, _uiMapL1,
736 					gVars.gpMapMgr, _apLayer[ _eCurrentLayer ]) == true))
737 			{
738 				_bLMBPressed = true;
739 			} //if
740 //debug begin
741 //SDL_GL_SwapBuffers(); // uncomment this if you want to know how it works
742 //SDL_Delay( 500 );
743 //debug end
744 
745 		// RMB (right mouse button) close/open the toolcircle
746 			if (rcsMBE.button == SDL_BUTTON_RIGHT) {
747 			// IF the user has invoked "Query" THEN we destroy it first
748 				if (_pctr == _pctrQ) {
749 					_pctr = _pctrMain;
750 				// Enable the visible bit since, it is disabled later
751 				// the main toolcircle won't be displayed
752 					_pctr->Set( OC_GUIMAIN_VISIBLE );
753 				}
754 
755 				if (_pctr->IsSet( OC_GUIMAIN_VISIBLE ) == true) {
756 					_pctr->Unset( OC_GUIMAIN_VISIBLE );
757 				}
758 				else {
759 					_pctr->SetLocation( rcsMBE.x - 70, _iWinHeight - rcsMBE.y - 70 );
760 					_pctr->Set( OC_GUIMAIN_VISIBLE );
761 				}
762 			}
763 
764 		// Wheel button forward
765 			if (rcsMBE.button == 4) {
766 			// move right if CTRL pressed
767 				if (SDL_GetModState() & KMOD_CTRL)
768 					gVars.gpRenderer->MoveRight();
769 
770 			// move up if SHIFT pressed
771 				if (SDL_GetModState() & KMOD_SHIFT)
772 					gVars.gpRenderer->MoveUp();
773 
774 			// zoom in if nothing pressed
775 				if (!(SDL_GetModState() & (KMOD_SHIFT | KMOD_CTRL)))
776 					gVars.gpRenderer->ZoomIn();
777 			}
778 
779 		// Wheel button backward
780 			if (rcsMBE.button == 5) {
781 			// move right if CTRL pressed
782 				if (SDL_GetModState() & KMOD_CTRL)
783 					gVars.gpRenderer->MoveLeft();
784 
785 			// move up if SHIFT pressed
786 				if (SDL_GetModState() & KMOD_SHIFT)
787 					gVars.gpRenderer->MoveDown();
788 
789 			// zoom in if nothing pressed
790 				if (!(SDL_GetModState() & (KMOD_SHIFT | KMOD_CTRL)))
791 					gVars.gpRenderer->ZoomOut();
792 			}
793 
794 		break;
795 		} //case SDL_PRESSED
796 
797 	   //-------------------------------------------------------
798 		case SDL_RELEASED: {
799 			// IF Ctrl not pressed,
800 			// AND dragging enabled
801 			// AND mouse button was correctly released in the map
802 			// THEN do tool
803 			if (not (SDL_GetModState() & KMOD_CTRL)
804 				and _bLMBPressed
805 				and gVars.gpRenderer->GetSelectedWLFrom(
806 					rcsMBE.x, rcsMBE.y,
807 					_uiMapW2, _uiMapL2,
808 					gVars.gpMapMgr,
809 					_apLayer[ _eCurrentLayer ] ))
810 			{
811 //debug
812 //cout << "W2: " << _uiMapW2 << "/" << "H2: "
813 //     << _uiMapL2 << endl;
814 //test pathfinding
815 				_TestPathfinding();
816 				_DoTool( rcsMBE );
817 			} //if
818 			_bLMBPressed = false;
819 			break;
820 
821 		} //case SDL_RELEASED
822 
823 	} // switch
824 }
825 
826 
827    /*=====================================================================*/
828 void
Expose(const SDL_ExposeEvent & rcEvent)829 City::Expose( const SDL_ExposeEvent& rcEvent )
830 {
831 	OPENCITY_DEBUG( "Expose event received" );
832 
833 	gVars.gpRenderer->Display( gVars.gpMapMgr, _apLayer[ _eCurrentLayer ] );
834 	_pctr->Expose( rcEvent );
835 	_pctrStatus->Expose( rcEvent );
836 	if (_pctrMenu != NULL) {
837 		_pctrMenu->Expose( rcEvent );
838 	}
839 
840 	SDL_GL_SwapBuffers();
841 }
842 
843 
844    /*=====================================================================*/
Resize(const SDL_ResizeEvent & rcEvent)845 void City::Resize( const SDL_ResizeEvent& rcEvent )
846 {
847 	OPENCITY_DEBUG( "Resize event received" );
848 
849 // Set the new window's size
850 	_iWinWidth = rcEvent.w;
851 	_iWinHeight = rcEvent.h;
852 	gVars.gpRenderer->SetWinSize( _iWinWidth, _iWinHeight );
853 
854 // Resize the main status bar and reposition it
855 	_pctrStatus->Resize( rcEvent );
856 	_pctrStatus->SetLocation( (_iWinWidth-512)/2, 0 );
857 
858 // Tell the containers about the event
859 	_pctrMain->Resize( rcEvent );
860 	_pctrL->Resize( rcEvent );
861 	_pctrT->Resize( rcEvent );
862 	_pctrZ->Resize( rcEvent );
863 	_pctrG->Resize( rcEvent );
864 	_pctrN->Resize( rcEvent );
865 	_pctrS->Resize( rcEvent );
866 	_pctrPath->Resize( rcEvent );
867 	_pctrMAS->Resize( rcEvent );
868 
869 	if (_pctrMenu != NULL) {
870 		_pctrMenu->Resize( rcEvent );
871 		_pctrMenu->SetSize( _iWinWidth, _iWinHeight );
872 		_CenterMenu();
873 	}
874 
875 // IF the query tool is displayed THEN invoke the resize event
876 	if (_pctrQ != NULL) {
877 		_pctrQ->Resize( rcEvent );
878 	}
879 }
880 
881 
882 
883 
884 
885 
886 
887 
888 
889 
890 
891 
892 
893 
894    /*=====================================================================*/
895    /*                        PRIVATE     METHODS                          */
896    /*=====================================================================*/
897 
898 
899 
900 
901 
902 
_CreateTree()903 void City::_CreateTree()
904 {
905 // Create a new tree density map
906 	int* treeDensity = gVars.gpMapMaker->getTreeDensity();
907 
908 // Build the trees according to the density map
909 	uint cost = 0;
910 	for (uint l = 0, linear = 0; l < _uiLength; l++)
911 	for (uint w = 0; w < _uiWidth; w++, linear++) {
912 		if (treeDensity[linear] > 0) {
913 			_apLayer[ OC_LAYER_BUILDING ]->BuildStructure( w, l, w, l, OC_STRUCTURE_FLORA, cost );
914 		}
915 	}
916 
917 	delete [] treeDensity;
918 }
919 
920 
921    /*=====================================================================*/
_CreateSimulator()922 void City::_CreateSimulator()
923 {
924 // Simulators' initialization
925 	_pMSim = new MainSim( gVars.gpmutexSim, (BuildingLayer*)_apLayer[ OC_LAYER_BUILDING ], gVars.gpMapMgr );
926 
927 // Now initialize simulators threads
928 	_pthreadMSim = SDL_CreateThread( Simulator::ThreadWrapper, _pMSim );
929 
930 // Kept for future reference
931 // How can I put funcTSim into the TrafficSim class ?
932 //
933 //	int (*fn)(void*);
934 //	fn = reinterpret_cast<int (*)(void*)>(&TrafficSim::Run);
935 //	pthreadTSim = SDL_CreateThread( TrafficSim::Run, pTSim );
936 //
937 
938 // Put all the simulators' threads into RUN state
939 	_pMSim->Run();
940 }
941 
942 
943    /*=====================================================================*/
944 void
_DeleteSimulator()945 City::_DeleteSimulator()
946 {
947 	int iStatus;
948 
949 // put all the simulators' threads into RETURN state
950 	_pMSim->Return();
951 
952 // wait for simulator threads to end
953 	SDL_WaitThread( _pthreadMSim, &iStatus );
954 
955 // delete simulators at the end
956 	delete _pMSim;
957 }
958 
959 
960    /*=====================================================================*/
961 void
_CreateGUI()962 City::_CreateGUI()
963 {
964 	ostringstream ossTemp;
965 
966 // Load the buttons used by the status bar
967 	_apbtnCurrentTool[OC_TOOL_NONE]
968 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/unknown" ));
969 	_apbtnCurrentTool[OC_TOOL_DESTROY]
970 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/destroy" ));
971 	_apbtnCurrentTool[OC_TOOL_ZONE_RES]
972 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/residential" ));
973 	_apbtnCurrentTool[OC_TOOL_ZONE_COM]
974 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/commercial" ));
975 	_apbtnCurrentTool[OC_TOOL_ZONE_IND]
976 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/industrial" ));
977 	_apbtnCurrentTool[OC_TOOL_HEIGHT_UP]
978 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/raise" ));
979 	_apbtnCurrentTool[OC_TOOL_HEIGHT_DOWN]
980 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/lower" ));
981 	_apbtnCurrentTool[OC_TOOL_ROAD]
982 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/road" ));
983 	_apbtnCurrentTool[OC_TOOL_ELINE]
984 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/power_line" ));
985 	_apbtnCurrentTool[OC_TOOL_EPLANT_COAL]
986 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/power_plant_coal" ));
987 	_apbtnCurrentTool[OC_TOOL_EPLANT_NUCLEAR]
988 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/power_plant_nuclear" ));
989 	_apbtnCurrentTool[OC_TOOL_PARK]
990 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/park" ));
991 	_apbtnCurrentTool[OC_TOOL_FLORA]
992 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/tree" ));
993 	_apbtnCurrentTool[OC_TOOL_FIRE]
994 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/fire" ));
995 
996 	_apbtnCurrentTool[OC_TOOL_POLICE]
997 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/police" ));
998 	_apbtnCurrentTool[OC_TOOL_HOSPITAL]
999 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/hospital" ));
1000 	_apbtnCurrentTool[OC_TOOL_EDUCATION]
1001 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/education" ));
1002 	_apbtnCurrentTool[OC_TOOL_QUERY]
1003 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/query" ));
1004 
1005 	_apbtnCurrentTool[OC_TOOL_AGENT_POLICE]
1006 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/unknown" ));
1007 	_apbtnCurrentTool[OC_TOOL_AGENT_DEMONSTRATOR]
1008 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/unknown" ));
1009 	_apbtnCurrentTool[OC_TOOL_AGENT_ROBBER]
1010 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/unknown" ));
1011 	_apbtnCurrentTool[OC_TOOL_TEST_BUILDING]
1012 		= new GUIButton( GUIBUTTON_POSITION_TOOL, ocDataDirPrefix( "graphism/gui/status/unknown" ));
1013 
1014 // The status bar
1015 	_pbtnPause = new GUIButton( 54, 4, 24, 24, ocDataDirPrefix( "graphism/gui/status/speed_pause" ));
1016 	_pbtnPlay  = new GUIButton( 54, 4, 24, 24, ocDataDirPrefix( "graphism/gui/status/speed_play" ));
1017 	_pbtnPause->Unset( OC_GUIMAIN_VISIBLE );
1018 
1019 	ossTemp << _liCityFund;
1020 	_plblFund = new GUILabel( 125, 11, 80, 10, ossTemp.str() );
1021 	_plblFund->SetAlign( GUILabel::OC_ALIGN_RIGHT );
1022 	_plblFund->SetForeground( OPENCITY_PALETTE[Color::OC_WHITE] );
1023 
1024 	ossTemp.str("");
1025 	ossTemp << _uiPopulation;
1026 	_plblPopulation = new GUILabel( 240, 11, 80, 10, ossTemp.str() );
1027 	_plblPopulation->SetAlign( GUILabel::OC_ALIGN_RIGHT );
1028 	_plblPopulation->SetForeground( OPENCITY_PALETTE[Color::OC_WHITE] );
1029 
1030 	ossTemp.str("");
1031 	ossTemp << _uiDay << "/" << _uiMonth << "/" << _uiYear;
1032 	_plblDate = new GUILabel( 348, 11, 80, 10, ossTemp.str() );
1033 	_plblDate->SetAlign( GUILabel::OC_ALIGN_CENTER );
1034 	_plblDate->SetForeground( OPENCITY_PALETTE[Color::OC_WHITE] );
1035 
1036 	_pbarResidence = new GUIBar( 5, 5, 7, 53 );
1037 	_pbarResidence->SetForeground( OPENCITY_PALETTE[Color::OC_GREEN] );
1038 
1039 	_pbarCommerce = new GUIBar( 18, 5, 7, 53 );
1040 	_pbarCommerce->SetForeground( OPENCITY_PALETTE[Color::OC_BLUE] );
1041 
1042 	_pbarIndustry = new GUIBar( 29, 5, 7, 53 );
1043 	_pbarIndustry->SetForeground( OPENCITY_PALETTE[Color::OC_YELLOW] );
1044 
1045 	_pbarPower = new GUIBar( 42, 5, 7, 53 );
1046 	_pbarPower->SetForeground( OPENCITY_PALETTE[Color::OC_PINK] );
1047 
1048 	_pctrStatus =
1049 		new GUIContainer( (_iWinWidth-512)/2, 0, 512, 64, ocDataDirPrefix( "graphism/gui/main_status_bar.png" ) );
1050 	_pctrStatus->Add( _pbtnPause );
1051 	_pctrStatus->Add( _pbtnPlay );
1052 	_pctrStatus->Add( _plblFund );
1053 	_pctrStatus->Add( _plblPopulation );
1054 	_pctrStatus->Add( _plblDate );
1055 	_pctrStatus->Add( _pbarResidence );
1056 	_pctrStatus->Add( _pbarCommerce );
1057 	_pctrStatus->Add( _pbarIndustry );
1058 	_pctrStatus->Add( _pbarPower );
1059 	_pctrStatus->Set( OC_GUIMAIN_VISIBLE );
1060 
1061 // The status bar buttons
1062 	for (int i = 0; i < OC_TOOL_NUMBER; i++) {
1063 		_apbtnCurrentTool[i]->Unset( OC_GUIMAIN_VISIBLE );
1064 		_pctrStatus->Add( _apbtnCurrentTool[i] );
1065 	}
1066 	_apbtnCurrentTool[OC_TOOL_NONE]->Set( OC_GUIMAIN_VISIBLE );
1067 
1068 // GUI main toolcircle
1069 	pbtnZ = new GUIButton( GUIBUTTON_POSITION_1, ocDataDirPrefix( "graphism/gui/zone" ));
1070 	pbtnS = new GUIButton( GUIBUTTON_POSITION_5, ocDataDirPrefix( "graphism/gui/save" ));
1071 	pbtnL = new GUIButton( GUIBUTTON_POSITION_2, ocDataDirPrefix( "graphism/gui/power" ));
1072 	pbtnP = new GUIButton( GUIBUTTON_POSITION_3, ocDataDirPrefix( "graphism/gui/road" ));
1073 	pbtnX = new GUIButton( GUIBUTTON_POSITION_4, ocDataDirPrefix( "graphism/gui/bulldozer" ));
1074 	pbtnG = new GUIButton( GUIBUTTON_POSITION_6, ocDataDirPrefix( "graphism/gui/government" ));
1075 
1076 	_pctrMain = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1077 	_pctrMain->Add( pbtnZ );
1078 	_pctrMain->Add( pbtnS );
1079 	_pctrMain->Add( pbtnL );
1080 	_pctrMain->Add( pbtnP );
1081 	_pctrMain->Add( pbtnX );
1082 	_pctrMain->Add( pbtnG );
1083 
1084 
1085 // GUI Z toolcircle for RCI buttons
1086 	pbtnZB = new GUIButton( GUIBUTTON_POSITION_1, ocDataDirPrefix( "graphism/gui/back" ));
1087 	pbtnZR = new GUIButton( GUIBUTTON_POSITION_2, ocDataDirPrefix( "graphism/gui/residential" ));
1088 	pbtnZC = new GUIButton( GUIBUTTON_POSITION_3, ocDataDirPrefix( "graphism/gui/commercial" ));
1089 	pbtnZI = new GUIButton( GUIBUTTON_POSITION_4, ocDataDirPrefix( "graphism/gui/industrial" ));
1090 
1091 	_pctrZ = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1092 	_pctrZ->Add( pbtnZB );
1093 	_pctrZ->Add( pbtnZR );
1094 	_pctrZ->Add( pbtnZC );
1095 	_pctrZ->Add( pbtnZI );
1096 
1097 
1098 // GUI L toolcircle ( electric lines, electric plants )
1099 	pbtnLB = new GUIButton( GUIBUTTON_POSITION_2, ocDataDirPrefix( "graphism/gui/back" ));
1100 	pbtnLL = new GUIButton( GUIBUTTON_POSITION_3, ocDataDirPrefix( "graphism/gui/power_line" ));
1101 	pbtnLN = new GUIButton( GUIBUTTON_POSITION_4, ocDataDirPrefix( "graphism/gui/power_plant_nuclear" ));
1102 	pbtnLC = new GUIButton( GUIBUTTON_POSITION_5, ocDataDirPrefix( "graphism/gui/power_plant_coal" ));
1103 
1104 	_pctrL = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1105 	_pctrL->Add( pbtnLB );
1106 	_pctrL->Add( pbtnLL );
1107 	_pctrL->Add( pbtnLN );
1108 	_pctrL->Add( pbtnLC );
1109 
1110 
1111 // GUI T toolcircle ( raise, lower terrain )
1112 	pbtnTU = new GUIButton( GUIBUTTON_POSITION_2, ocDataDirPrefix( "graphism/gui/raise" ));
1113 	pbtnTD = new GUIButton( GUIBUTTON_POSITION_3, ocDataDirPrefix( "graphism/gui/lower" ));
1114 	pbtnTB = new GUIButton( GUIBUTTON_POSITION_4, ocDataDirPrefix( "graphism/gui/back" ));
1115 	pbtnTX = new GUIButton( GUIBUTTON_POSITION_1, ocDataDirPrefix( "graphism/gui/destroy" ));
1116 	pbtnTQ = new GUIButton( GUIBUTTON_POSITION_5, ocDataDirPrefix( "graphism/gui/query" ));
1117 
1118 	_pctrT = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1119 	_pctrT->Add( pbtnTB );
1120 	_pctrT->Add( pbtnTU );
1121 	_pctrT->Add( pbtnTD );
1122 	_pctrT->Add( pbtnTX );
1123 	_pctrT->Add( pbtnTQ );
1124 
1125 
1126 // GUI Gouvernement toolcircle ( park, education, hospital, police and fire )
1127 	pbtnGB = new GUIButton( GUIBUTTON_POSITION_6, ocDataDirPrefix( "graphism/gui/back" ));
1128 	pbtnGP = new GUIButton( GUIBUTTON_POSITION_1, ocDataDirPrefix( "graphism/gui/park" ));
1129 	pbtnGE = new GUIButton( GUIBUTTON_POSITION_5, ocDataDirPrefix( "graphism/gui/education" ));
1130 	pbtnGH = new GUIButton( GUIBUTTON_POSITION_2, ocDataDirPrefix( "graphism/gui/hospital" ));
1131 	pbtnGL = new GUIButton( GUIBUTTON_POSITION_3, ocDataDirPrefix( "graphism/gui/police" ));
1132 	pbtnGF = new GUIButton( GUIBUTTON_POSITION_4, ocDataDirPrefix( "graphism/gui/fire" ));
1133 
1134 	_pctrG = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1135 	_pctrG->Add( pbtnGB );
1136 	_pctrG->Add( pbtnGP );
1137 	_pctrG->Add( pbtnGE );
1138 	_pctrG->Add( pbtnGH );
1139 	_pctrG->Add( pbtnGL );
1140 	_pctrG->Add( pbtnGF );
1141 
1142 
1143 // Create the nature container
1144 	pbtnNB = new GUIButton( GUIBUTTON_POSITION_1, ocDataDirPrefix( "graphism/gui/back" ));
1145 	pbtnNP = new GUIButton( GUIBUTTON_POSITION_6, ocDataDirPrefix( "graphism/gui/park_city" ));
1146 	pbtnNT = new GUIButton( GUIBUTTON_POSITION_5, ocDataDirPrefix( "graphism/gui/tree" ));
1147 
1148 	_pctrN = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1149 	_pctrN->Add( pbtnNB );
1150 	_pctrN->Add( pbtnNP );
1151 	_pctrN->Add( pbtnNT );
1152 
1153 
1154 // Create save/load buttons and the container
1155 	pbtnSL = new GUIButton( GUIBUTTON_POSITION_1, ocDataDirPrefix( "graphism/gui/save_load" ));
1156 	pbtnSS = new GUIButton( GUIBUTTON_POSITION_6, ocDataDirPrefix( "graphism/gui/save_save" ));
1157 	pbtnSB = new GUIButton( GUIBUTTON_POSITION_5, ocDataDirPrefix( "graphism/gui/back" ));
1158 
1159 	_pctrS = new GUIContainer( 100, 100, 140, 140, ocDataDirPrefix( "graphism/gui/toolcircle_bg.png" ) );
1160 	_pctrS->Add( pbtnSB );
1161 	_pctrS->Add( pbtnSS );
1162 	_pctrS->Add( pbtnSL );
1163 
1164 
1165 // MAS toolcircle
1166 	_pctrMAS = new GUIContainer( 100, 100, 140, 140 );
1167 	pbtnMASPolice = new GUIButton( 20,  20,  30, 30, ocDataDirPrefix( "graphism/gui/police" ));
1168 	pbtnMASDemonstrator = new GUIButton( 60,  0,   30, 30, ocDataDirPrefix( "graphism/gui/demonstrator" ));
1169 	pbtnMASRobber = new GUIButton( 100, 20,  30, 30, ocDataDirPrefix( "graphism/gui/robber" ));
1170 	_pctrMAS->Add( pbtnMASPolice );
1171 	_pctrMAS->Add( pbtnMASDemonstrator );
1172 	_pctrMAS->Add( pbtnMASRobber );
1173 
1174 	pbtnMASRobber->Unset( OC_GUIMAIN_VISIBLE );
1175 
1176 // the current _pctr points to the MAIN one
1177 	_pctr = _pctrMain;
1178 
1179 // there isn't a query container
1180 	_pctrQ = NULL;
1181 }
1182 
1183 
1184    /*=====================================================================*/
1185 void
_DeleteGUI()1186 City::_DeleteGUI()
1187 {
1188 	_pctrQ = NULL;
1189 
1190 // MAS toolcircle
1191 	delete _pctrMAS;
1192 	delete pbtnMASRobber;
1193 	delete pbtnMASDemonstrator;
1194 	delete pbtnMASPolice;
1195 
1196 // Load/save toolcircle
1197 	delete _pctrS;
1198 	delete pbtnSB;
1199 	delete pbtnSS;
1200 	delete pbtnSL;
1201 
1202 // Nature toolcircle
1203 	delete _pctrN;
1204 	delete pbtnNB;
1205 	delete pbtnNP;
1206 	delete pbtnNT;
1207 
1208 // GUI G toolcircle ( park, education, hospital, police and fire )
1209 	delete _pctrG;
1210 	delete pbtnGB;
1211 	delete pbtnGP;
1212 	delete pbtnGE;
1213 	delete pbtnGH;
1214 	delete pbtnGL;
1215 	delete pbtnGF;
1216 
1217 // GUI T toolcircle ( raise, lower terrain )
1218 	delete _pctrT;
1219 	delete pbtnTB;
1220 	delete pbtnTU;
1221 	delete pbtnTD;
1222 	delete pbtnTX;
1223 	delete pbtnTQ;
1224 
1225 // GUI L toolcircle ( electric lines, electric plants )
1226 	delete _pctrL;
1227 	delete pbtnLB;
1228 	delete pbtnLL;
1229 	delete pbtnLN;
1230 	delete pbtnLC;
1231 
1232 // GUI Z toolcircle
1233 	delete _pctrZ;
1234 	delete pbtnZB;
1235 	delete pbtnZR;
1236 	delete pbtnZC;
1237 	delete pbtnZI;
1238 
1239 // GUI main toolcircle
1240 	delete _pctrMain;
1241 	delete pbtnZ;
1242 	delete pbtnS;
1243 	delete pbtnL;
1244 	delete pbtnP;
1245 	delete pbtnX;
1246 	delete pbtnG;
1247 
1248 // Delete the status bar
1249 	delete _pctrStatus;
1250 	delete _pbarPower;
1251 	delete _pbarIndustry;
1252 	delete _pbarCommerce;
1253 	delete _pbarResidence;
1254 	delete _plblFund;
1255 	delete _plblPopulation;
1256 	delete _plblDate;
1257 	delete _pbtnPlay;
1258 	delete _pbtnPause;
1259 
1260 // The status bar buttons
1261 	for (int i = 0; i < OC_TOOL_NUMBER; i++) {
1262 		delete _apbtnCurrentTool[i];
1263 		_apbtnCurrentTool[i] = NULL;		// Safe
1264 	}
1265 }
1266 
1267 
1268    /*=====================================================================*/
1269 void
_LoadMenu()1270 City::_LoadMenu()
1271 {
1272 	_pbtnMenuNew  = new GUIButton( 0, 0, 128, 128, ocDataDirPrefix("graphism/gui/main_menu_new") );
1273 	_pbtnMenuLoad = new GUIButton( 0, 0, 128, 128, ocDataDirPrefix("graphism/gui/main_menu_load") );
1274 	_pbtnMenuSave = new GUIButton( 0, 0, 128, 128, ocDataDirPrefix("graphism/gui/main_menu_save") );
1275 	_pbtnMenuQuit = new GUIButton( 0, 0, 128, 128, ocDataDirPrefix("graphism/gui/main_menu_quit") );
1276 
1277 	_pctrMenu = new GUIContainer(
1278 		0, 0, _iWinWidth, _iWinHeight, ocDataDirPrefix("graphism/gui/main_menu_bg.png")
1279 	);
1280 	_pctrMenu->Add( _pbtnMenuNew );
1281 	_pctrMenu->Add( _pbtnMenuLoad );
1282 	_pctrMenu->Add( _pbtnMenuSave );
1283 	_pctrMenu->Add( _pbtnMenuQuit );
1284 	_pctrMenu->Set( OC_GUIMAIN_VISIBLE );
1285 
1286 // Hide the status bar and the compass
1287 	if (_bStatusVisible) {
1288 		gVars.gpRenderer->ToggleCompass();
1289 		_pctrStatus->Unset( OC_GUIMAIN_VISIBLE );
1290 	}
1291 
1292 	_CenterMenu();
1293 }
1294 
1295 
1296    /*=====================================================================*/
1297 void
_CenterMenu()1298 City::_CenterMenu()
1299 {
1300 	assert( _pctrMenu != NULL );
1301 
1302 // Center the menu
1303 	int x = _iWinWidth/2;
1304 	int y = _iWinHeight/2;
1305 	_pbtnMenuNew->SetLocation( x-264, y );
1306 	_pbtnMenuLoad->SetLocation( x-64, y );
1307 	_pbtnMenuSave->SetLocation( x+136, y );
1308 	_pbtnMenuQuit->SetLocation( _iWinWidth-150, 22 );
1309 
1310 // Push the mouse motion event to activate the over state if necessary
1311 	SDL_Event event;
1312 	int mouseX, mouseY;
1313 	event.type = SDL_MOUSEMOTION;
1314 	event.motion.type = SDL_MOUSEMOTION;
1315 	event.motion.state = SDL_GetMouseState(&mouseX, &mouseY);
1316 	event.motion.x = mouseX;
1317 	event.motion.y = mouseY;
1318 	event.motion.xrel = 0;
1319 	event.motion.yrel = 0;
1320 	SDL_PushEvent(&event);
1321 }
1322 
1323 
1324    /*=====================================================================*/
1325 void
_UnloadMenu()1326 City::_UnloadMenu()
1327 {
1328 	delete _pctrMenu;
1329 	delete _pbtnMenuQuit;
1330 	delete _pbtnMenuSave;
1331 	delete _pbtnMenuLoad;
1332 	delete _pbtnMenuNew;
1333 
1334 	_pctrMenu = NULL;
1335 
1336 // IF the status bar was visible THEN display it now
1337 	if (_bStatusVisible) {
1338 		gVars.gpRenderer->ToggleCompass();
1339 		_pctrStatus->Set( OC_GUIMAIN_VISIBLE );
1340 	}
1341 }
1342 
1343 
1344    /*=====================================================================*/
1345 void
_SetCurrentTool(const OPENCITY_TOOL_CODE & tool)1346 City::_SetCurrentTool( const OPENCITY_TOOL_CODE& tool )
1347 {
1348 	_apbtnCurrentTool[ _eCurrentTool ]->Unset( OC_GUIMAIN_VISIBLE );
1349 	_eCurrentTool = tool;
1350 	_apbtnCurrentTool[ _eCurrentTool ]->Set( OC_GUIMAIN_VISIBLE );
1351 }
1352 
1353 
1354    /*=====================================================================*/
1355 void
_DoTool(const SDL_MouseButtonEvent & sdlMBEvent)1356 City::_DoTool(
1357 	const SDL_MouseButtonEvent & sdlMBEvent )
1358 {
1359 	if ( _eCurrentTool == OC_TOOL_NONE )
1360 		return;
1361 
1362 	static uint cost;
1363 	static OPENCITY_ERR_CODE enumErrCode;
1364 	static int w1, h1, w2, h2;
1365 
1366 	Structure* pstruct = NULL;		// for MAS
1367 
1368 	cost = 0;
1369 	w1 = _uiMapW1;
1370 	h1 = _uiMapL1;
1371 	w2 = _uiMapW2;
1372 	h2 = _uiMapL2;
1373 	OPENCITY_SWAP( w1, w2, int );
1374 	OPENCITY_SWAP( h1, h2, int );
1375 
1376 
1377 // we return if we don't have enough funds
1378 	if (_liCityFund < 0)
1379 		return;
1380 
1381 
1382 // block all the sim threads while modifying the game datas
1383 	SDL_LockMutex( gVars.gpmutexSim );
1384 
1385 	switch (_eCurrentTool) {
1386 	case OC_TOOL_ZONE_RES:
1387 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1388 			BuildStructure(
1389 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1390 				OC_STRUCTURE_RES, cost )) == OC_ERR_FREE) {
1391 			gVars.gpAudioMgr->PlaySound( OC_SOUND_RCI );
1392 		}
1393 		break;
1394 
1395 	case OC_TOOL_ZONE_COM:
1396 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1397 			BuildStructure(
1398 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1399 				OC_STRUCTURE_COM, cost )) == OC_ERR_FREE) {
1400 			gVars.gpAudioMgr->PlaySound( OC_SOUND_RCI );
1401 		}
1402 		break;
1403 
1404 	case OC_TOOL_ZONE_IND:
1405 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1406 			BuildStructure(
1407 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1408 				OC_STRUCTURE_IND, cost )) == OC_ERR_FREE) {
1409 			gVars.gpAudioMgr->PlaySound( OC_SOUND_RCI );
1410 		}
1411 		break;
1412 
1413 	case OC_TOOL_ROAD:
1414 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1415 			BuildStructure(
1416 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1417 				OC_STRUCTURE_ROAD, cost )) == OC_ERR_FREE) {
1418 			gVars.gpAudioMgr->PlaySound( OC_SOUND_ROAD );
1419 		}
1420 		break;
1421 
1422 	case OC_TOOL_ELINE:
1423 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1424 			BuildStructure(
1425 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1426 				OC_STRUCTURE_ELINE, cost )) == OC_ERR_FREE) {
1427 			gVars.gpAudioMgr->PlaySound( OC_SOUND_ELINE );
1428 		}
1429 		break;
1430 
1431 	case OC_TOOL_EPLANT_COAL:
1432 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1433 			BuildStructure(
1434 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1435 				OC_STRUCTURE_EPLANT_COAL, cost )) == OC_ERR_FREE) {
1436 			_pMSim->AddStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, Simulator::OC_ELECTRIC );
1437 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1438 		}
1439 		break;
1440 
1441 	case OC_TOOL_EPLANT_NUCLEAR:
1442 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1443 			BuildStructure(
1444 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1445 				OC_STRUCTURE_EPLANT_NUCLEAR, cost )) == OC_ERR_FREE) {
1446 			_pMSim->AddStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, Simulator::OC_ELECTRIC );
1447 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1448 		}
1449 		break;
1450 
1451 	case OC_TOOL_PARK:
1452 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1453 			BuildStructure(
1454 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1455 				OC_STRUCTURE_PARK, cost )) == OC_ERR_FREE) {
1456 			gVars.gpAudioMgr->PlaySound( OC_SOUND_PARK );
1457 		}
1458 		break;
1459 
1460 	case OC_TOOL_FLORA:
1461 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1462 			BuildStructure(
1463 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1464 				OC_STRUCTURE_FLORA, cost )) == OC_ERR_FREE) {
1465 			gVars.gpAudioMgr->PlaySound( OC_SOUND_PARK );
1466 		}
1467 		break;
1468 
1469 	case OC_TOOL_FIRE:
1470 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1471 			BuildStructure(
1472 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1473 				OC_STRUCTURE_FIREDEPT, cost )) == OC_ERR_FREE) {
1474 // not used			_pMSim->AddStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, MainSim::OC_MICROSIM_ELE );
1475 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1476 		}
1477 		break;
1478 
1479 	case OC_TOOL_POLICE:
1480 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1481 			BuildStructure(
1482 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1483 				OC_STRUCTURE_POLICEDEPT, cost )) == OC_ERR_FREE) {
1484 // not used			_pMSim->AddStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, MainSim::OC_MICROSIM_ELE );
1485 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1486 		}
1487 		break;
1488 
1489 	case OC_TOOL_HOSPITAL:
1490 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1491 			BuildStructure(
1492 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1493 				OC_STRUCTURE_HOSPITALDEPT, cost )) == OC_ERR_FREE) {
1494 // not used			_pMSim->AddStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, MainSim::OC_MICROSIM_ELE );
1495 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1496 		}
1497 		break;
1498 
1499 	case OC_TOOL_EDUCATION:
1500 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1501 			BuildStructure(
1502 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1503 				OC_STRUCTURE_EDUCATIONDEPT, cost )) == OC_ERR_FREE) {
1504 // not used			_pMSim->AddStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, MainSim::OC_MICROSIM_ELE );
1505 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1506 		}
1507 		break;
1508 
1509 	case OC_TOOL_TEST_BUILDING:
1510 		if ((enumErrCode = _apLayer[ _eCurrentLayer ]->
1511 			BuildStructure(
1512 				_uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2,
1513 				OC_STRUCTURE_TEST, cost )) == OC_ERR_FREE) {
1514 			gVars.gpAudioMgr->PlaySound( OC_SOUND_EPLANT );
1515 		}
1516 		break;
1517 
1518 	case OC_TOOL_AGENT_POLICE:
1519 		assert( gVars.gpKernel != NULL );
1520 		assert( gVars.gpEnvironment != NULL );
1521 		pstruct = _apLayer[ OC_LAYER_BUILDING ]->GetStructure( _uiMapW1, _uiMapL1 );
1522 		if ((pstruct != NULL) && (pstruct->GetCode() == OC_STRUCTURE_ROAD))
1523 		new AgentPolice(*gVars.gpKernel, *gVars.gpEnvironment, _uiMapW1, _uiMapL1);
1524 		break;
1525 
1526 	case OC_TOOL_AGENT_DEMONSTRATOR:
1527 		assert( gVars.gpKernel != NULL );
1528 		assert( gVars.gpEnvironment != NULL );
1529 		pstruct = _apLayer[ OC_LAYER_BUILDING ]->GetStructure( _uiMapW1, _uiMapL1 );
1530 		if ((pstruct != NULL) && (pstruct->GetCode() == OC_STRUCTURE_ROAD))
1531 		new AgentDemonstrator(*gVars.gpKernel, *gVars.gpEnvironment, _uiMapW1, _uiMapL1);
1532 		break;
1533 
1534 	case OC_TOOL_AGENT_ROBBER:
1535 		assert( gVars.gpKernel != NULL );
1536 		assert( gVars.gpEnvironment != NULL );
1537 		pstruct = _apLayer[ OC_LAYER_BUILDING ]->GetStructure( _uiMapW1, _uiMapL1 );
1538 		if ((pstruct != NULL) && (pstruct->GetCode() == OC_STRUCTURE_ROAD))
1539 		new AgentRobber(*gVars.gpKernel, *gVars.gpEnvironment, _uiMapW1, _uiMapL1);
1540 		break;
1541 
1542 //FIXME: cost
1543 	case OC_TOOL_HEIGHT_UP:
1544 		enumErrCode = gVars.gpMapMgr->ChangeHeight( _uiMapW1, _uiMapL1, OC_MAP_UP );
1545 		if ( enumErrCode == OC_ERR_FREE ) {
1546 			gVars.gpRenderer->bHeightChange = true;
1547 			gVars.gpAudioMgr->PlaySound( OC_SOUND_TERRAIN );
1548 			cost = 5;		// Quick hack
1549 		}
1550 		break;
1551 
1552 	case OC_TOOL_HEIGHT_DOWN:
1553 		enumErrCode = gVars.gpMapMgr->ChangeHeight( _uiMapW1, _uiMapL1, OC_MAP_DOWN );
1554 		if ( enumErrCode == OC_ERR_FREE ) {
1555 			gVars.gpRenderer->bHeightChange = true;
1556 			gVars.gpAudioMgr->PlaySound( OC_SOUND_TERRAIN );
1557 			cost = 5;		// Quick hack
1558 		}
1559 		break;
1560 
1561 	case OC_TOOL_QUERY:
1562 	// Get the new query container
1563 		_pctrQ = _apLayer[ _eCurrentLayer ]->QueryStructure( _uiMapW1, _uiMapL1 );
1564 
1565 	// Reset the old container
1566 		_pctr->ResetAttribute( OC_GUIMAIN_CLICKED | OC_GUIMAIN_MOUSEOVER );
1567 		_pctr->Unset( OC_GUIMAIN_VISIBLE );
1568 
1569 	// Show the informations queried
1570 		_pctr = _pctrQ;
1571 		_pctr->SetLocation( sdlMBEvent.x - 70, _iWinHeight - sdlMBEvent.y - 70 );
1572 		_pctr->Set( OC_GUIMAIN_VISIBLE );
1573 		enumErrCode = OC_ERR_SOMETHING;		// avoid to calculate the cost
1574 		break;
1575 
1576 	case OC_TOOL_DESTROY:
1577 	// If it is a part of a bigger structure (an EPLANT for example),
1578 	// the whole structure will be then destroyed
1579 	// The following part tell the simulators to remove the collected data concerning
1580 	// the structures which are going to be destroyed
1581 		_pMSim->RemoveStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2 );
1582 		enumErrCode = _apLayer[ _eCurrentLayer ]->
1583 			DestroyStructure( _uiMapW1, _uiMapL1, _uiMapW2, _uiMapL2, cost );
1584 		if (enumErrCode == OC_ERR_FREE) {
1585 			gVars.gpAudioMgr->PlaySound( OC_SOUND_DESTROY );
1586 		}
1587 		break;
1588 
1589 	default:
1590 		enumErrCode = OC_ERR_SOMETHING;// which tool is this ?
1591 	} // switch
1592 
1593 // now unlock the mutex and let the sims run
1594 	SDL_UnlockMutex( gVars.gpmutexSim );
1595 
1596 	if (enumErrCode == OC_ERR_FREE) {
1597 		_liCityFund -= cost;
1598 	}
1599 }
1600 
1601 
1602    /*=====================================================================*/
1603 bool
_HandleKeyPressed()1604 City::_HandleKeyPressed()
1605 {
1606 	int actionFactor = 1;
1607 	int key;
1608 	bool boolKeyDown = false;		// There is no key pressed
1609 
1610 // Key multiplier
1611 	if (_abKeyPressed[KEY_ALT] == true)
1612 		actionFactor = OC_ACTION_FACTOR;
1613 	else
1614 		actionFactor = 1;
1615 
1616 // Look for pressed keys
1617 	for (key = KEY_UP; key < KEY_NUMBER; key++) {
1618 		if (_abKeyPressed[key] == true) {
1619 			switch (key) {
1620 			case KEY_UP:
1621 				gVars.gpRenderer->MoveDown(actionFactor);
1622 				break;
1623 			case KEY_DOWN:
1624 				gVars.gpRenderer->MoveUp(actionFactor);
1625 				break;
1626 			case KEY_RIGHT:
1627 				gVars.gpRenderer->MoveLeft(actionFactor);
1628 				break;
1629 			case KEY_LEFT:
1630 				gVars.gpRenderer->MoveRight(actionFactor);
1631 				break;
1632 
1633 			case KEY_PAGEUP:
1634 				gVars.gpRenderer->RotateLeft(actionFactor);
1635 				break;
1636 			case KEY_PAGEDOWN:
1637 				gVars.gpRenderer->RotateRight(actionFactor);
1638 				break;
1639 
1640 			case KEY_INSERT: // zoom in
1641 				gVars.gpRenderer->ZoomIn();
1642 				break;
1643 			case KEY_DELETE: // zoom out
1644 				gVars.gpRenderer->ZoomOut();
1645 				break;
1646 			} // switch
1647 
1648 		// There's at least one key pressed
1649 			boolKeyDown = true;
1650 		} // if
1651 	} // for
1652 
1653 // Tell the caller that there's whether at least a key pressed or not
1654 	return boolKeyDown;
1655 }
1656 
1657 
1658    /*=====================================================================*/
1659 void
_RecordRessource()1660 City::_RecordRessource()
1661 {
1662 // Accumulate the income each month
1663 	uint r, c, i;
1664 	uint w = 0, e = 0, g = 0;
1665 	r = _pMSim->GetValue(Simulator::OC_RESIDENTIAL);
1666 	c = _pMSim->GetValue(Simulator::OC_COMMERCIAL);
1667 	i = _pMSim->GetValue(Simulator::OC_INDUSTRIAL);
1668 
1669 // Create a new record
1670 	Ressource res;
1671 	res.fund = _liCityFund;
1672 	res.population = _uiPopulation;
1673 	res.r = r;
1674 	res.c = c;
1675 	res.i = i;
1676 	res.w = w;
1677 	res.e = e;
1678 	res.g = g;
1679 
1680 // Pop the oldest record if available (safe)
1681 	if (!_dqRessource.empty())
1682 		_dqRessource.pop_front();
1683 	_dqRessource.push_back(res);
1684 }
1685 
1686 
1687    /*=====================================================================*/
1688 void
_DoBill(const OPENCITY_PROPERTY_CODE & enumProperty)1689 City::_DoBill(
1690 	const OPENCITY_PROPERTY_CODE & enumProperty )
1691 {
1692 	uint maintenance;
1693 	uint index, surface;
1694 	Structure* pStruct;
1695 	uint r, c, i;
1696 
1697 	surface = _uiWidth * _uiLength;
1698 	maintenance = 0;
1699 	for (index = 0; index < surface; index++) {
1700 		pStruct = _apLayer[ OC_LAYER_BUILDING ]->GetLinearStructure( index );
1701 		if (pStruct != NULL)
1702 			maintenance +=
1703 				gVars.gpPropertyMgr->Get(OC_MAINTENANCE_COST, pStruct->GetCode());
1704 	}
1705 
1706 	_liCityFund -= maintenance;
1707 
1708 // Accumulate the income each month
1709 	r = _pMSim->GetValue(Simulator::OC_RESIDENTIAL);
1710 	c = _pMSim->GetValue(Simulator::OC_COMMERCIAL);
1711 	i = _pMSim->GetValue(Simulator::OC_INDUSTRIAL);
1712 
1713 	_uiIncome += (r*OC_R_INCOME_TAX + c*OC_C_INCOME_TAX + i*OC_I_INCOME_TAX) / 100;
1714 
1715 // Add the income only if we reach the end of the year
1716 	if (enumProperty == OC_INCOME ) {
1717 	// Here is the gouvernment's help for this year :D
1718 		_uiIncome += _uiIncome * OC_INCOME_HELP/100;
1719 		_liCityFund += _uiIncome;
1720 		OPENCITY_INFO(
1721 			"Happy new year ! " <<
1722 			"Income: " << _uiIncome <<
1723 			" d/m/y: " << _uiDay << "/" << _uiMonth << "/" << _uiYear <<
1724 			" R/C/I: " << r << "/" << c << "/" << i
1725 		);
1726 
1727 		_uiIncome = 0;
1728 	}
1729 }
1730 
1731 
1732    /*=====================================================================*/
1733 void
_HandleMenuClick()1734 City::_HandleMenuClick()
1735 {
1736 	assert( _pctrMenu != NULL );
1737 
1738 	uint uiObject = _pctrMenu->GetClick();
1739 
1740 	switch (uiObject) {
1741 		case 1:
1742 			ocRestart();
1743 			break;
1744 
1745 		case 2:		// Load
1746 			_Load( ocSaveDirPrefix( "opencity.save" ) );
1747 			break;
1748 		case 3:		// Save
1749 			_Save( ocSaveDirPrefix( "opencity.save" ) );
1750 			break;
1751 
1752 		case 4:		// Quit button
1753 			ocQuit();
1754 			break;
1755 
1756 		default:
1757 			OPENCITY_DEBUG( "Menu design error");
1758 			assert(0);
1759 	}
1760 
1761 	_UnloadMenu();
1762 }
1763 
1764 
1765    /*=====================================================================*/
1766 void
_HandleStatusClick()1767 City::_HandleStatusClick()
1768 {
1769 	uint uiObject = _pctrStatus->GetClick();
1770 
1771 // WARNING: the GUI button displays the current speed
1772 	switch (uiObject) {
1773 		case 1:		// Pause button
1774 			OPENCITY_DEBUG( "Normal speed mode" );
1775 			_pbtnPause->Unset( OC_GUIMAIN_VISIBLE );
1776 			_pbtnPlay->Set( OC_GUIMAIN_VISIBLE );
1777 			_eSpeed = OC_SPEED_NORMAL;
1778 			_pMSim->Run();
1779 			break;
1780 		case 2:		// Play button
1781 			OPENCITY_DEBUG( "Pause mode" );
1782 			_pbtnPlay->Unset( OC_GUIMAIN_VISIBLE );
1783 			_pbtnPause->Set( OC_GUIMAIN_VISIBLE );
1784 			_eSpeed = OC_SPEED_PAUSE;
1785 			_pMSim->Stop();
1786 			break;
1787 
1788 		default:
1789 			OPENCITY_DEBUG( "WARNING: What's this control -> " << uiObject);
1790 			//assert(0);
1791 			break;
1792 	}
1793 
1794 	_pctrStatus->ResetAttribute( OC_GUIMAIN_CLICKED | OC_GUIMAIN_MOUSEOVER );
1795 }
1796 
1797 
1798    /*=====================================================================*/
1799 void
_HandleGUIClick()1800 City::_HandleGUIClick()
1801 {
1802 	uint uiObject;
1803 	GUIContainer* pOldContainer;
1804 	int iX, iY;
1805 
1806 	pOldContainer = _pctr;
1807 	uiObject = _pctr->GetClick();
1808 
1809 // is this the main container ?
1810 	if (_pctr == _pctrMain)
1811 	switch (uiObject) {
1812 		case 1: // switch to Z toolcircle
1813 			_pctr = _pctrZ;
1814 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1815 			break;
1816 		case 2: // load/save toolcircle
1817 			_pctr = _pctrS;
1818 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1819 			break;
1820 		case 3:  // L button, open the L toolcircle
1821 			_pctr = _pctrL;
1822 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1823 			break;
1824 		case 4:  // P button, set tool for "building road"
1825 			_SetCurrentTool( OC_TOOL_ROAD );
1826 			break;
1827 		case 5: // T button, open the "Terrain" toolcircle
1828 			_pctr = _pctrT;
1829 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1830 			break;
1831 		case 6: // G button, open the government toolcircle
1832 			_pctr = _pctrG;
1833 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1834 			break;
1835 
1836 		default: // never reached
1837 			OPENCITY_DEBUG( "WARNING: What's going wrong ?" );
1838 			assert(0);
1839 			break;
1840 	}
1841 
1842 // the user clicked on the Zone toolcircle
1843 	else if (_pctr == _pctrZ )
1844 	switch (uiObject) {
1845 		case 1: // back button, open the main toolcircle
1846 			_pctr = _pctrMain;
1847 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1848 			break;
1849 		case 2: // R button
1850 			_SetCurrentTool( OC_TOOL_ZONE_RES );
1851 			break;
1852 		case 3:  // C button, set tool for "zone commercial"
1853 			_SetCurrentTool( OC_TOOL_ZONE_COM );
1854 			break;
1855 		case 4:  // I button, set tool for "zone industrial"
1856 			_SetCurrentTool( OC_TOOL_ZONE_IND );
1857 			break;
1858 
1859 		default:
1860 			OPENCITY_DEBUG("Design error");
1861 			assert( 0 );
1862 			break;
1863 	}
1864 
1865 // the user clicked on the eLectric toolcircle
1866 	else if (_pctr == _pctrL)
1867 	switch (uiObject) {
1868 		case 1: // back button, open the main toolcircle
1869 			_pctr = _pctrMain;
1870 		// highlight the previous button under the mouse cursor
1871 			_pctr->Set( 3, OC_GUIMAIN_MOUSEOVER );
1872 			break;
1873 		case 2:  // L button, set tool for building electric lines
1874 			_SetCurrentTool( OC_TOOL_ELINE );
1875 			break;
1876 		case 3:  // set tool for building nuclear power plant
1877 			_SetCurrentTool( OC_TOOL_EPLANT_NUCLEAR );
1878 			break;
1879 		case 4:  // set tool for building coal power plant
1880 			_SetCurrentTool( OC_TOOL_EPLANT_COAL );
1881 			break;
1882 
1883 		default:
1884 			OPENCITY_DEBUG( "WARNING: What's going wrong ?" );
1885 			assert(0);
1886 			break;
1887 	}
1888 
1889 // the user clicked on the Terrain toolcircle
1890 	else if (_pctr == _pctrT)
1891 	switch (uiObject) {
1892 		case 1: // back button, open the main toolcircle
1893 			_pctr = _pctrMain;
1894 			_pctr->Set( 5, OC_GUIMAIN_MOUSEOVER );
1895 			break;
1896 		case 2:  // height up
1897 			_SetCurrentTool( OC_TOOL_HEIGHT_UP );
1898 			break;
1899 		case 3:  // height down
1900 			_SetCurrentTool( OC_TOOL_HEIGHT_DOWN );
1901 			break;
1902 		case 4:  // destroy tool
1903 			_SetCurrentTool( OC_TOOL_DESTROY );
1904 			break;
1905 		case 5: // query tool
1906 			_SetCurrentTool( OC_TOOL_QUERY );
1907 			break;
1908 
1909 		default:
1910 			OPENCITY_DEBUG( "WARNING: What's going wrong ?" );
1911 			assert(0);
1912 			break;
1913 	}
1914 
1915 // the user clicked on the government toolcircle
1916 	else if (_pctr == _pctrG)
1917 	switch (uiObject) {
1918 		case 1: // back button, open the main toolcircle
1919 			_pctr = _pctrMain;
1920 			_pctr->Set( 6, OC_GUIMAIN_MOUSEOVER );
1921 			break;
1922 		case 2:  // nature toolcircle
1923 			_pctr = _pctrN;
1924 			_pctr->Set( 1, OC_GUIMAIN_MOUSEOVER );
1925 			break;
1926 		case 3:
1927 			_SetCurrentTool( OC_TOOL_EDUCATION );
1928 			break;
1929 		case 4:
1930 			_SetCurrentTool( OC_TOOL_HOSPITAL );
1931 			break;
1932 		case 5:
1933 			_SetCurrentTool( OC_TOOL_POLICE );
1934 			break;
1935 		case 6:
1936 			_SetCurrentTool( OC_TOOL_FIRE );
1937 			break;
1938 
1939 		default:
1940 			OPENCITY_DEBUG( "WARNING: Unknown command" );
1941 			assert(0);
1942 			break;
1943 	}
1944 
1945 // the user clicked on the "nature" toolcircle
1946 	else if (_pctr == _pctrN)
1947 	switch (uiObject) {
1948 		case 1: // back button, open the government toolcircle
1949 			_pctr = _pctrG;
1950 			_pctr->Set( 2, OC_GUIMAIN_MOUSEOVER );
1951 			break;
1952 		case 2:  // build park
1953 			_SetCurrentTool( OC_TOOL_PARK );
1954 			break;
1955 		case 3:  // build tree
1956 			_SetCurrentTool( OC_TOOL_FLORA );
1957 			break;
1958 
1959 		default:
1960 			OPENCITY_DEBUG( "WARNING: Unknown tool" );
1961 			assert(0);
1962 			break;
1963 	}
1964 
1965 // the user clicked on the load/save toolcircle
1966 	else if (_pctr == _pctrS)
1967 	switch (uiObject) {
1968 		case 1: // back button, open the main toolcircle
1969 			_pctr = _pctrMain;
1970 			_pctr->Set( 2, OC_GUIMAIN_MOUSEOVER );
1971 			break;
1972 		case 2:  // save
1973 			_Save( ocSaveDirPrefix( "opencity.save" ) );
1974 			break;
1975 		case 3:  // load
1976 			_Load( ocSaveDirPrefix( "opencity.save" ) );
1977 			break;
1978 
1979 		default:
1980 			OPENCITY_DEBUG( "WARNING: Unknown command" );
1981 			assert(0);
1982 			break;
1983 	}
1984 
1985 // the user clicked on the Path toolcircle
1986 	else if (_pctr == _pctrPath)
1987 	switch (uiObject) {
1988 		case 1: // start button
1989 			_SetCurrentTool( OC_TOOL_NONE );
1990 			boolPathGo = false;
1991 //debug cout << "changed to false" << endl;
1992 			break;
1993 		case 2: // stop button
1994 			_SetCurrentTool( OC_TOOL_NONE );
1995 			boolPathGo = true;
1996 			this->uiVehicleType = Vehicle::VEHICLE_BUS;
1997 			break;
1998 		case 3: // stop button
1999 			_SetCurrentTool( OC_TOOL_NONE );
2000 			boolPathGo = true;
2001 			this->uiVehicleType = Vehicle::VEHICLE_SPORT;
2002 //debug cout << "changed to true" << endl;
2003 			break;
2004 		case 4: // build test building
2005 			_SetCurrentTool( OC_TOOL_TEST_BUILDING );
2006 			break;
2007 		default:
2008 			break;
2009 	}
2010 
2011 // The user has clicked on the MAS toolcircle
2012 	else if (_pctr == _pctrMAS)
2013 	switch (uiObject) {
2014 		case 1: // start button
2015 			_SetCurrentTool( OC_TOOL_AGENT_POLICE );
2016 			break;
2017 		case 2: // stop button
2018 			_SetCurrentTool( OC_TOOL_AGENT_DEMONSTRATOR );
2019 			break;
2020 		case 3: // stop button
2021 			_SetCurrentTool( OC_TOOL_AGENT_ROBBER );
2022 			break;
2023 
2024 		default:
2025 			break;
2026 	}
2027 
2028 
2029 // IF the container has been changed then we reset
2030 // the MouseOver & Clicked attributes
2031 // otherwise we reset only the Clicked attribute
2032 	if (_pctr != pOldContainer) {
2033 		pOldContainer->ResetAttribute( OC_GUIMAIN_CLICKED | OC_GUIMAIN_MOUSEOVER );
2034 		pOldContainer->GetLocation( iX, iY );
2035 		_pctr->SetLocation( iX, iY );
2036 		_pctr->Set( OC_GUIMAIN_VISIBLE );
2037 	}
2038 	else {
2039 		pOldContainer->ResetAttribute( OC_GUIMAIN_CLICKED );
2040 	}
2041 	pOldContainer->Unset( OC_GUIMAIN_VISIBLE );
2042 }
2043 
2044 
2045    /*=====================================================================*/
2046 // Unused at the moment because it disturbs the GUI
2047 void
_HandleMouseXY()2048 City::_HandleMouseXY()
2049 {
2050 	#define OC_MOUSE_AUTOSCROLL 15
2051 
2052 	static int mouseX, mouseY;
2053 
2054 // return immediately if the app doesn't have mouse focus
2055 	if (!(SDL_GetAppState() & SDL_APPMOUSEFOCUS ))
2056 		return;
2057 
2058 	SDL_GetMouseState( &mouseX, &mouseY );
2059 
2060 // handle horizontal automatic map translation
2061 	if ((mouseX < OC_MOUSE_AUTOSCROLL) && !(mouseY < OC_MOUSE_AUTOSCROLL))
2062 		gVars.gpRenderer->MoveRight();
2063 	if ((mouseX >= _iWinWidth-OC_MOUSE_AUTOSCROLL) && !(mouseY < OC_MOUSE_AUTOSCROLL))
2064 		gVars.gpRenderer->MoveLeft();
2065 
2066 // handle vertical automatic map translation
2067 	if (!(mouseX < OC_MOUSE_AUTOSCROLL)
2068 	  &&!(mouseX >= _iWinWidth-OC_MOUSE_AUTOSCROLL) && (mouseY < OC_MOUSE_AUTOSCROLL))
2069 		gVars.gpRenderer->MoveDown();
2070 	if ((mouseY >= _iWinHeight-OC_MOUSE_AUTOSCROLL))
2071 		gVars.gpRenderer->MoveUp();
2072 
2073 // handle map rotation
2074 	if ((mouseX < OC_MOUSE_AUTOSCROLL) && (mouseY < OC_MOUSE_AUTOSCROLL))
2075 		gVars.gpRenderer->RotateLeft();
2076 
2077 	if ((mouseY < OC_MOUSE_AUTOSCROLL) && (mouseX >= _iWinWidth-OC_MOUSE_AUTOSCROLL))
2078 		gVars.gpRenderer->RotateRight();
2079 }
2080 
2081 
2082    /*=====================================================================*/
2083 void
_TestPathfinding()2084 City::_TestPathfinding() {
2085 	if (_pctr == _pctrPath) {
2086 		if (this->boolPathGo == false) {
2087 			this->uiPathStartW = _uiMapW2;
2088 			this->uiPathStartH = _uiMapL2;
2089 		}
2090 		else {
2091 		//TODO: put this somewhere else
2092 			vector<Destination> vdest;
2093 
2094 			this->uiPathStopW = _uiMapW2;
2095 			this->uiPathStopH = _uiMapL2;
2096 
2097 		// Buses prefer short distance
2098 			if (this->uiVehicleType == Vehicle::VEHICLE_BUS) {
2099 				gVars.gpPathFinder->findShortestPath(
2100 					uiPathStartW, uiPathStartH,
2101 					uiPathStopW, uiPathStopH,
2102 					vdest,
2103 					PathFinder::OC_DISTANCE );
2104 			}
2105 		// Sport vehicle prefer less traffic
2106 			else if (this->uiVehicleType == Vehicle::VEHICLE_SPORT) {
2107 				gVars.gpPathFinder->findShortestPath(
2108 					uiPathStartW, uiPathStartH,
2109 					uiPathStopW, uiPathStopH,
2110 					vdest,
2111 					PathFinder::OC_TRAFFIC );
2112 			}
2113 
2114 		// Now create the new vehicle if a path was found
2115 			if ( vdest.size() > 0 ) {
2116 				pvehicle = new Vehicle(
2117 					(Vehicle::VEHICLE_TYPE)this->uiVehicleType );
2118 				pvehicle->SetPath( vdest );	// path init
2119 				pvehicle->Start();		// vehicle init
2120 				if (gVars.gpMoveMgr->Add( pvehicle ) < 0) {
2121 					OPENCITY_DEBUG("MoveMgr full");
2122 					delete pvehicle;
2123 				}
2124 			}
2125 		}
2126 	}
2127 //debug: pathfinding
2128 /*
2129 cout << "StW: " << uiPathStartW << " / " << " StH: " << uiPathStartH
2130      << " SpW: " << uiPathStopW << " / " << "SpH: " << uiPathStopH << endl;
2131 */
2132 }
2133 
2134 
2135    /*=====================================================================*/
2136 void
_BuildPreview()2137 City::_BuildPreview()
2138 {
2139 	static OPENCITY_STRUCTURE_CODE scode = OC_STRUCTURE_UNDEFINED;
2140 	static OPENCITY_GRAPHIC_CODE gcode = OC_EMPTY;
2141 	static OPENCITY_TOOL_CODE tcode = OC_TOOL_NONE;
2142 	static OPENCITY_ERR_CODE ecode = OC_ERR_FREE;
2143 
2144 
2145 // Get the corresponding structure code of the tool
2146 	if (tcode != _eCurrentTool) {
2147 		tcode = _eCurrentTool;
2148 		switch (tcode) {
2149 		/* not implemented yet
2150 			case OC_TOOL_ZONE_RES:
2151 				scode = OC_STRUCTURE_RES;
2152 				break;
2153 			case OC_TOOL_ZONE_COM:
2154 				scode = OC_STRUCTURE_COM;
2155 				break;
2156 			case OC_TOOL_ZONE_IND:
2157 				scode = OC_STRUCTURE_IND;
2158 				break;
2159 			case OC_TOOL_ROAD:
2160 				scode = OC_STRUCTURE_ROAD;
2161 				break;
2162 			case OC_TOOL_ELINE:
2163 				scode = OC_STRUCTURE_ELINE;
2164 				break;
2165 		*/
2166 
2167 			case OC_TOOL_EPLANT_COAL:
2168 				scode = OC_STRUCTURE_EPLANT_COAL;
2169 				break;
2170 			case OC_TOOL_EPLANT_NUCLEAR:
2171 				scode = OC_STRUCTURE_EPLANT_NUCLEAR;
2172 				break;
2173 			case OC_TOOL_PARK:
2174 				scode = OC_STRUCTURE_PARK;
2175 				break;
2176 			case OC_TOOL_FLORA:
2177 				scode = OC_STRUCTURE_FLORA;
2178 				break;
2179 			case OC_TOOL_FIRE:
2180 				scode = OC_STRUCTURE_FIREDEPT;
2181 				break;
2182 			case OC_TOOL_POLICE:
2183 				scode = OC_STRUCTURE_POLICEDEPT;
2184 				break;
2185 			case OC_TOOL_HOSPITAL:
2186 				scode = OC_STRUCTURE_HOSPITALDEPT;
2187 				break;
2188 			case OC_TOOL_EDUCATION:
2189 				scode = OC_STRUCTURE_EDUCATIONDEPT;
2190 				break;
2191 
2192 			case OC_TOOL_TEST_BUILDING:
2193 				scode = OC_STRUCTURE_TEST;
2194 				break;
2195 
2196 			default:
2197 				scode = OC_STRUCTURE_UNDEFINED;
2198 				break;
2199 		} // switch
2200 	} // if
2201 
2202 // Get the corresponding graphic code
2203 	if ((scode != OC_STRUCTURE_UNDEFINED)
2204 	 && (_bLMBPressed == true)) {
2205 		ecode = _apLayer[ _eCurrentLayer ]->
2206 			BuildPreview( _uiMapW1, _uiMapL1, scode, gcode );
2207 
2208 		if (ecode == OC_ERR_FREE) {
2209 			gVars.gpRenderer->DisplayBuildPreview(
2210 				_uiMapW1, _uiMapL1, OC_GREEN_COLOR, gcode );
2211 		}
2212 		else {
2213 			gVars.gpRenderer->DisplayBuildPreview(
2214 				_uiMapW1, _uiMapL1, OC_RED_COLOR, gcode );
2215 		}
2216 	}
2217 }
2218 
2219 
2220    /*=====================================================================*/
2221 bool
_Save(const string & strFilename)2222 City::_Save( const string& strFilename )
2223 {
2224 	fstream fs;
2225 
2226 	fs.open( strFilename.c_str(), ios_base::out | ios_base::binary | ios_base::trunc );
2227 	if (!fs.good()) {
2228 		OPENCITY_DEBUG( "File opening error: " << strFilename );
2229 		return false;
2230 	}
2231 
2232 // Save the signature and version
2233 	fs << "OpenCity_" << ocStrVersion() << std::endl;
2234 	fs << ocLongVersion() << std::ends;
2235 
2236 // Lock the simulator
2237 	SDL_LockMutex( gVars.gpmutexSim );
2238 
2239 // Save city data
2240 	this->SaveTo( fs );
2241 
2242 // Save map data
2243 	gVars.gpMapMgr->SaveTo( fs );
2244 
2245 // Save layers's data
2246 	_apLayer[ OC_LAYER_BUILDING ]->SaveTo( fs );
2247 
2248 // Save simulators data
2249 	_pMSim->SaveTo( fs );
2250 
2251 // Unlock the simulator
2252 	SDL_UnlockMutex( gVars.gpmutexSim );
2253 
2254 	fs.close();
2255 	return true;
2256 }
2257 
2258 
2259    /*=====================================================================*/
2260 bool
_Load(const string & strFilename)2261 City::_Load( const string& strFilename )
2262 {
2263 	fstream fs;
2264 	uint w, l;
2265 
2266 	fs.open( strFilename.c_str(), ios_base::in | ios_base::binary );
2267 	if (!fs.good()) {
2268 		OPENCITY_DEBUG( "File opening error in: " << strFilename );
2269 		return false;
2270 	}
2271 
2272 // Load the signature and version
2273 	string strSignature;
2274 	long currentVersion = ocLongVersion();
2275 	long lVersion;
2276 
2277 	getline( fs, strSignature );
2278 	fs >> lVersion; fs.ignore();
2279 
2280 // Version checking
2281 	if (lVersion > currentVersion) {
2282 		OPENCITY_INFO( "Failed to load a more recent save file: " << strFilename );
2283 		OPENCITY_INFO( "Current OpenCity version is: " << currentVersion );
2284 		OPENCITY_INFO( "The save file version is : " << lVersion );
2285 		return false;
2286 	}
2287 
2288 // Lock the simulator
2289 	SDL_LockMutex( gVars.gpmutexSim );
2290 
2291 // Remove all moving objects
2292 	gVars.gpMoveMgr->Remove();
2293 
2294 // Load city data
2295 	OPENCITY_INFO( "Loading save file from " << strSignature );
2296 	this->LoadFrom( fs );
2297 
2298 // Load map data
2299 	gVars.gpMapMgr->LoadFrom( fs );
2300 	gVars.gpRenderer->bHeightChange = true;
2301 	gVars.gpRenderer->bMinimapChange = true;
2302 
2303 // Load layers' data
2304 	_apLayer[ OC_LAYER_BUILDING ]->LoadFrom( fs );
2305 
2306 // Load simulators' data
2307 	_pMSim->LoadFrom( fs );
2308 
2309 // Manually add the structures to the simulators
2310 	for ( w = 0; w < _uiWidth; w++ ) {
2311 		for ( l = 0; l < _uiLength; l++ ) {
2312 			_pMSim->AddStructure( w, l, w, l );
2313 		}
2314 	}
2315 
2316 // Refresh/recalculate the simulators' value
2317 	_pMSim->RefreshSimValue();
2318 
2319 // Unlock the simulator
2320 	SDL_UnlockMutex( gVars.gpmutexSim );
2321 
2322 	fs.close();
2323 	return true;
2324 }
2325 
2326 
2327 
2328 
2329 
2330 
2331 
2332 
2333 
2334 
2335 
2336 
2337 
2338 
2339 
2340 
2341 
2342 
2343 
2344 
2345 
2346 
2347 
2348 
2349 
2350 
2351 
2352 
2353 
2354 
2355 
2356 
2357 
2358 
2359 
2360 
2361