/* Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière for any question or comment contact us at or Copyright (C) 2006 Bradley Arsenault This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "EndGameScreen.h" #include #include #include #include #include #include #include #include #include #include #include "GlobalContainer.h" EndGameStat::EndGameStat(int x, int y, int w, int h, Uint32 hAlign, Uint32 vAlign, Game *game) { this->x=x; this->y=y; this->w=w; this->h=h; this->hAlignFlag=hAlign; this->vAlignFlag=vAlign; this->game = game; for(int x=0; x<32; ++x) isTeamEnabled[x]=true; this->type = EndOfGameStat::TYPE_UNITS; mouse_x = -1; mouse_y = -1; } void EndGameStat::setStatType(EndOfGameStat::Type type) { this->type=type; } void EndGameStat::setEnabledState(int teamNum, bool isEnabled) { isTeamEnabled[teamNum]=isEnabled; } void EndGameStat::paint(void) { int x, y, w, h; getScreenPos(&x, &y, &w, &h); assert(parent); assert(parent->getSurface()); // draw background parent->getSurface()->drawRect(x, y, w, h, Style::style->frameColor); if(game->teams[0]->stats.endOfGameStats.size()==0) return; // find maximum int team, maxValue = 0; unsigned int pos=0; for (team=0; team < game->mapHeader.getNumberOfTeams(); team++) for (pos=0; posteams[team]->stats.endOfGameStats.size(); pos++) maxValue = std::max(maxValue, game->teams[team]->stats.endOfGameStats[pos].value[type]); ///You can't draw anything if the game ended so quickly that there wheren't two recorded values to draw a line between if(game->teams[0]->stats.endOfGameStats.size() >= 2) { //Calculate the maximum width of the numbers so they can be lined up int num=10; maxValue+=num-(maxValue%num); std::stringstream maxstr; maxstr<littleFont->getStringWidth(str.str().c_str()); max_width=std::max(width, max_width); } //Draw horizontal lines to given the scale of the graphs values. for(int n=0; ngetSurface()->drawHorzLine(x+w-5, y+pos, 10, 255, 255, 255); std::stringstream str; str<littleFont->getStringHeight(str.str().c_str()); parent->getSurface()->drawString(x+w-max_width-8, y+pos-height/2, globalContainer->littleFont, str.str().c_str()); } ///Draw vertical lines to give the timescale double time_line_seperate=double(w)/double(15); int time_period=(game->teams[0]->stats.endOfGameStats.size()*512/250)*10; double time_value_seperate=double(time_period)/double(15); for(int n=1; n<16; ++n) { if(n!=16) parent->getSurface()->drawVertLine(int(double(x)+time_line_seperate*double(n)+0.5), y+h-5, 10, 255, 255, 255); std::stringstream str; int min=int(double(n)*time_value_seperate+0.5)/60; int sec=int(double(n)*time_value_seperate+0.5)%60; str<littleFont->getStringWidth(str.str().c_str()); parent->getSurface()->drawString(int(double(x)+time_line_seperate*double(n)+0.5)-width/2, y+h-30, globalContainer->littleFont, str.str().c_str()); } int closest_position = 1681; int circle_position_value=-1; int circle_position_x=-1; int circle_position_y=-1; // draw curve if (maxValue) { for (team=0; team < game->mapHeader.getNumberOfTeams(); team++) { if(!isTeamEnabled[team]) continue; Uint8 r = game->teams[team]->colorR; Uint8 g = game->teams[team]->colorG; Uint8 b = game->teams[team]->colorB; int previous_y = h - int(double(h) * getValue(0, team, type) / double(maxValue)); for(int px=0; px<(w-2); ++px) { double value = getValue(double(px) / double(w-2), team, type); int ny = h - int(double(h) * value / double(maxValue)); parent->getSurface()->drawLine(x + px + 1, y + previous_y, x + px, y + ny, Color(r, g, b)); previous_y = ny; int dist = (mouse_y-ny)*(mouse_y-ny) + (mouse_x-px-1)*(mouse_x-px-1); if(dist < closest_position) { circle_position_value = int(std::floor(value+0.5)); circle_position_x = x + px; circle_position_y = y + ny; closest_position = dist; } } } } if(circle_position_x!=-1) { parent->getSurface()->drawCircle(circle_position_x, circle_position_y, 10, Color::white); std::stringstream str; str<getSurface()->drawString(circle_position_x+10, circle_position_y+10, globalContainer->littleFont, str.str()); } } } double EndGameStat::getValue(double position, int team, int type) { int s = game->teams[team]->stats.endOfGameStats.size()-1; int lower = int(position * float(s)); int upper = lower+1; double mu = (position * float(s)) - lower; //int y0 = game->teams[team]->stats.endOfGameStats[std::max(lower-1, 0)].value[type]; int y1 = game->teams[team]->stats.endOfGameStats[lower].value[type]; int y2 = game->teams[team]->stats.endOfGameStats[upper].value[type]; //int y3 = game->teams[team]->stats.endOfGameStats[std::min(upper+1, s)].value[type]; //Linear interpolation return (1-mu) * y1 + mu * y2; /* //Cubic interpolation double mu2 = mu * mu; double a0 = y3 - y2 - y0 + y1; double a1 = y0 - y1 - a0; double a2 = y2 - y0; double a3 = y1; return a0*mu*mu2+a1*mu2+a2*mu+a3; */ /* //Cosine interpolation double mu2 = (1-std::cos(mu*3.141592653))/2; return(y1*(1-mu2)+y2*mu2); */ } void EndGameStat::onSDLMouseMotion(SDL_Event* event) { int x, y, w, h; getScreenPos(&x, &y, &w, &h); if(event->motion.x > x && event->motion.x < x+w && event->motion.y > y && event->motion.y < y+h) { mouse_x=event->motion.x-x+21; mouse_y=event->motion.y-y; } else { mouse_x=-1; mouse_y=-1; } } //! This function is used to sort the player array struct MoreScore : public std::binary_function { EndOfGameStat::Type type; bool operator()(const TeamEntry& t1, const TeamEntry& t2) { return t1.endVal[type] > t2.endVal[type]; } }; EndGameScreen::EndGameScreen(GameGUI *gui) { // title & graph std::string titleText; if (gui->game.totalPrestigeReached) { Team *t=gui->game.getTeamWithMostPrestige(); assert(t); if (t==gui->getLocalTeam()) { titleText=Toolkit::getStringTable()->getString("[Won : you have the most prestige]"); } else { FormatableString strText; if ((t->allies) & (gui->getLocalTeam()->me)) strText = Toolkit::getStringTable()->getString("[Won : your ally %0 has the most prestige]"); else strText = Toolkit::getStringTable()->getString("[Lost : %0 has more prestige than you]"); std::string playerText = t->getFirstPlayerName(); strText.arg(playerText); titleText = strText; } } else if (!gui->getLocalTeam()->isAlive) { titleText=Toolkit::getStringTable()->getString("[Lost : your colony is dead]"); } else if (!gui->game.isGameEnded) { titleText=Toolkit::getStringTable()->getString("[The game has not been finished]"); } else { titleText=Toolkit::getStringTable()->getString("[Won : you defeated your opponents]"); } addWidget(new Text(0, 18, ALIGN_FILL, ALIGN_LEFT, "menu", titleText.c_str())); statWidget=new EndGameStat(20, 80, 180, 150, ALIGN_FILL, ALIGN_FILL, &(gui->game)); addWidget(statWidget); graphLabel=new Text(25, 85, ALIGN_LEFT, ALIGN_TOP, "menu", Toolkit::getStringTable()->getString("[Units]")); addWidget(graphLabel); // add buttons addWidget(new TextButton(90, 90, 80, 20, ALIGN_SCREEN_CENTERED, ALIGN_BOTTOM, "standard", Toolkit::getStringTable()->getString("[Units]"), 0, '1')); addWidget(new TextButton(190, 90, 80, 20, ALIGN_SCREEN_CENTERED, ALIGN_BOTTOM, "standard", Toolkit::getStringTable()->getString("[Buildings]"), 1, '2')); addWidget(new TextButton(290, 90, 80, 20, ALIGN_SCREEN_CENTERED, ALIGN_BOTTOM, "standard", Toolkit::getStringTable()->getString("[Prestige]"), 2, '3')); addWidget(new TextButton(90, 65, 80, 20, ALIGN_SCREEN_CENTERED, ALIGN_BOTTOM, "standard", Toolkit::getStringTable()->getString("[hp]"), 3, '4')); addWidget(new TextButton(190, 65, 80, 20, ALIGN_SCREEN_CENTERED, ALIGN_BOTTOM, "standard", Toolkit::getStringTable()->getString("[Attack]"), 4, '5')); addWidget(new TextButton(290, 65, 80, 20, ALIGN_SCREEN_CENTERED, ALIGN_BOTTOM, "standard", Toolkit::getStringTable()->getString("[Defense]"), 5, '6')); addWidget(new TextButton(0, 5, 300, 40, ALIGN_CENTERED, ALIGN_BOTTOM, "menu", Toolkit::getStringTable()->getString("[ok]"), 38, 13)); // add players name Text *text; int inc = (gui->game.mapHeader.getNumberOfTeams() < 16) ? 20 : 10; // set teams entries for later sort for (int i=0; igame.mapHeader.getNumberOfTeams(); i++) { Team *t=gui->game.teams[i]; int endIndex=t->stats.endOfGameStats.size()-1; struct TeamEntry entry; entry.name=t->getFirstPlayerName(); entry.teamNum=i; entry.r=t->colorR; entry.g=t->colorG; entry.b=t->colorB; entry.a=0; for (int j=0; jstats.endOfGameStats[endIndex].value[(EndOfGameStat::Type)j]; } teams.push_back(entry); } // sort MoreScore moreScore; moreScore.type=EndOfGameStat::TYPE_UNITS; std::sort(teams.begin(), teams.end(), moreScore); // add widgets for (unsigned i=0; isetStyle(Font::Style(Font::STYLE_NORMAL, teams[i].r, teams[i].g, teams[i].b)); names.push_back(text); addWidget(text); } } void EndGameScreen::onAction(Widget *source, Action action, int par1, int par2) { if ((action==BUTTON_RELEASED) || (action==BUTTON_SHORTCUT)) { ///This is a change in the graph type if (par1<6) { EndOfGameStat::Type type = (EndOfGameStat::Type)par1; statWidget->setStatType(type); sortAndSet(type); if(type==EndOfGameStat::TYPE_UNITS) graphLabel->setText(Toolkit::getStringTable()->getString("[Units]")); else if(type==EndOfGameStat::TYPE_BUILDINGS) graphLabel->setText(Toolkit::getStringTable()->getString("[Buildings]")); else if(type==EndOfGameStat::TYPE_PRESTIGE) graphLabel->setText(Toolkit::getStringTable()->getString("[Prestige]")); else if(type==EndOfGameStat::TYPE_HP) graphLabel->setText(Toolkit::getStringTable()->getString("[hp]")); else if(type==EndOfGameStat::TYPE_ATTACK) graphLabel->setText(Toolkit::getStringTable()->getString("[Attack]")); else if(type==EndOfGameStat::TYPE_DEFENSE) graphLabel->setText(Toolkit::getStringTable()->getString("[Defense]")); // Resort the names on the side of the graph based on their respective scores MoreScore moreScore; moreScore.type=type; std::sort(teams.begin(), teams.end(), moreScore); int prev_num=1; for (unsigned i=0; i0 && teams[i].endVal[type] == teams[i-1].endVal[type]) { str<setText(str.str().c_str()); names[i]->setStyle(Font::Style(Font::STYLE_NORMAL, teams[i].r, teams[i].g, teams[i].b)); team_enabled_buttons[i]->returnCode=6+i; } } ///One of the buttons beside the team names where selected else if(par1 >= 6 && par1 < static_cast(6+teams.size())) { int n=par1-6; statWidget->setEnabledState(teams[n].teamNum, team_enabled_buttons[n]->getState()); } else endExecute(par1); } } void EndGameScreen::sortAndSet(EndOfGameStat::Type type) { MoreScore moreScore; moreScore.type=type; std::sort(teams.begin(), teams.end(), moreScore); for (unsigned i=0; isetStyle(Font::Style(Font::STYLE_NORMAL, teams[i].r, teams[i].g, teams[i].b)); names[i]->setText(teams[i].name.c_str()); } }