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