/*
* Copyright 2010-2016 OpenXcom Developers.
*
* This file is part of OpenXcom.
*
* OpenXcom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenXcom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GraphsState.h"
#include <sstream>
#include "../Engine/Game.h"
#include "../Mod/Mod.h"
#include "../Engine/Palette.h"
#include "../Engine/Surface.h"
#include "../Engine/InteractiveSurface.h"
#include "../Savegame/Country.h"
#include "../Savegame/Region.h"
#include "../Mod/RuleCountry.h"
#include "../Mod/RuleRegion.h"
#include "../Interface/Text.h"
#include "../Engine/LocalizedText.h"
#include "../Interface/TextButton.h"
#include "../Interface/ToggleTextButton.h"
#include "../Savegame/GameTime.h"
#include "../Savegame/SavedGame.h"
#include "../Interface/TextList.h"
#include "../Engine/Action.h"
#include "../Engine/Options.h"
#include "../Engine/Unicode.h"
#include "../Mod/RuleInterface.h"
namespace OpenXcom
{
struct GraphButInfo
{
LocalizedText _name;
int _color;
bool _pushed;
GraphButInfo(const LocalizedText& name, Uint8 color): _name(name), _color(color), _pushed(false) {}
};
/**
* Initializes all the elements in the Graphs screen.
* @param game Pointer to the core game.
*/
GraphsState::GraphsState() : _butRegionsOffset(0), _butCountriesOffset(0)
{
// Create objects
_bg = new InteractiveSurface(320, 200, 0, 0);
_bg->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELUP);
_bg->onMousePress((ActionHandler)&GraphsState::shiftButtons, SDL_BUTTON_WHEELDOWN);
_btnUfoRegion = new InteractiveSurface(32, 24, 96, 0);
_btnUfoCountry = new InteractiveSurface(32, 24, 128, 0);
_btnXcomRegion = new InteractiveSurface(32, 24, 160, 0);
_btnXcomCountry = new InteractiveSurface(32, 24, 192, 0);
_btnIncome = new InteractiveSurface(32, 24, 224, 0);
_btnFinance = new InteractiveSurface(32, 24, 256, 0);
_btnGeoscape = new InteractiveSurface(32, 24, 288, 0);
_txtTitle = new Text(230, 16, 90, 28);
_txtFactor = new Text(38, 11, 96, 28);
_txtMonths = new TextList(205, 8, 115, 183);
_txtYears = new TextList(200, 8, 121, 191);
// Set palette
setInterface("graphs");
//add all our elements
add(_bg);
add(_btnUfoRegion);
add(_btnUfoCountry);
add(_btnXcomRegion);
add(_btnXcomCountry);
add(_btnIncome);
add(_btnFinance);
add(_btnGeoscape);
add(_txtMonths, "scale", "graphs");
add(_txtYears, "scale", "graphs");
add(_txtTitle, "text", "graphs");
add(_txtFactor, "text", "graphs");
for (int scaleText = 0; scaleText != 10; ++scaleText)
{
_txtScale.push_back(new Text(42, 16, 80, 171 - (scaleText*14)));
add(_txtScale.at(scaleText), "scale", "graphs");
}
Uint8 regionTotalColor = _game->getMod()->getInterface("graphs")->getElement("regionTotal")->color;
Uint8 countryTotalColor = _game->getMod()->getInterface("graphs")->getElement("countryTotal")->color;
//create buttons (sooooo many buttons)
size_t offset = 0;
for (std::vector<Region *>::iterator iter = _game->getSavedGame()->getRegions()->begin(); iter != _game->getSavedGame()->getRegions()->end(); ++iter)
{
// always save in toggles all the regions
Uint8 color = 13 + 8 * (offset % GRAPH_MAX_BUTTONS);
_regionToggles.push_back(new GraphButInfo(tr((*iter)->getRules()->getType()), color));
// initially add the GRAPH_MAX_BUTTONS having the first regions information
if (offset < GRAPH_MAX_BUTTONS)
{
_btnRegions.push_back(new ToggleTextButton(88, 11, 0, offset*11));
_btnRegions.at(offset)->setText(tr((*iter)->getRules()->getType()));
_btnRegions.at(offset)->setInvertColor(color);
_btnRegions.at(offset)->onMousePress((ActionHandler)&GraphsState::btnRegionListClick);
add(_btnRegions.at(offset), "button", "graphs");
}
_alienRegionLines.push_back(new Surface(320,200,0,0));
add(_alienRegionLines.at(offset));
_xcomRegionLines.push_back(new Surface(320,200,0,0));
add(_xcomRegionLines.at(offset));
++offset;
}
if (_regionToggles.size() < GRAPH_MAX_BUTTONS)
_btnRegionTotal = new ToggleTextButton(88, 11, 0, _regionToggles.size()*11);
else
_btnRegionTotal = new ToggleTextButton(88, 11, 0, GRAPH_MAX_BUTTONS*11);
_regionToggles.push_back(new GraphButInfo(tr("STR_TOTAL_UC"), regionTotalColor));
_btnRegionTotal->onMousePress((ActionHandler)&GraphsState::btnRegionListClick);
_btnRegionTotal->setInvertColor(regionTotalColor);
_btnRegionTotal->setText(tr("STR_TOTAL_UC"));
_alienRegionLines.push_back(new Surface(320,200,0,0));
add(_alienRegionLines.at(offset));
_xcomRegionLines.push_back(new Surface(320,200,0,0));
add(_xcomRegionLines.at(offset));
add(_btnRegionTotal, "button", "graphs");
offset = 0;
for (std::vector<Country *>::iterator iter = _game->getSavedGame()->getCountries()->begin(); iter != _game->getSavedGame()->getCountries()->end(); ++iter)
{
// always save in toggles all the countries
Uint8 color = 13 + 8 * (offset % GRAPH_MAX_BUTTONS);
_countryToggles.push_back(new GraphButInfo(tr((*iter)->getRules()->getType()), color));
// initially add the GRAPH_MAX_BUTTONS having the first countries information
if (offset < GRAPH_MAX_BUTTONS)
{
_btnCountries.push_back(new ToggleTextButton(88, 11, 0, offset*11));
_btnCountries.at(offset)->setInvertColor(color);
_btnCountries.at(offset)->setText(tr((*iter)->getRules()->getType()));
_btnCountries.at(offset)->onMousePress((ActionHandler)&GraphsState::btnCountryListClick);
add(_btnCountries.at(offset), "button", "graphs");
}
_alienCountryLines.push_back(new Surface(320,200,0,0));
add(_alienCountryLines.at(offset));
_xcomCountryLines.push_back(new Surface(320,200,0,0));
add(_xcomCountryLines.at(offset));
_incomeLines.push_back(new Surface(320,200,0,0));
add(_incomeLines.at(offset));
++offset;
}
if (_countryToggles.size() < GRAPH_MAX_BUTTONS)
_btnCountryTotal = new ToggleTextButton(88, 11, 0, _countryToggles.size()*11);
else
_btnCountryTotal = new ToggleTextButton(88, 11, 0, GRAPH_MAX_BUTTONS*11);
_countryToggles.push_back(new GraphButInfo(tr("STR_TOTAL_UC"), countryTotalColor));
_btnCountryTotal->onMousePress((ActionHandler)&GraphsState::btnCountryListClick);
_btnCountryTotal->setInvertColor(countryTotalColor);
_btnCountryTotal->setText(tr("STR_TOTAL_UC"));
_alienCountryLines.push_back(new Surface(320,200,0,0));
add(_alienCountryLines.at(offset));
_xcomCountryLines.push_back(new Surface(320,200,0,0));
add(_xcomCountryLines.at(offset));
_incomeLines.push_back(new Surface(320,200,0,0));
add(_incomeLines.at(offset));
add(_btnCountryTotal, "button", "graphs");
for (int iter = 0; iter != 5; ++iter)
{
offset = iter;
_btnFinances.push_back(new ToggleTextButton(88, 11, 0, offset*11));
_financeToggles.push_back(false);
_btnFinances.at(offset)->setInvertColor(13 + (8*offset));
_btnFinances.at(offset)->onMousePress((ActionHandler)&GraphsState::btnFinanceListClick);
add(_btnFinances.at(offset), "button", "graphs");
_financeLines.push_back(new Surface(320,200,0,0));
add(_financeLines.at(offset));
}
_btnFinances.at(0)->setText(tr("STR_INCOME"));
_btnFinances.at(1)->setText(tr("STR_EXPENDITURE"));
_btnFinances.at(2)->setText(tr("STR_MAINTENANCE"));
_btnFinances.at(3)->setText(tr("STR_BALANCE"));
_btnFinances.at(4)->setText(tr("STR_SCORE"));
// load back the button states
std::string graphRegionToggles = _game->getSavedGame()->getGraphRegionToggles();
std::string graphCountryToggles = _game->getSavedGame()->getGraphCountryToggles();
std::string graphFinanceToggles = _game->getSavedGame()->getGraphFinanceToggles();
while (graphRegionToggles.size() < _regionToggles.size()) graphRegionToggles.push_back('0');
while (graphCountryToggles.size() < _countryToggles.size()) graphCountryToggles.push_back('0');
while (graphFinanceToggles.size() < _financeToggles.size()) graphFinanceToggles.push_back('0');
for (size_t i = 0; i < _regionToggles.size(); ++i)
{
_regionToggles[i]->_pushed = ('0'==graphRegionToggles[i]) ? false : true;
if (_regionToggles.size()-1 == i)
_btnRegionTotal->setPressed(_regionToggles[i]->_pushed);
else if (i < GRAPH_MAX_BUTTONS)
_btnRegions.at(i)->setPressed(_regionToggles[i]->_pushed);
}
for (size_t i = 0; i < _countryToggles.size(); ++i)
{
_countryToggles[i]->_pushed = ('0'==graphCountryToggles[i]) ? false : true;
if (_countryToggles.size()-1 == i)
_btnCountryTotal->setPressed(_countryToggles[i]->_pushed);
else if (i < GRAPH_MAX_BUTTONS)
_btnCountries.at(i)->setPressed(_countryToggles[i]->_pushed);
}
for (size_t i = 0; i < _financeToggles.size(); ++i)
{
_financeToggles[i] = ('0'==graphFinanceToggles[i]) ? false : true;
_btnFinances.at(i)->setPressed(_financeToggles[i]);
}
Uint8 gridColor = _game->getMod()->getInterface("graphs")->getElement("graph")->color;
// set up the grid
_bg->drawRect(125, 49, 188, 127, gridColor);
for (int grid = 0; grid !=5; ++grid)
{
for (int y = 50 + grid; y <= 163 + grid; y += 14)
{
for (int x = 126 + grid; x <= 297 + grid; x += 17)
{
Uint8 color = gridColor + grid + 1;
if (grid == 4)
{
color = 0;
}
_bg->drawRect(x, y, 16 - (grid*2), 13 - (grid*2), color);
}
}
}
//set up the horizontal measurement units
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"};
int month = _game->getSavedGame()->getTime()->getMonth();
// i know using textlist for this is ugly and brutal, but YOU try getting this damn text to line up.
// also, there's nothing wrong with being ugly or brutal, you should learn tolerance.
_txtMonths->setColumns(12, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17);
_txtMonths->addRow(12, " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ");
_txtYears->setColumns(6, 34, 34, 34, 34, 34, 34);
_txtYears->addRow(6, " ", " ", " ", " ", " ", " ");
for (int iter = 0; iter != 12; ++iter)
{
if (month > 11)
{
month = 0;
std::ostringstream ss;
ss << _game->getSavedGame()->getTime()->getYear();
_txtYears->setCellText(0, iter/2, ss.str());
if (iter > 2)
{
std::ostringstream ss2;
ss2 << (_game->getSavedGame()->getTime()->getYear()-1);
_txtYears->setCellText(0, 0, ss2.str());
}
}
_txtMonths->setCellText(0, iter, tr(months[month]));
++month;
}
// set up the vertical measurement units
for (std::vector<Text *>::iterator iter = _txtScale.begin(); iter != _txtScale.end(); ++iter)
{
(*iter)->setAlign(ALIGN_RIGHT);
}
btnUfoRegionClick(0);
// Set up objects
if (_game->getMod()->getSurface("GRAPH.BDY", false))
{
_game->getMod()->getSurface("GRAPH.BDY")->blit(_bg);
}
else
{
_game->getMod()->getSurface("GRAPHS.SPK")->blit(_bg);
}
_txtTitle->setAlign(ALIGN_CENTER);
_txtFactor->setText(tr("STR_FINANCE_THOUSANDS"));
// Set up buttons
_btnUfoRegion->onMousePress((ActionHandler)&GraphsState::btnUfoRegionClick);
_btnUfoCountry->onMousePress((ActionHandler)&GraphsState::btnUfoCountryClick);
_btnXcomRegion->onMousePress((ActionHandler)&GraphsState::btnXcomRegionClick);
_btnXcomCountry->onMousePress((ActionHandler)&GraphsState::btnXcomCountryClick);
_btnIncome->onMousePress((ActionHandler)&GraphsState::btnIncomeClick);
_btnFinance->onMousePress((ActionHandler)&GraphsState::btnFinanceClick);
_btnGeoscape->onMousePress((ActionHandler)&GraphsState::btnGeoscapeClick);
_btnGeoscape->onKeyboardPress((ActionHandler)&GraphsState::btnGeoscapeClick, Options::keyCancel);
_btnGeoscape->onKeyboardPress((ActionHandler)&GraphsState::btnGeoscapeClick, Options::keyGeoGraphs);
centerAllSurfaces();
}
/**
*
*/
GraphsState::~GraphsState()
{
std::string graphRegionToggles;
std::string graphCountryToggles;
std::string graphFinanceToggles;
for (size_t i = 0; i < _regionToggles.size(); ++i)
{
graphRegionToggles.push_back(_regionToggles[i]->_pushed ? '1' : '0');
delete _regionToggles[i];
}
for (size_t i = 0; i < _countryToggles.size(); ++i)
{
graphCountryToggles.push_back(_countryToggles[i]->_pushed ? '1' : '0');
delete _countryToggles[i];
}
for (size_t i = 0; i < _financeToggles.size(); ++i)
{
graphFinanceToggles.push_back(_financeToggles[i] ? '1' : '0');
}
_game->getSavedGame()->setGraphRegionToggles(graphRegionToggles);
_game->getSavedGame()->setGraphCountryToggles(graphCountryToggles);
_game->getSavedGame()->setGraphFinanceToggles(graphFinanceToggles);
}
/**
* Returns to the previous screen.
* @param action Pointer to an action.
*/
void GraphsState::btnGeoscapeClick(Action *)
{
_game->popState();
}
/**
* Switches to the UFO Region Activity screen.
* @param action Pointer to an action.
*/
void GraphsState::btnUfoRegionClick(Action *)
{
_alien = true;
_income = false;
_country = false;
_finance = false;
resetScreen();
drawLines();
for (std::vector<ToggleTextButton *>::iterator iter = _btnRegions.begin(); iter != _btnRegions.end(); ++iter)
{
(*iter)->setVisible(true);
}
_btnRegionTotal->setVisible(true);
_txtTitle->setBig();
_txtTitle->setText(tr("STR_UFO_ACTIVITY_IN_AREAS"));
}
/**
* Switches to the UFO Country activity screen.
* @param action Pointer to an action.
*/
void GraphsState::btnUfoCountryClick(Action *)
{
_alien = true;
_income = false;
_country = true;
_finance = false;
resetScreen();
drawLines();
for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
{
(*iter)->setVisible(true);
}
_btnCountryTotal->setVisible(true);
_txtTitle->setBig();
_txtTitle->setText(tr("STR_UFO_ACTIVITY_IN_COUNTRIES"));
}
/**
* Switches to the XCom Region activity screen.
* @param action Pointer to an action.
*/
void GraphsState::btnXcomRegionClick(Action *)
{
_alien = false;
_income = false;
_country = false;
_finance = false;
resetScreen();
drawLines();
for (std::vector<ToggleTextButton *>::iterator iter = _btnRegions.begin(); iter != _btnRegions.end(); ++iter)
{
(*iter)->setVisible(true);
}
_btnRegionTotal->setVisible(true);
_txtTitle->setBig();
_txtTitle->setText(tr("STR_XCOM_ACTIVITY_IN_AREAS"));
}
/**
* Switches to the XCom Country activity screen.
* @param action Pointer to an action.
*/
void GraphsState::btnXcomCountryClick(Action *)
{
_alien = false;
_income = false;
_country = true;
_finance = false;
resetScreen();
drawLines();
for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
{
(*iter)->setVisible(true);
}
_btnCountryTotal->setVisible(true);
_txtTitle->setBig();
_txtTitle->setText(tr("STR_XCOM_ACTIVITY_IN_COUNTRIES"));
}
/**
* Switches to the Income screen.
* @param action Pointer to an action.
*/
void GraphsState::btnIncomeClick(Action *)
{
_alien = false;
_income = true;
_country = true;
_finance = false;
resetScreen();
drawLines();
_txtFactor->setVisible(true);
for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
{
(*iter)->setVisible(true);
}
_btnCountryTotal->setVisible(true);
_txtTitle->setBig();
_txtTitle->setText(tr("STR_INCOME"));
}
/**
* Switches to the Finances screen.
* @param action Pointer to an action.
*/
void GraphsState::btnFinanceClick(Action *)
{
_alien = false;
_income = false;
_country = false;
_finance = true;
resetScreen();
drawLines();
for (std::vector<ToggleTextButton *>::iterator iter = _btnFinances.begin(); iter != _btnFinances.end(); ++iter)
{
(*iter)->setVisible(true);
}
_txtTitle->setBig();
_txtTitle->setText(tr("STR_FINANCE"));
}
/**
* Handles a click on a region button.
* @param action Pointer to an action.
*/
void GraphsState::btnRegionListClick(Action * action)
{
size_t number = 0;
ToggleTextButton *button = dynamic_cast<ToggleTextButton*>(action->getSender());
if (button == _btnRegionTotal)
{
number = _regionToggles.size() - 1;
}
else
{
for (size_t i = 0; i < _btnRegions.size(); ++i)
{
if (button == _btnRegions[i])
{
number = i + _butRegionsOffset;
break;
}
}
}
_regionToggles.at(number)->_pushed = button->getPressed();
drawLines();
}
/**
* Handles a click on a country button.
* @param action Pointer to an action.
*/
void GraphsState::btnCountryListClick(Action * action)
{
size_t number = 0;
ToggleTextButton *button = dynamic_cast<ToggleTextButton*>(action->getSender());
if (button == _btnCountryTotal)
{
number = _countryToggles.size() - 1;
}
else
{
for (size_t i = 0; i < _btnCountries.size(); ++i)
{
if (button == _btnCountries[i])
{
number = i + _butCountriesOffset;
break;
}
}
}
_countryToggles.at(number)->_pushed = button->getPressed();
drawLines();
}
/**
* handles a click on a finances button.
* @param action Pointer to an action.
*/
void GraphsState::btnFinanceListClick(Action *action)
{
size_t number = 0;
ToggleTextButton *button = dynamic_cast<ToggleTextButton*>(action->getSender());
for (size_t i = 0; i < _btnFinances.size(); ++i)
{
if (button == _btnFinances[i])
{
number = i;
break;
}
}
_financeLines.at(number)->setVisible(!_financeToggles.at(number));
_financeToggles.at(number) = button->getPressed();
drawLines();
}
/**
* remove all elements from view
*/
void GraphsState::resetScreen()
{
for (std::vector<Surface *>::iterator iter = _alienRegionLines.begin(); iter != _alienRegionLines.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<Surface *>::iterator iter = _alienCountryLines.begin(); iter != _alienCountryLines.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<Surface *>::iterator iter = _xcomRegionLines.begin(); iter != _xcomRegionLines.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<Surface *>::iterator iter = _xcomCountryLines.begin(); iter != _xcomCountryLines.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<Surface *>::iterator iter = _incomeLines.begin(); iter != _incomeLines.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<Surface *>::iterator iter = _financeLines.begin(); iter != _financeLines.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<ToggleTextButton *>::iterator iter = _btnRegions.begin(); iter != _btnRegions.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<ToggleTextButton *>::iterator iter = _btnCountries.begin(); iter != _btnCountries.end(); ++iter)
{
(*iter)->setVisible(false);
}
for (std::vector<ToggleTextButton *>::iterator iter = _btnFinances.begin(); iter != _btnFinances.end(); ++iter)
{
(*iter)->setVisible(false);
}
_btnRegionTotal->setVisible(false);
_btnCountryTotal->setVisible(false);
_txtFactor->setVisible(false);
}
/**
* updates the text on the vertical scale
* @param lowerLimit minimum value
* @param upperLimit maximum value
*/
void GraphsState::updateScale(double lowerLimit, double upperLimit)
{
double increment = ((upperLimit - lowerLimit) / 9);
if (increment < 10)
{
increment = 10;
}
double text = lowerLimit;
for (int i = 0; i < 10; ++i)
{
_txtScale.at(i)->setText(Unicode::formatNumber(static_cast<int>(text)));
text += increment;
}
}
/**
* instead of having all our line drawing in one giant ridiculous routine, just use the one we need.
*/
void GraphsState::drawLines()
{
if (!_country && !_finance)
{
drawRegionLines();
}
else if (!_finance)
{
drawCountryLines();
}
else
{
drawFinanceLines();
}
}
/**
* Sets up the screens and draws the lines for country buttons
* to toggle on and off
*/
void GraphsState::drawCountryLines()
{
//calculate the totals, and set up our upward maximum
int upperLimit = 0;
int lowerLimit = 0;
int totals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
for (size_t entry = 0; entry != _game->getSavedGame()->getFundsList().size(); ++entry)
{
int total = 0;
if (_alien)
{
for (size_t iter = 0; iter != _game->getSavedGame()->getCountries()->size(); ++iter)
{
total += _game->getSavedGame()->getCountries()->at(iter)->getActivityAlien().at(entry);
if (_game->getSavedGame()->getCountries()->at(iter)->getActivityAlien().at(entry) > upperLimit && _countryToggles.at(iter)->_pushed)
{
upperLimit = _game->getSavedGame()->getCountries()->at(iter)->getActivityAlien().at(entry);
}
}
}
else if (_income)
{
for (size_t iter = 0; iter != _game->getSavedGame()->getCountries()->size(); ++iter)
{
total += _game->getSavedGame()->getCountries()->at(iter)->getFunding().at(entry) / 1000;
if (_game->getSavedGame()->getCountries()->at(iter)->getFunding().at(entry) / 1000 > upperLimit && _countryToggles.at(iter)->_pushed)
{
upperLimit = _game->getSavedGame()->getCountries()->at(iter)->getFunding().at(entry) / 1000;
}
}
}
else
{
for (size_t iter = 0; iter != _game->getSavedGame()->getCountries()->size(); ++iter)
{
total += _game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry);
if (_game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry) > upperLimit && _countryToggles.at(iter)->_pushed)
{
upperLimit = _game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry);
}
if (_game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry) < lowerLimit && _countryToggles.at(iter)->_pushed)
{
lowerLimit = _game->getSavedGame()->getCountries()->at(iter)->getActivityXcom().at(entry);
}
}
}
if (_countryToggles.back()->_pushed && total > upperLimit)
upperLimit = total;
}
//adjust the scale to fit the upward maximum
double range = upperLimit - lowerLimit;
double low = lowerLimit;
int grids = 9; // cells in grid
int check = _income ? 50 : 10;
while (range > check * grids)
{
check *= 2;
}
lowerLimit = 0;
upperLimit = check * grids;
if (low < 0)
{
while (low < lowerLimit)
{
lowerLimit -= check;
upperLimit -= check;
}
}
range = upperLimit - lowerLimit;
double units = range / 126;
// draw country lines
for (size_t entry = 0; entry != _game->getSavedGame()->getCountries()->size(); ++entry)
{
Country *country = _game->getSavedGame()->getCountries()->at(entry);
_alienCountryLines.at(entry)->clear();
_xcomCountryLines.at(entry)->clear();
_incomeLines.at(entry)->clear();
std::vector<Sint16> newLineVector;
int reduction = 0;
for (size_t iter = 0; iter != 12; ++iter)
{
int x = 312 - (iter*17);
int y = 175 - (-lowerLimit / units);
if (_alien)
{
if (iter < country->getActivityAlien().size())
{
reduction = country->getActivityAlien().at(country->getActivityAlien().size()-(1+iter)) / units;
y -= reduction;
totals[iter] += country->getActivityAlien().at(country->getActivityAlien().size()-(1+iter));
}
}
else if (_income)
{
if (iter < country->getFunding().size())
{
reduction = (country->getFunding().at(country->getFunding().size()-(1+iter)) / 1000) / units;
y -= reduction;
totals[iter] += country->getFunding().at(country->getFunding().size()-(1+iter)) / 1000;
}
}
else
{
if (iter < country->getActivityXcom().size())
{
reduction = country->getActivityXcom().at(country->getActivityXcom().size()-(1+iter)) / units;
y -= reduction;
totals[iter] += country->getActivityXcom().at(country->getActivityXcom().size()-(1+iter));
}
}
if (y >=175)
y = 175;
newLineVector.push_back(y);
if (newLineVector.size() > 1 && _alien)
_alienCountryLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), _countryToggles.at(entry)->_color+4);
else if (newLineVector.size() > 1 && _income)
_incomeLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), _countryToggles.at(entry)->_color+4);
else if (newLineVector.size() > 1)
_xcomCountryLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), _countryToggles.at(entry)->_color+4);
}
if (_alien)
_alienCountryLines.at(entry)->setVisible(_countryToggles.at(entry)->_pushed);
else if (_income)
_incomeLines.at(entry)->setVisible(_countryToggles.at(entry)->_pushed);
else
_xcomCountryLines.at(entry)->setVisible(_countryToggles.at(entry)->_pushed);
}
if (_alien)
_alienCountryLines.back()->clear();
else if (_income)
_incomeLines.back()->clear();
else
_xcomCountryLines.back()->clear();
// set up the "total" line
std::vector<Sint16> newLineVector;
Uint8 color = _game->getMod()->getInterface("graphs")->getElement("countryTotal")->color2;
for (int iter = 0; iter != 12; ++iter)
{
int x = 312 - (iter*17);
int y = 175 - (-lowerLimit / units);
if (totals[iter] > 0)
{
int reduction = totals[iter] / units;
y -= reduction;
}
newLineVector.push_back(y);
if (newLineVector.size() > 1)
{
if (_alien)
_alienCountryLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), color);
else if (_income)
_incomeLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), color);
else
_xcomCountryLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), color);
}
}
if (_alien)
_alienCountryLines.back()->setVisible(_countryToggles.back()->_pushed);
else if (_income)
_incomeLines.back()->setVisible(_countryToggles.back()->_pushed);
else
_xcomCountryLines.back()->setVisible(_countryToggles.back()->_pushed);
updateScale(lowerLimit, upperLimit);
_txtFactor->setVisible(_income);
}
/**
* Sets up the screens and draws the lines for region buttons
* to toggle on and off
*/
void GraphsState::drawRegionLines()
{
//calculate the totals, and set up our upward maximum
int upperLimit = 0;
int lowerLimit = 0;
int totals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
for (size_t entry = 0; entry != _game->getSavedGame()->getFundsList().size(); ++entry)
{
int total = 0;
if (_alien)
{
for (size_t iter = 0; iter != _game->getSavedGame()->getRegions()->size(); ++iter)
{
total += _game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry);
if (_game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry) > upperLimit && _regionToggles.at(iter)->_pushed)
{
upperLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry);
}
if (_game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry) < lowerLimit && _regionToggles.at(iter)->_pushed)
{
lowerLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityAlien().at(entry);
}
}
}
else
{
for (size_t iter = 0; iter != _game->getSavedGame()->getRegions()->size(); ++iter)
{
total += _game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry);
if (_game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry) > upperLimit && _regionToggles.at(iter)->_pushed)
{
upperLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry);
}
if (_game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry) < lowerLimit && _regionToggles.at(iter)->_pushed)
{
lowerLimit = _game->getSavedGame()->getRegions()->at(iter)->getActivityXcom().at(entry);
}
}
}
if (_regionToggles.back()->_pushed && total > upperLimit)
upperLimit = total;
}
//adjust the scale to fit the upward maximum
double range = upperLimit - lowerLimit;
double low = lowerLimit;
int check = 10;
int grids = 9; // cells in grid
while (range > check * grids)
{
check *= 2;
}
lowerLimit = 0;
upperLimit = check * grids;
if (low < 0)
{
while (low < lowerLimit)
{
lowerLimit -= check;
upperLimit -= check;
}
}
range = upperLimit - lowerLimit;
double units = range / 126;
// draw region lines
for (size_t entry = 0; entry != _game->getSavedGame()->getRegions()->size(); ++entry)
{
Region *region = _game->getSavedGame()->getRegions()->at(entry);
_alienRegionLines.at(entry)->clear();
_xcomRegionLines.at(entry)->clear();
std::vector<Sint16> newLineVector;
int reduction = 0;
for (size_t iter = 0; iter != 12; ++iter)
{
int x = 312 - (iter*17);
int y = 175 - (-lowerLimit / units);
if (_alien)
{
if (iter < region->getActivityAlien().size())
{
reduction = region->getActivityAlien().at(region->getActivityAlien().size()-(1+iter)) / units;
y -= reduction;
totals[iter] += region->getActivityAlien().at(region->getActivityAlien().size()-(1+iter));
}
}
else
{
if (iter < region->getActivityXcom().size())
{
reduction = region->getActivityXcom().at(region->getActivityXcom().size()-(1+iter)) / units;
y -= reduction;
totals[iter] += region->getActivityXcom().at(region->getActivityXcom().size()-(1+iter));
}
}
if (y >=175)
y = 175;
newLineVector.push_back(y);
if (newLineVector.size() > 1 && _alien)
_alienRegionLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), _regionToggles.at(entry)->_color+4);
else if (newLineVector.size() > 1)
_xcomRegionLines.at(entry)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), _regionToggles.at(entry)->_color+4);
}
if (_alien)
_alienRegionLines.at(entry)->setVisible(_regionToggles.at(entry)->_pushed);
else
_xcomRegionLines.at(entry)->setVisible(_regionToggles.at(entry)->_pushed);
}
// set up the "total" line
if (_alien)
_alienRegionLines.back()->clear();
else
_xcomRegionLines.back()->clear();
Uint8 color = _game->getMod()->getInterface("graphs")->getElement("regionTotal")->color2;
std::vector<Sint16> newLineVector;
for (int iter = 0; iter != 12; ++iter)
{
int x = 312 - (iter*17);
int y = 175 - (-lowerLimit / units);
if (totals[iter] > 0)
{
int reduction = totals[iter] / units;
y -= reduction;
}
newLineVector.push_back(y);
if (newLineVector.size() > 1)
{
if (_alien)
_alienRegionLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), color);
else
_xcomRegionLines.back()->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), color);
}
}
if (_alien)
_alienRegionLines.back()->setVisible(_regionToggles.back()->_pushed);
else
_xcomRegionLines.back()->setVisible(_regionToggles.back()->_pushed);
updateScale(lowerLimit, upperLimit);
_txtFactor->setVisible(false);
}
/**
* Sets up the screens and draws the lines for the finance buttons
* to toggle on and off
*/
void GraphsState::drawFinanceLines()
{
//set up arrays
int upperLimit = 0;
int lowerLimit = 0;
int64_t incomeTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int64_t balanceTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int64_t expendTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int64_t maintTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int scoreTotals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
maintTotals[0] = _game->getSavedGame()->getBaseMaintenance() / 1000;
// start filling those arrays with score values
// determine which is the highest one being displayed, so we can adjust the scale
for (size_t entry = 0; entry != _game->getSavedGame()->getFundsList().size(); ++entry)
{
size_t invertedEntry = _game->getSavedGame()->getFundsList().size() - (1 + entry);
maintTotals[entry] += _game->getSavedGame()->getMaintenances().at(invertedEntry) / 1000;
balanceTotals[entry] = _game->getSavedGame()->getFundsList().at(invertedEntry) / 1000;
scoreTotals[entry] = _game->getSavedGame()->getResearchScores().at(invertedEntry);
for (std::vector<Region*>::iterator iter = _game->getSavedGame()->getRegions()->begin(); iter != _game->getSavedGame()->getRegions()->end(); ++iter)
{
scoreTotals[entry] += (*iter)->getActivityXcom().at(invertedEntry) - (*iter)->getActivityAlien().at(invertedEntry);
}
if (_financeToggles.at(2))
{
if (maintTotals[entry] > upperLimit)
{
upperLimit = maintTotals[entry];
}
if (maintTotals[entry] < lowerLimit)
{
lowerLimit = maintTotals[entry];
}
}
if (_financeToggles.at(3))
{
if (balanceTotals[entry] > upperLimit)
{
upperLimit = balanceTotals[entry];
}
if (balanceTotals[entry] < lowerLimit)
{
lowerLimit = balanceTotals[entry];
}
}
if (_financeToggles.at(4))
{
if (scoreTotals[entry] > upperLimit)
{
upperLimit = scoreTotals[entry];
}
if (scoreTotals[entry] < lowerLimit)
{
lowerLimit = scoreTotals[entry];
}
}
}
for (size_t entry = 0; entry != _game->getSavedGame()->getExpenditures().size(); ++entry)
{
expendTotals[entry] = _game->getSavedGame()->getExpenditures().at(_game->getSavedGame()->getExpenditures().size() - (entry + 1)) / 1000;
incomeTotals[entry] = _game->getSavedGame()->getIncomes().at(_game->getSavedGame()->getIncomes().size() - (entry + 1)) / 1000;
if (_financeToggles.at(0) && incomeTotals[entry] > upperLimit)
{
upperLimit = incomeTotals[entry];
}
if (_financeToggles.at(1) && expendTotals[entry] > upperLimit)
{
upperLimit = expendTotals[entry];
}
}
double range = upperLimit - lowerLimit;
double low = lowerLimit;
int check = 250;
int grids = 9; // cells in grid
while (range > check * grids)
{
check *= 2;
}
lowerLimit = 0;
upperLimit = check * grids;
if (low < 0)
{
while (low < lowerLimit)
{
lowerLimit -= check;
upperLimit -= check;
}
}
//toggle screens
for (int button = 0; button != 5; ++button)
{
_financeLines.at(button)->setVisible(_financeToggles.at(button));
_financeLines.at(button)->clear();
}
range = upperLimit - lowerLimit;
//figure out how many units to the pixel, then plot the points for the graph and connect the dots.
double units = range / 126;
for (int button = 0; button != 5; ++button)
{
std::vector<Sint16> newLineVector;
for (int iter = 0; iter != 12; ++iter)
{
int x = 312 - (iter*17);
int y = 175 - (-lowerLimit / units);
int reduction = 0;
switch(button)
{
case 0:
reduction = incomeTotals[iter] / units;
break;
case 1:
reduction = expendTotals[iter] / units;
break;
case 2:
reduction = maintTotals[iter] / units;
break;
case 3:
reduction = balanceTotals[iter] / units;
break;
case 4:
reduction = scoreTotals[iter] / units;
break;
}
y -= reduction;
newLineVector.push_back(y);
int offset = button % 2 ? 8 : 0;
if (newLineVector.size() > 1)
_financeLines.at(button)->drawLine(x, y, x+17, newLineVector.at(newLineVector.size()-2), Palette::blockOffset((button/2)+1)+offset);
}
}
updateScale(lowerLimit, upperLimit);
_txtFactor->setVisible(true);
}
/**
* 'Shift' the buttons to display only GRAPH_MAX_BUTTONS - reset their state from toggles
*/
void GraphsState::shiftButtons(Action *action)
{
// only if active 'screen' is other than finance
if (_finance)
return;
// select the data's we'll processing - regions or countries
if (_country)
{
// too few countries? - return
if (_countryToggles.size() <= GRAPH_MAX_BUTTONS)
return;
else if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
scrollButtons(_countryToggles, _btnCountries, _butCountriesOffset, -1);
else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
scrollButtons(_countryToggles, _btnCountries, _butCountriesOffset, 1);
}
else
{
// too few regions? - return
if (_regionToggles.size() <= GRAPH_MAX_BUTTONS)
return;
else if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
scrollButtons(_regionToggles, _btnRegions, _butRegionsOffset, -1);
else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
scrollButtons(_regionToggles, _btnRegions, _butRegionsOffset, 1);
}
}
void GraphsState::scrollButtons(std::vector<GraphButInfo *> &toggles, std::vector<ToggleTextButton *> &buttons, size_t &offset, int step)
{
if ( int(step + (int)offset) < 0 || offset + step + GRAPH_MAX_BUTTONS >= toggles.size())
return;
// set the next offset - cheaper to do it from starters
offset += step;
size_t i = 0;
std::vector<ToggleTextButton *>::iterator iterb = buttons.begin();
for (std::vector<GraphButInfo *>::iterator itert = toggles.begin() + offset; itert != toggles.end() && i < GRAPH_MAX_BUTTONS; ++itert, ++iterb, ++i)
{
updateButton(*itert, *iterb);
}
}
void GraphsState::updateButton(GraphButInfo *from,ToggleTextButton *to)
{
to->setText(from->_name);
to->setInvertColor(from->_color);
to->setPressed(from->_pushed);
}
}
↑ V522 There might be dereferencing of a potential null pointer 'button'.
↑ V522 There might be dereferencing of a potential null pointer 'button'.
↑ V522 There might be dereferencing of a potential null pointer 'button'.
↑ V1026 The 'total' variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.
↑ V1026 The 'total' variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.
↑ V1026 The 'total' variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.
↑ V1026 The 'total' variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.
↑ V1026 The 'total' variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.