1 /*
2 * Copyright 2010-2014 OpenXcom Developers.
3 *
4 * This file is part of OpenXcom.
5 *
6 * OpenXcom is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenXcom is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "GraphsState.h"
20 #include <sstream>
21 #include "../Engine/Game.h"
22 #include "../Resource/ResourcePack.h"
23 #include "../Engine/Palette.h"
24 #include "../Engine/Surface.h"
25 #include "../Engine/Screen.h"
26 #include "../Engine/InteractiveSurface.h"
27 #include "../Savegame/Country.h"
28 #include "../Savegame/Region.h"
29 #include "../Ruleset/RuleCountry.h"
30 #include "../Ruleset/RuleRegion.h"
31 #include "../Interface/Text.h"
32 #include "../Engine/Language.h"
33 #include "../Interface/TextButton.h"
34 #include "../Interface/ToggleTextButton.h"
35 #include "../Savegame/GameTime.h"
36 #include "../Savegame/SavedGame.h"
37 #include "../Interface/TextList.h"
38 #include "../Engine/Action.h"
39 #include "../Engine/Options.h"
40
41 namespace OpenXcom
42 {
43
44 struct GraphButInfo
45 {
46 LocalizedText _name;
47 int _color;
48 bool _pushed;
GraphButInfoOpenXcom::GraphButInfo49 GraphButInfo(const LocalizedText& name, Uint8 color): _name(name), _color(color), _pushed(false) {}
50 };
51 /**
52 * Initializes all the elements in the Graphs screen.
53 * @param game Pointer to the core game.
54 */
GraphsState(Game * game)55 GraphsState::GraphsState(Game *game) : State(game), _butRegionsOffset(0), _butCountriesOffset(0)
56 {
57 // Create objects
58 _bg = new InteractiveSurface(320, 200, 0, 0);
59 _bg->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELUP);
60 _bg->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELDOWN);
61 _btnUfoRegion = new InteractiveSurface(32, 24, 96, 0);
62 _btnUfoCountry = new InteractiveSurface(32, 24, 128, 0);
63 _btnXcomRegion = new InteractiveSurface(32, 24, 160, 0);
64 _btnXcomCountry = new InteractiveSurface(32, 24, 192, 0);
65 _btnIncome = new InteractiveSurface(32, 24, 224, 0);
66 _btnFinance = new InteractiveSurface(32, 24, 256, 0);
67 _btnGeoscape = new InteractiveSurface(32, 24, 288, 0);
68 _txtTitle = new Text(220, 16, 100, 28);
69 _txtFactor = new Text(38, 11, 96, 28);
70 _txtMonths = new TextList(205, 8, 115, 183);
71 _txtYears = new TextList(200, 8, 121, 191);
72
73 // Set palette
74 setPalette("PAL_GRAPHS");
75
76 //add all our elements
77 add(_bg);
78 add(_btnUfoRegion);
79 add(_btnUfoCountry);
80 add(_btnXcomRegion);
81 add(_btnXcomCountry);
82 add(_btnIncome);
83 add(_btnFinance);
84 add(_btnGeoscape);
85 add(_txtMonths);
86 add(_txtYears);
87 add(_txtTitle);
88 add(_txtFactor);
89 for (int scaleText = 0; scaleText != 10; ++scaleText)
90 {
91 _txtScale.push_back(new Text(42, 16, 80, 171 - (scaleText*14)));
92 add(_txtScale.at(scaleText));
93 }
94
95 //create buttons (sooooo many buttons)
96 size_t offset = 0;
97 for (std::vector<Region *>::iterator iter = _game->getSavedGame()->getRegions()->begin(); iter != _game->getSavedGame()->getRegions()->end(); ++iter)
98 {
99 // always save in toggles all the regions
100 _regionToggles.push_back(new GraphButInfo(tr((*iter)->getRules()->getType()) , -42 + (4*offset)));
101 // initially add the GRAPH_MAX_BUTTONS having the first regions information
102 if(offset < GRAPH_MAX_BUTTONS)
103 {
104 _btnRegions.push_back(new ToggleTextButton(80, 11, 0, offset*11));
105 _btnRegions.at(offset)->setColor(Palette::blockOffset(9)+7);
106 _btnRegions.at(offset)->setInvertColor(-42 + (4*offset));
107 _btnRegions.at(offset)->setText(tr((*iter)->getRules()->getType()));
108 _btnRegions.at(offset)->onMousePress((ActionHandler)&GraphsState::btnRegionListClick);
109 _btnRegions.at(offset)->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELUP);
110 _btnRegions.at(offset)->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELDOWN);
111 add(_btnRegions.at(offset));
112 }
113 _alienRegionLines.push_back(new Surface(320,200,0,0));
114 add(_alienRegionLines.at(offset));
115 _xcomRegionLines.push_back(new Surface(320,200,0,0));
116 add(_xcomRegionLines.at(offset));
117
118 ++offset;
119 }
120
121 if(_regionToggles.size() < GRAPH_MAX_BUTTONS)
122 _btnRegionTotal = new ToggleTextButton(80, 11, 0, _regionToggles.size()*11);
123 else
124 _btnRegionTotal = new ToggleTextButton(80, 11, 0, GRAPH_MAX_BUTTONS*11);
125 _regionToggles.push_back(new GraphButInfo(tr("STR_TOTAL_UC"), 18));
126 _btnRegionTotal->onMousePress((ActionHandler)&GraphsState::btnRegionListClick);
127 _btnRegionTotal->setColor(Palette::blockOffset(9)+7);
128 _btnRegionTotal->setInvertColor(18);
129 _btnRegionTotal->setText(tr("STR_TOTAL_UC"));
130 _alienRegionLines.push_back(new Surface(320,200,0,0));
131 add(_alienRegionLines.at(offset));
132 _xcomRegionLines.push_back(new Surface(320,200,0,0));
133 add(_xcomRegionLines.at(offset));
134 add(_btnRegionTotal);
135
136 offset = 0;
137 for (std::vector<Country *>::iterator iter = _game->getSavedGame()->getCountries()->begin(); iter != _game->getSavedGame()->getCountries()->end(); ++iter)
138 {
139 // always save in toggles all the countries
140 _countryToggles.push_back(new GraphButInfo(tr((*iter)->getRules()->getType()) , -42 + (4*offset)));
141 // initially add the GRAPH_MAX_BUTTONS having the first countries information
142 if(offset < GRAPH_MAX_BUTTONS)
143 {
144 _btnCountries.push_back(new ToggleTextButton(80, 11, 0, offset*11));
145 _btnCountries.at(offset)->setColor(Palette::blockOffset(9)+7);
146 _btnCountries.at(offset)->setInvertColor(-42 + (4*offset));
147 _btnCountries.at(offset)->setText(tr((*iter)->getRules()->getType()));
148 _btnCountries.at(offset)->onMousePress((ActionHandler)&GraphsState::btnCountryListClick);
149 _btnCountries.at(offset)->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELUP);
150 _btnCountries.at(offset)->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELDOWN);
151 add(_btnCountries.at(offset));
152 }
153 _alienCountryLines.push_back(new Surface(320,200,0,0));
154 add(_alienCountryLines.at(offset));
155 _xcomCountryLines.push_back(new Surface(320,200,0,0));
156 add(_xcomCountryLines.at(offset));
157 _incomeLines.push_back(new Surface(320,200,0,0));
158 add(_incomeLines.at(offset));
159
160 ++offset;
161 }
162
163 if(_countryToggles.size() < GRAPH_MAX_BUTTONS)
164 _btnCountryTotal = new ToggleTextButton(80, 11, 0, _countryToggles.size()*11);
165 else
166 _btnCountryTotal = new ToggleTextButton(80, 11, 0, GRAPH_MAX_BUTTONS*11);
167 _countryToggles.push_back(new GraphButInfo(tr("STR_TOTAL_UC"), 22));
168 _btnCountryTotal->onMousePress((ActionHandler)&GraphsState::btnCountryListClick);
169 _btnCountryTotal->setColor(Palette::blockOffset(9)+7);
170 _btnCountryTotal->setInvertColor(22);
171 _btnCountryTotal->setText(tr("STR_TOTAL_UC"));
172 _alienCountryLines.push_back(new Surface(320,200,0,0));
173 add(_alienCountryLines.at(offset));
174 _xcomCountryLines.push_back(new Surface(320,200,0,0));
175 add(_xcomCountryLines.at(offset));
176 _incomeLines.push_back(new Surface(320,200,0,0));
177 add(_incomeLines.at(offset));
178 add(_btnCountryTotal);
179
180
181 for (int iter = 0; iter != 5; ++iter)
182 {
183 offset = iter;
184 _btnFinances.push_back(new ToggleTextButton(80, 11, 0, offset*11));
185 _financeToggles.push_back(false);
186 _btnFinances.at(offset)->setColor(Palette::blockOffset(9)+7);
187 _btnFinances.at(offset)->setInvertColor(-42 + (4*offset));
188 _btnFinances.at(offset)->onMousePress((ActionHandler)&GraphsState::btnFinanceListClick);
189 add(_btnFinances.at(offset));
190 _financeLines.push_back(new Surface(320,200,0,0));
191 add(_financeLines.at(offset));
192 }
193
194 _btnFinances.at(0)->setText(tr("STR_INCOME"));
195 _btnFinances.at(1)->setText(tr("STR_EXPENDITURE"));
196 _btnFinances.at(2)->setText(tr("STR_MAINTENANCE"));
197 _btnFinances.at(3)->setText(tr("STR_BALANCE"));
198 _btnFinances.at(4)->setText(tr("STR_SCORE"));
199
200 // load back the button states
201 std::string graphRegionToggles = _game->getSavedGame()->getGraphRegionToggles();
202 std::string graphCountryToggles = _game->getSavedGame()->getGraphCountryToggles();
203 std::string graphFinanceToggles = _game->getSavedGame()->getGraphFinanceToggles();
204 while (graphRegionToggles.size() < _regionToggles.size()) graphRegionToggles.push_back('0');
205 while (graphCountryToggles.size() < _countryToggles.size()) graphCountryToggles.push_back('0');
206 while (graphFinanceToggles.size() < _financeToggles.size()) graphFinanceToggles.push_back('0');
207 for (size_t i = 0; i < _regionToggles.size(); ++i)
208 {
209 _regionToggles[i]->_pushed = ('0'==graphRegionToggles[i]) ? false : true;
210 if (_regionToggles.size()-1 == i)
211 _btnRegionTotal->setPressed(_regionToggles[i]->_pushed);
212 else if(i < GRAPH_MAX_BUTTONS)
213 _btnRegions.at(i)->setPressed(_regionToggles[i]->_pushed);
214 }
215 for (size_t i = 0; i < _countryToggles.size(); ++i)
216 {
217 _countryToggles[i]->_pushed = ('0'==graphCountryToggles[i]) ? false : true;
218 if (_countryToggles.size()-1 == i)
219 _btnCountryTotal->setPressed(_countryToggles[i]->_pushed);
220 else if(i < GRAPH_MAX_BUTTONS)
221 _btnCountries.at(i)->setPressed(_countryToggles[i]->_pushed);
222 }
223 for (size_t i = 0; i < _financeToggles.size(); ++i)
224 {
225 _financeToggles[i] = ('0'==graphFinanceToggles[i]) ? false : true;
226 _btnFinances.at(i)->setPressed(_financeToggles[i]);
227 }
228
229 // set up the grid
230 _bg->drawRect(125, 49, 188, 127, Palette::blockOffset(10));
231
232 for (int grid = 0; grid !=5; ++grid)
233 {
234 for (int y = 50 + grid; y <= 163 + grid; y += 14)
235 {
236 for (int x = 126 + grid; x <= 297 + grid; x += 17)
237 {
238 Uint8 color = Palette::blockOffset(10)+grid+1;
239 if (grid == 4)
240 {
241 color = 0;
242 }
243 _bg->drawRect(x, y, 16 - (grid*2), 13 - (grid*2), color);
244 }
245 }
246 }
247
248 //set up the horizontal measurement units
249 std::string months[] = {"STR_JAN", "STR_FEB", "STR_MAR", "STR_APR", "STR_MAY", "STR_JUN", "STR_JUL", "STR_AUG", "STR_SEP", "STR_OCT", "STR_NOV", "STR_DEC"};
250 int month = _game->getSavedGame()->getTime()->getMonth();
251 // i know using textlist for this is ugly and brutal, but YOU try getting this damn text to line up.
252 // also, there's nothing wrong with being ugly or brutal, you should learn tolerance.
253 _txtMonths->setColumns(12, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17);
254 _txtMonths->addRow(12, L" ", L" ", L" ", L" ", L" ", L" ", L" ", L" ", L" ", L" ", L" ", L" ");
255 _txtMonths->setRowColor(0, Palette::blockOffset(6)+7);
256 _txtYears->setColumns(6, 34, 34, 34, 34, 34, 34);
257 _txtYears->addRow(6, L" ", L" ", L" ", L" ", L" ", L" ");
258 _txtYears->setRowColor(0, Palette::blockOffset(6)+7);
259
260 for (int iter = 0; iter != 12; ++iter)
261 {
262 if (month > 11)
263 {
264 month = 0;
265 std::wostringstream ss;
266 ss << _game->getSavedGame()->getTime()->getYear();
267 _txtYears->setCellText(0, iter/2, ss.str());
268 if (iter > 2)
269 {
270 std::wostringstream ss2;
271 ss2 << (_game->getSavedGame()->getTime()->getYear()-1);
272 _txtYears->setCellText(0, 0, ss2.str());
273 }
274 }
275 _txtMonths->setCellText(0, iter, tr(months[month]));
276 ++month;
277 }
278
279 // set up the vertical measurement units
280 for (std::vector<Text *>::iterator iter = _txtScale.begin(); iter != _txtScale.end(); ++iter)
281 {
282 (*iter)->setAlign(ALIGN_RIGHT);
283 (*iter)->setColor(Palette::blockOffset(6)+7);
284 }
285 btnUfoRegionClick(0);
286
287 // Set up objects
288 _game->getResourcePack()->getSurface("GRAPHS.SPK")->blit(_bg);
289 _txtTitle->setAlign(ALIGN_CENTER);
290 _txtTitle->setColor(Palette::blockOffset(8)+7);
291
292 _txtFactor->setText(L"$1000's");
293 _txtFactor->setColor(Palette::blockOffset(8)+7);
294
295 // Set up buttons
296 _btnUfoRegion->onMousePress((ActionHandler)&GraphsState::btnUfoRegionClick);
297 _btnUfoCountry->onMousePress((ActionHandler)&GraphsState::btnUfoCountryClick);
298 _btnXcomRegion->onMousePress((ActionHandler)&GraphsState::btnXcomRegionClick);
299 _btnXcomCountry->onMousePress((ActionHandler)&GraphsState::btnXcomCountryClick);
300 _btnIncome->onMousePress((ActionHandler)&GraphsState::btnIncomeClick);
301 _btnFinance->onMousePress((ActionHandler)&GraphsState::btnFinanceClick);
302 _btnGeoscape->onMousePress((ActionHandler)&GraphsState::btnGeoscapeClick);
303 _btnGeoscape->onKeyboardPress((ActionHandler)&GraphsState::btnGeoscapeClick, Options::keyCancel);
304 _btnGeoscape->onKeyboardPress((ActionHandler)&GraphsState::btnGeoscapeClick, Options::keyGeoGraphs);
305
306 centerAllSurfaces();
307 }
308
309 /**
310 *
311 */
~GraphsState()312 GraphsState::~GraphsState()
313 {
314 std::string graphRegionToggles = "";
315 std::string graphCountryToggles = "";
316 std::string graphFinanceToggles = "";
317 for (size_t i = 0; i < _regionToggles.size(); ++i)
318 {
319 graphRegionToggles.push_back(_regionToggles[i]->_pushed ? '1' : '0');
320 delete _regionToggles[i];
321 }
322 for (size_t i = 0; i < _countryToggles.size(); ++i)
323 {
324 graphCountryToggles.push_back(_countryToggles[i]->_pushed ? '1' : '0');
325 delete _countryToggles[i];
326 }
327 for (size_t i = 0; i < _financeToggles.size(); ++i)
328 {
329 graphFinanceToggles.push_back(_financeToggles[i] ? '1' : '0');
330 }
331 _game->getSavedGame()->setGraphRegionToggles(graphRegionToggles);
332 _game->getSavedGame()->setGraphCountryToggles(graphCountryToggles);
333 _game->getSavedGame()->setGraphFinanceToggles(graphFinanceToggles);
334 }
335
336 /**
337 * Returns to the previous screen.
338 * @param action Pointer to an action.
339 */
btnGeoscapeClick(Action *)340 void GraphsState::btnGeoscapeClick(Action *)
341 {
342 _game->popState();
343 }
344
345 /**
346 * Switches to the UFO Region Activity screen.
347 * @param action Pointer to an action.
348 */
btnUfoRegionClick(Action *)349 void GraphsState::btnUfoRegionClick(Action *)
350 {
351 _alien = true;
352 _income = false;
353 _country = false;
354 _finance = false;
355 resetScreen();
356 drawLines();
357 for (std::vector<ToggleTextButton *>::iterator iter = _btnRegions.begin(); iter != _btnRegions.end(); ++iter)
358 {
359 (*iter)->setVisible(true);
360 }
361 _btnRegionTotal->setVisible(true);
362 _txtTitle->setBig();
363 _txtTitle->setText(tr("STR_UFO_ACTIVITY_IN_AREAS"));
364 }
365
366 /**
367 * Switches to the UFO Country activity screen.
368 * @param action Pointer to an action.
369 */
btnUfoCountryClick(Action *)370 void GraphsState::btnUfoCountryClick(Action *)
371 {
372 _alien = true;
373 _income = false;
374 _country = true;
375 _finance = false;
376 resetScreen();
377 drawLines();
378 for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
379 {
380 (*iter)->setVisible(true);
381 }
382 _btnCountryTotal->setVisible(true);
383 _txtTitle->setBig();
384 _txtTitle->setText(tr("STR_UFO_ACTIVITY_IN_COUNTRIES"));
385 }
386
387 /**
388 * Switches to the XCom Region activity screen.
389 * @param action Pointer to an action.
390 */
btnXcomRegionClick(Action *)391 void GraphsState::btnXcomRegionClick(Action *)
392 {
393 _alien = false;
394 _income = false;
395 _country = false;
396 _finance = false;
397 resetScreen();
398 drawLines();
399 for (std::vector<ToggleTextButton *>::iterator iter = _btnRegions.begin(); iter != _btnRegions.end(); ++iter)
400 {
401 (*iter)->setVisible(true);
402 }
403 _btnRegionTotal->setVisible(true);
404 _txtTitle->setBig();
405 _txtTitle->setText(tr("STR_XCOM_ACTIVITY_IN_AREAS"));
406 }
407
408 /**
409 * Switches to the XCom Country activity screen.
410 * @param action Pointer to an action.
411 */
btnXcomCountryClick(Action *)412 void GraphsState::btnXcomCountryClick(Action *)
413 {
414 _alien = false;
415 _income = false;
416 _country = true;
417 _finance = false;
418 resetScreen();
419 drawLines();
420 for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
421 {
422 (*iter)->setVisible(true);
423 }
424 _btnCountryTotal->setVisible(true);
425 _txtTitle->setBig();
426 _txtTitle->setText(tr("STR_XCOM_ACTIVITY_IN_COUNTRIES"));
427 }
428
429 /**
430 * Switches to the Income screen.
431 * @param action Pointer to an action.
432 */
btnIncomeClick(Action *)433 void GraphsState::btnIncomeClick(Action *)
434 {
435 _alien = false;
436 _income = true;
437 _country = true;
438 _finance = false;
439 resetScreen();
440 drawLines();
441 _txtFactor->setVisible(true);
442 for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
443 {
444 (*iter)->setVisible(true);
445 }
446 _btnCountryTotal->setVisible(true);
447 _txtTitle->setBig();
448 _txtTitle->setText(tr("STR_INCOME"));
449 }
450
451 /**
452 * Switches to the Finances screen.
453 * @param action Pointer to an action.
454 */
btnFinanceClick(Action *)455 void GraphsState::btnFinanceClick(Action *)
456 {
457 _alien = false;
458 _income = false;
459 _country = false;
460 _finance = true;
461 resetScreen();
462 drawLines();
463
464 for (std::vector<ToggleTextButton *>::iterator iter = _btnFinances.begin(); iter != _btnFinances.end(); ++iter)
465 {
466 (*iter)->setVisible(true);
467 }
468 _txtTitle->setBig();
469 _txtTitle->setText(tr("STR_FINANCE"));
470
471 }
472
473 /**
474 * Handles a click on a region button.
475 * @param action Pointer to an action.
476 */
btnRegionListClick(Action * action)477 void GraphsState::btnRegionListClick(Action * action)
478 {
479 size_t number = (action->getSender()->getY()-_game->getScreen()->getDY())/11;
480 ToggleTextButton *button = 0;
481
482 if ((_regionToggles.size() <= GRAPH_MAX_BUTTONS + 1 && number == _regionToggles.size()-1)||(_regionToggles.size() > GRAPH_MAX_BUTTONS + 1 && number == GRAPH_MAX_BUTTONS))
483 {
484 button = _btnRegionTotal;
485 }
486 else
487 {
488 button = _btnRegions.at(number);
489 }
490
491 _regionToggles.at(number+_butRegionsOffset)->_pushed = button->getPressed();
492
493 drawLines();
494 }
495
496 /**
497 * Handles a click on a country button.
498 * @param action Pointer to an action.
499 */
btnCountryListClick(Action * action)500 void GraphsState::btnCountryListClick(Action * action)
501 {
502 size_t number = (action->getSender()->getY()-_game->getScreen()->getDY())/11;
503 ToggleTextButton *button = 0;
504
505 if ((_countryToggles.size() <= GRAPH_MAX_BUTTONS + 1 && number == _countryToggles.size()-1)||(_countryToggles.size() > GRAPH_MAX_BUTTONS + 1 && number == GRAPH_MAX_BUTTONS))
506 {
507 button = _btnCountryTotal;
508 }
509 else
510 {
511 button = _btnCountries.at(number);
512 }
513
514 _countryToggles.at(number+_butCountriesOffset)->_pushed = button->getPressed();
515
516 drawLines();
517 }
518
519 /**
520 * handles a click on a finances button.
521 * @param action Pointer to an action.
522 */
btnFinanceListClick(Action * action)523 void GraphsState::btnFinanceListClick(Action *action)
524 {
525 size_t number = (action->getSender()->getY()-_game->getScreen()->getDY())/11;
526 ToggleTextButton *button = _btnFinances.at(number);
527
528 _financeLines.at(number)->setVisible(!_financeToggles.at(number));
529 _financeToggles.at(number) = button->getPressed();
530
531 drawLines();
532 }
533
534 /**
535 * remove all elements from view
536 */
resetScreen()537 void GraphsState::resetScreen()
538 {
539 for (std::vector<Surface *>::iterator iter = _alienRegionLines.begin(); iter != _alienRegionLines.end(); ++iter)
540 {
541 (*iter)->setVisible(false);
542 }
543 for (std::vector<Surface *>::iterator iter = _alienCountryLines.begin(); iter != _alienCountryLines.end(); ++iter)
544 {
545 (*iter)->setVisible(false);
546 }
547 for (std::vector<Surface *>::iterator iter = _xcomRegionLines.begin(); iter != _xcomRegionLines.end(); ++iter)
548 {
549 (*iter)->setVisible(false);
550 }
551 for (std::vector<Surface *>::iterator iter = _xcomCountryLines.begin(); iter != _xcomCountryLines.end(); ++iter)
552 {
553 (*iter)->setVisible(false);
554 }
555 for (std::vector<Surface *>::iterator iter = _incomeLines.begin(); iter != _incomeLines.end(); ++iter)
556 {
557 (*iter)->setVisible(false);
558 }
559 for (std::vector<Surface *>::iterator iter = _financeLines.begin(); iter != _financeLines.end(); ++iter)
560 {
561 (*iter)->setVisible(false);
562 }
563
564
565 for (std::vector<ToggleTextButton *>::iterator iter = _btnRegions.begin(); iter != _btnRegions.end(); ++iter)
566 {
567 (*iter)->setVisible(false);
568 }
569 for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
570 {
571 (*iter)->setVisible(false);
572 }
573 for (std::vector<ToggleTextButton *>::iterator iter = _btnFinances.begin(); iter != _btnFinances.end(); ++iter)
574 {
575 (*iter)->setVisible(false);
576 }
577
578 _btnRegionTotal->setVisible(false);
579 _btnCountryTotal->setVisible(false);
580 _txtFactor->setVisible(false);
581 }
582
583 /**
584 * updates the text on the vertical scale
585 * @param lowerLimit minimum value
586 * @param upperLimit maximum value
587 */
updateScale(double lowerLimit,double upperLimit)588 void GraphsState::updateScale(double lowerLimit, double upperLimit)
589 {
590 double increment = ((upperLimit - lowerLimit) / 9);
591 if (increment < 10)
592 {
593 increment = 10;
594 }
595 double text = lowerLimit;
596 for (int i = 0; i < 10; ++i)
597 {
598 _txtScale.at(i)->setText(Text::formatNumber(static_cast<int>(text)));
599 text += increment;
600 }
601 }
602
603 /**
604 * instead of having all our line drawing in one giant ridiculous routine, just use the one we need.
605 */
drawLines()606 void GraphsState::drawLines()
607 {
608 if (!_country && !_finance)
609 {
610 drawRegionLines();
611 }
612 else if (!_finance)
613 {
614 drawCountryLines();
615 }
616 else
617 {
618 drawFinanceLines();
619 }
620 }
621
622 /**
623 * Sets up the screens and draws the lines for country buttons
624 * to toggle on and off
625 */
drawCountryLines()626 void GraphsState::drawCountryLines()
627 {
628 //calculate the totals, and set up our upward maximum
629 int upperLimit = 0;
630 int lowerLimit = 0;
631 int totals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
632 for (size_t entry = 0; entry != _game->getSavedGame()->getFundsList().size(); ++entry)
633 {
634 int total = 0;
635 if (_alien)
636 {
637 for (size_t iter = 0; iter != _game->getSavedGame()->getCountries()->size(); ++iter)
638 {
639 total += _game->getSavedGame()->getCountries()->at(iter)->getActivityAlien().at(entry);
640 if (_game->getSavedGame()->getCountries()->at(iter)->getActivityAlien().at(entry) > upperLimit && _countryToggles.at(iter)->_pushed)
641 {
642 upperLimit = _game->getSavedGame()->getCountries()->at(iter)->getActivityAlien().at(entry);
643 }
644 }
645 }
646 else if (_income)
647 {
648 for (size_t iter = 0; iter != _game->getSavedGame()->getCountries()->size(); ++iter)
649 {
650 total += _game->getSavedGame()->getCountries()->at(iter)->getFunding().at(entry) / 1000;
651 if (_game->getSavedGame()->getCountries()->at(iter)->getFunding().at(entry) / 1000 > upperLimit && _countryToggles.at(iter)->_pushed)
652 {
653 upperLimit = _game->getSavedGame()->getCountries()->at(iter)->getFunding().at(entry) / 1000;
654 }
655 }
656 }
657 else
658 {
659 for (size_t iter = 0; iter != _game->getSavedGame()->getCountries()->size(); ++iter)
660 {
661 total += _game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry);
662 if (_game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry) > upperLimit && _countryToggles.at(iter)->_pushed)
663 {
664 upperLimit = _game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry);
665 }
666 if (_game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry) < lowerLimit && _countryToggles.at(iter)->_pushed)
667 {
668 lowerLimit = _game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry);
669 }
670
671 }
672 }
673 if (_countryToggles.back()->_pushed && total > upperLimit)
674 upperLimit = total;
675 }
676
677 //adjust the scale to fit the upward maximum
678 double range = upperLimit - lowerLimit;
679 double low = lowerLimit;
680 int grids = 9; // cells in grid
681 int check = _income ? 50 : 10;
682 while (range > check * grids)
683 {
684 check *= 2;
685 }
686
687 lowerLimit = 0;
688 upperLimit = check * grids;
689
690 if (low < 0)
691 {
692 while (low < lowerLimit)
693 {
694 lowerLimit -= check;
695 // upperLimit -= check;
696 }
697 }
698
699 range = upperLimit - lowerLimit;
700 double units = range / 126;
701
702 // draw country lines
703 for (size_t entry = 0; entry != _game->getSavedGame()->getCountries()->size(); ++entry)
704 {
705 Country *country = _game->getSavedGame()->getCountries()->at(entry);
706 _alienCountryLines.at(entry)->clear();
707 _xcomCountryLines.at(entry)->clear();
708 _incomeLines.at(entry)->clear();
709 std::vector<Sint16> newLineVector;
710 int reduction = 0;
711 for (size_t iter = 0; iter != 12; ++iter)
712 {
713 int x = 312 - (iter*17);
714 int y = 175 - (-lowerLimit / units);
715 if (_alien)
716 {
717 if (iter < country->getActivityAlien().size())
718 {
719 reduction = country->getActivityAlien().at(country->getActivityAlien().size()-(1+iter)) / units;
720 y -= reduction;
721 totals[iter] += country->getActivityAlien().at(country->getActivityAlien().size()-(1+iter));
722 }
723 }
724 else if (_income)
725 {
726 if (iter < country->getFunding().size())
727 {
728 reduction = (country->getFunding().at(country->getFunding().size()-(1+iter)) / 1000) / units;
729 y -= reduction;
730 totals[iter] += country->getFunding().at(country->getFunding().size()-(1+iter)) / 1000;
731 }
732 }
733 else
734 {
735 if (iter < country->getActivityXcom().size())
736 {
737 reduction = country->getActivityXcom().at(country->getActivityXcom().size()-(1+iter)) / units;
738 y -= reduction;
739 totals[iter] += country->getActivityXcom().at(country->getActivityXcom().size()-(1+iter));
740 }
741 }
742 if (y >=175)
743 y = 175;
744 newLineVector.push_back(y);
745 int offset = 0;
746 if (entry % 2)
747 offset = 8;
748 if (newLineVector.size() > 1 && _alien)
749 _alienCountryLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((entry/2)+1)+offset);
750 else if (newLineVector.size() > 1 && _income)
751 _incomeLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((entry/2)+1)+offset);
752 else if (newLineVector.size() > 1)
753 _xcomCountryLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((entry/2)+1)+offset);
754 }
755 if (_alien)
756 _alienCountryLines.at(entry)->setVisible(_countryToggles.at(entry)->_pushed);
757 else if (_income)
758 _incomeLines.at(entry)->setVisible(_countryToggles.at(entry)->_pushed);
759 else
760 _xcomCountryLines.at(entry)->setVisible(_countryToggles.at(entry)->_pushed);
761 }
762 if (_alien)
763 _alienCountryLines.back()->clear();
764 else if (_income)
765 _incomeLines.back()->clear();
766 else
767 _xcomCountryLines.back()->clear();
768
769 // set up the "total" line
770 std::vector<Sint16> newLineVector;
771 for (int iter = 0; iter != 12; ++iter)
772 {
773 int x = 312 - (iter*17);
774 int y = 175 - (-lowerLimit / units);
775 if (totals[iter] > 0)
776 {
777 int reduction = totals[iter] / units;
778 y -= reduction;
779 }
780 newLineVector.push_back(y);
781 if (newLineVector.size() > 1)
782 {
783 if (_alien)
784 _alienCountryLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset(9));
785 else if (_income)
786 _incomeLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset(9));
787 else
788 _xcomCountryLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset(9));
789 }
790 }
791 if (_alien)
792 _alienCountryLines.back()->setVisible(_countryToggles.back()->_pushed);
793 else if (_income)
794 _incomeLines.back()->setVisible(_countryToggles.back()->_pushed);
795 else
796 _xcomCountryLines.back()->setVisible(_countryToggles.back()->_pushed);
797 updateScale(lowerLimit, upperLimit);
798 _txtFactor->setVisible(_income);
799 }
800
801 /**
802 * Sets up the screens and draws the lines for region buttons
803 * to toggle on and off
804 */
drawRegionLines()805 void GraphsState::drawRegionLines()
806 {
807 //calculate the totals, and set up our upward maximum
808 int upperLimit = 0;
809 int lowerLimit = 0;
810 int totals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
811 for (size_t entry = 0; entry != _game->getSavedGame()->getFundsList().size(); ++entry)
812 {
813 int total = 0;
814 if (_alien)
815 {
816 for (size_t iter = 0; iter != _game->getSavedGame()->getRegions()->size(); ++iter)
817 {
818 total += _game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry);
819 if (_game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry) > upperLimit && _regionToggles.at(iter)->_pushed)
820 {
821 upperLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry);
822 }
823 if (_game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry) < lowerLimit && _regionToggles.at(iter)->_pushed)
824 {
825 lowerLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry);
826 }
827 }
828 }
829 else
830 {
831 for (size_t iter = 0; iter != _game->getSavedGame()->getRegions()->size(); ++iter)
832 {
833 total += _game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry);
834 if (_game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry) > upperLimit && _regionToggles.at(iter)->_pushed)
835 {
836 upperLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry);
837 }
838 if (_game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry) < lowerLimit && _regionToggles.at(iter)->_pushed)
839 {
840 lowerLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry);
841 }
842 }
843 }
844 if (_regionToggles.back()->_pushed && total > upperLimit)
845 upperLimit = total;
846 }
847
848 //adjust the scale to fit the upward maximum
849 double range = upperLimit - lowerLimit;
850 double low = lowerLimit;
851 int check = 10;
852 while (range > check * 9)
853 {
854 check *= 2;
855 }
856
857 lowerLimit = 0;
858 upperLimit = check * 9;
859
860 if (low < 0)
861 {
862 while (low < lowerLimit)
863 {
864 lowerLimit -= check;
865 // upperLimit -= check;
866 }
867 }
868 range = upperLimit - lowerLimit;
869 double units = range / 126;
870 // draw region lines
871 for (size_t entry = 0; entry != _game->getSavedGame()->getRegions()->size(); ++entry)
872 {
873 Region *region = _game->getSavedGame()->getRegions()->at(entry);
874 _alienRegionLines.at(entry)->clear();
875 _xcomRegionLines.at(entry)->clear();
876 std::vector<Sint16> newLineVector;
877 int reduction = 0;
878 for (size_t iter = 0; iter != 12; ++iter)
879 {
880 int x = 312 - (iter*17);
881 int y = 175 - (-lowerLimit / units);
882 if (_alien)
883 {
884 if (iter < region->getActivityAlien().size())
885 {
886 reduction = region->getActivityAlien().at(region->getActivityAlien().size()-(1+iter)) / units;
887 y -= reduction;
888 totals[iter] += region->getActivityAlien().at(region->getActivityAlien().size()-(1+iter));
889 }
890 }
891 else
892 {
893 if (iter < region->getActivityXcom().size())
894 {
895 reduction = region->getActivityXcom().at(region->getActivityXcom().size()-(1+iter)) / units;
896 y -= reduction;
897 totals[iter] += region->getActivityXcom().at(region->getActivityXcom().size()-(1+iter));
898 }
899 }
900 if (y >=175)
901 y = 175;
902 newLineVector.push_back(y);
903 int offset = 0;
904 if (entry % 2)
905 offset = 8;
906 if (newLineVector.size() > 1 && _alien)
907 _alienRegionLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((entry/2)+1)+offset);
908 else if (newLineVector.size() > 1)
909 _xcomRegionLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((entry/2)+1)+offset);
910 }
911
912 if (_alien)
913 _alienRegionLines.at(entry)->setVisible(_regionToggles.at(entry)->_pushed);
914 else
915 _xcomRegionLines.at(entry)->setVisible(_regionToggles.at(entry)->_pushed);
916 }
917
918 // set up the "total" line
919 if (_alien)
920 _alienRegionLines.back()->clear();
921 else
922 _xcomRegionLines.back()->clear();
923
924 std::vector<Sint16> newLineVector;
925 for (int iter = 0; iter != 12; ++iter)
926 {
927 int x = 312 - (iter*17);
928 int y = 175;
929 if (totals[iter] > 0)
930 {
931 int reduction = totals[iter] / units;
932 y -= reduction;
933 }
934 newLineVector.push_back(y);
935 if (newLineVector.size() > 1)
936 {
937 if (_alien)
938 _alienRegionLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset(9)-8);
939 else
940 _xcomRegionLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset(9)-8);
941 }
942 }
943 if (_alien)
944 _alienRegionLines.back()->setVisible(_regionToggles.back()->_pushed);
945 else
946 _xcomRegionLines.back()->setVisible(_regionToggles.back()->_pushed);
947 updateScale(lowerLimit, upperLimit);
948 _txtFactor->setVisible(false);
949 }
950
951 /**
952 * Sets up the screens and draws the lines for the finance buttons
953 * to toggle on and off
954 */
drawFinanceLines()955 void GraphsState::drawFinanceLines()
956 {
957 //set up arrays
958 int upperLimit = 0;
959 int lowerLimit = 0;
960 int incomeTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
961 int balanceTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
962 int expendTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
963 int maintTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
964 int scoreTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
965 maintTotals[0] = _game->getSavedGame()->getBaseMaintenance() / 1000;
966
967 // start filling those arrays with score values
968 // determine which is the highest one being displayed, so we can adjust the scale
969 for (size_t entry = 0; entry != _game->getSavedGame()->getFundsList().size(); ++entry)
970 {
971 size_t invertedEntry = _game->getSavedGame()->getFundsList().size() - (1 + entry);
972 maintTotals[entry] += _game->getSavedGame()->getMaintenances().at(invertedEntry) / 1000;
973 balanceTotals[entry] = _game->getSavedGame()->getFundsList().at(invertedEntry) / 1000;
974 scoreTotals[entry] = _game->getSavedGame()->getResearchScores().at(invertedEntry);
975
976 for (std::vector<Region*>::iterator iter = _game->getSavedGame()->getRegions()->begin(); iter != _game->getSavedGame()->getRegions()->end(); ++iter)
977 {
978 scoreTotals[entry] += (*iter)->getActivityXcom().at(invertedEntry) - (*iter)->getActivityAlien().at(invertedEntry);
979 }
980
981 if (_financeToggles.at(2))
982 {
983 if (maintTotals[entry] > upperLimit)
984 {
985 upperLimit = maintTotals[entry];
986 }
987 if (maintTotals[entry] < lowerLimit)
988 {
989 lowerLimit = maintTotals[entry];
990 }
991 }
992 if (_financeToggles.at(3))
993 {
994 if (balanceTotals[entry] > upperLimit)
995 {
996 upperLimit = balanceTotals[entry];
997 }
998 if (balanceTotals[entry] < lowerLimit)
999 {
1000 lowerLimit = balanceTotals[entry];
1001 }
1002 }
1003 if (_financeToggles.at(4))
1004 {
1005 if (scoreTotals[entry] > upperLimit)
1006 {
1007 upperLimit = scoreTotals[entry];
1008 }
1009 if (scoreTotals[entry] < lowerLimit)
1010 {
1011 lowerLimit = scoreTotals[entry];
1012 }
1013 }
1014 }
1015
1016 for (size_t entry = 0; entry != _game->getSavedGame()->getExpenditures().size(); ++entry)
1017 {
1018 expendTotals[entry] = _game->getSavedGame()->getExpenditures().at(_game->getSavedGame()->getExpenditures().size() - (entry + 1)) / 1000;
1019 incomeTotals[entry] = _game->getSavedGame()->getIncomes().at(_game->getSavedGame()->getIncomes().size() - (entry + 1)) / 1000;
1020
1021 if (_financeToggles.at(0) && incomeTotals[entry] > upperLimit)
1022 {
1023 upperLimit = incomeTotals[entry];
1024 }
1025 if (_financeToggles.at(1) && expendTotals[entry] > upperLimit)
1026 {
1027 upperLimit = expendTotals[entry];
1028 }
1029 }
1030
1031 double range = upperLimit - lowerLimit;
1032 double low = lowerLimit;
1033 int check = 250;
1034 while (range > check * 9)
1035 {
1036 check *= 2;
1037 }
1038
1039 lowerLimit = 0;
1040 upperLimit = check * 9;
1041
1042 if (low < 0)
1043 {
1044 while (low < lowerLimit)
1045 {
1046 lowerLimit -= check;
1047 // upperLimit -= check;
1048 }
1049 }
1050 //toggle screens
1051 for (int button = 0; button != 5; ++button)
1052 {
1053 _financeLines.at(button)->setVisible(_financeToggles.at(button));
1054 _financeLines.at(button)->clear();
1055 }
1056 range = upperLimit - lowerLimit;
1057 //figure out how many units to the pixel, then plot the points for the graph and connect the dots.
1058 double units = range / 126;
1059 for (int button = 0; button != 5; ++button)
1060 {
1061 std::vector<Sint16> newLineVector;
1062 for (int iter = 0; iter != 12; ++iter)
1063 {
1064 int x = 312 - (iter*17);
1065 int y = 175 - (-lowerLimit / units);
1066 int reduction = 0;
1067 switch(button)
1068 {
1069 case 0:
1070 reduction = incomeTotals[iter] / units;
1071 break;
1072 case 1:
1073 reduction = expendTotals[iter] / units;
1074 break;
1075 case 2:
1076 reduction = maintTotals[iter] / units;
1077 break;
1078 case 3:
1079 reduction = balanceTotals[iter] / units;
1080 break;
1081 case 4:
1082 reduction = scoreTotals[iter] / units;
1083 break;
1084 }
1085 y -= reduction;
1086 newLineVector.push_back(y);
1087 int offset = button % 2 ? 8 : 0;
1088 if (newLineVector.size() > 1)
1089 _financeLines.at(button)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((button/2)+1)+offset);
1090 }
1091 }
1092 updateScale(lowerLimit, upperLimit);
1093 _txtFactor->setVisible(true);
1094 }
1095
1096 /**
1097 * 'Shift' the buttons to display only GRAPH_MAX_BUTTONS - reset their state from toggles
1098 */
shiftButtons(Action * action)1099 void GraphsState::shiftButtons(Action *action)
1100 {
1101 // only if active 'screen' is other than finance
1102 if(_finance)
1103 return;
1104 // select the data's we'll processing - regions or countries
1105 if(_country)
1106 {
1107 // too few countries? - return
1108 if(_countryToggles.size() <= GRAPH_MAX_BUTTONS)
1109 return;
1110 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
1111 scrollButtons(_countryToggles, _btnCountries, _butCountriesOffset, -1);
1112 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
1113 scrollButtons(_countryToggles, _btnCountries, _butCountriesOffset, 1);
1114 }
1115 else
1116 {
1117 // too few regions? - return
1118 if(_regionToggles.size() <= GRAPH_MAX_BUTTONS)
1119 return;
1120 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
1121 scrollButtons(_regionToggles, _btnRegions, _butRegionsOffset, -1);
1122 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
1123 scrollButtons(_regionToggles, _btnRegions, _butRegionsOffset, 1);
1124 }
1125 }
scrollButtons(std::vector<GraphButInfo * > & toggles,std::vector<ToggleTextButton * > & buttons,size_t & offset,int step)1126 void GraphsState::scrollButtons(std::vector<GraphButInfo *> &toggles, std::vector<ToggleTextButton *> &buttons, size_t &offset, int step)
1127 {
1128 // minus one, 'cause we'll already added the TOTAL button to toggles
1129 if( int(step + (int)offset) < 0 || offset + step + GRAPH_MAX_BUTTONS >= toggles.size()-1)
1130 return;
1131 // set the next offset - cheaper to do it from starters
1132 offset+=step;
1133 size_t i=0;
1134 std::vector<ToggleTextButton *>::iterator iterb=buttons.begin();
1135 for(std::vector<GraphButInfo *>::iterator itert=toggles.begin(); itert != toggles.end();++itert,++i)
1136 if(i < offset)
1137 continue;
1138 else if(i < offset+GRAPH_MAX_BUTTONS)
1139 updateButton(*itert,*iterb++);
1140 else
1141 return;
1142 }
updateButton(GraphButInfo * from,ToggleTextButton * to)1143 void GraphsState::updateButton(GraphButInfo *from,ToggleTextButton *to)
1144 {
1145 to->setText(from->_name);
1146 to->setInvertColor(from->_color);
1147 to->setPressed(from->_pushed);
1148 }
1149 }
1150