1 /*
2  * This file is part of the Colobot: Gold Edition source code
3  * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4  * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5  *
6  * This program 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  * This program 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.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see http://gnu.org/licenses
18  */
19 
20 #include "level/scoreboard.h"
21 
22 #include "common/restext.h"
23 #include "common/stringutils.h"
24 
25 #include "level/robotmain.h"
26 
27 #include "level/parser/parserline.h"
28 
29 #include "object/object.h"
30 
31 #include "ui/displaytext.h"
32 
33 #include <boost/lexical_cast.hpp>
34 
Read(CLevelParserLine * line)35 void CScoreboard::CScoreboardRule::Read(CLevelParserLine* line)
36 {
37     this->score = line->GetParam("score")->AsInt();
38 }
39 
Read(CLevelParserLine * line)40 void CScoreboard::CScoreboardKillRule::Read(CLevelParserLine* line)
41 {
42     CScoreboardRule::Read(line);
43     CObjectCondition::Read(line);
44     this->friendlyFire = line->GetParam("friendlyFire")->AsBool(false);
45 }
46 
Read(CLevelParserLine * line)47 void CScoreboard::CScoreboardObjectRule::Read(CLevelParserLine* line)
48 {
49     CScoreboardRule::Read(line);
50     CObjectCondition::Read(line);
51     this->winTeam = line->GetParam("winTeam")->AsInt();
52 }
53 
Read(CLevelParserLine * line)54 void CScoreboard::CScoreboardEndTakeRule::Read(CLevelParserLine* line)
55 {
56     CScoreboardRule::Read(line);
57     this->team = line->GetParam("team")->AsInt(0);
58     this->order = line->GetParam("order")->AsInt(0);
59 }
60 
AddKillRule(std::unique_ptr<CScoreboardKillRule> rule)61 void CScoreboard::AddKillRule(std::unique_ptr<CScoreboardKillRule> rule)
62 {
63     m_rulesKill.push_back(std::move(rule));
64 }
65 
AddObjectRule(std::unique_ptr<CScoreboard::CScoreboardObjectRule> rule)66 void CScoreboard::AddObjectRule(std::unique_ptr<CScoreboard::CScoreboardObjectRule> rule)
67 {
68     m_rulesObject.push_back(std::move(rule));
69 }
70 
AddEndTakeRule(std::unique_ptr<CScoreboardEndTakeRule> rule)71 void CScoreboard::AddEndTakeRule(std::unique_ptr<CScoreboardEndTakeRule> rule)
72 {
73     m_rulesEndTake.push_back(std::move(rule));
74 }
75 
ProcessKill(CObject * target,CObject * killer)76 void CScoreboard::ProcessKill(CObject* target, CObject* killer)
77 {
78     if (killer == nullptr) return;
79     if (killer->GetTeam() == 0) return;
80     for (auto& rule : m_rulesKill)
81     {
82         if ((rule->team == killer->GetTeam() || rule->team == 0) &&
83             killer->GetTeam() != 0 &&
84             rule->CheckForObject(target))
85         {
86             if (killer->GetTeam() == target->GetTeam() && !rule->friendlyFire)
87                 continue;
88             AddPoints(killer->GetTeam(), rule->score);
89         }
90     }
91 }
92 
UpdateObjectCount()93 void CScoreboard::UpdateObjectCount()
94 {
95     for (auto& rule : m_rulesObject)
96     {
97         assert(rule->winTeam != 0);
98         int count = rule->CountObjects();
99         int countDiff = count - rule->lastCount;
100         if (countDiff != 0)
101         {
102             rule->lastCount = count;
103             AddPoints(rule->winTeam, rule->score * countDiff);
104         }
105     }
106 }
107 
ProcessEndTake(int team)108 void CScoreboard::ProcessEndTake(int team)
109 {
110     if (team == 0) return;
111     m_finishCounter++;
112     for (auto& rule : m_rulesEndTake)
113     {
114         if ((rule->team == team || rule->team == 0) &&
115             (rule->order == m_finishCounter || rule->order == 0))
116         {
117             AddPoints(team, rule->score);
118         }
119     }
120 }
121 
AddPoints(int team,int points)122 void CScoreboard::AddPoints(int team, int points)
123 {
124     GetLogger()->Info("Team %d earned %d points\n", team, points);
125 
126     CRobotMain* main = CRobotMain::GetInstancePointer();
127     std::string text;
128     GetResource(RES_ERR, INFO_TEAM_SCORE, text);
129     text = StrUtils::Format(text.c_str(), main->GetTeamName(team).c_str(), points);
130     main->GetDisplayText()->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_WARNING);
131 
132     m_score[team].points += points;
133     m_score[team].time = main->GetGameTime();
134 }
135 
GetScore(int team)136 CScoreboard::Score CScoreboard::GetScore(int team)
137 {
138     return m_score[team];
139 }
140 
SetScore(int team,int points)141 void CScoreboard::SetScore(int team, int points)
142 {
143     m_score[team].points = points;
144 }
145 
GetSortType()146 CScoreboard::SortType CScoreboard::GetSortType()
147 {
148     return m_sortType;
149 }
150 
SetSortType(SortType type)151 void CScoreboard::SetSortType(SortType type)
152 {
153     m_sortType = type;
154 }
155 
GetSortedScores()156 std::vector<std::pair<int, CScoreboard::Score>> CScoreboard::GetSortedScores()
157 {
158     CRobotMain* main = CRobotMain::GetInstancePointer();
159     std::set<int> teams = main->GetAllTeams();
160     std::vector<std::pair<int, Score>> sortedTeams(teams.size());
161     std::transform(teams.begin(), teams.end(), sortedTeams.begin(), [&](int team)
162     {
163         return *m_score.find(team);
164     });
165     if (m_sortType == SortType::SORT_POINTS)
166     {
167         std::sort(sortedTeams.begin(), sortedTeams.end(), [&](std::pair<int, Score> teamA, std::pair<int, Score> teamB)
168         {
169             if (teamA.second.points > teamB.second.points) return true; // Team A have more points than B?
170             if (teamA.second.points < teamB.second.points) return false; // Team A have less points than B?
171 
172             return teamA.second.time < teamB.second.time; // Team A scored slower than B?
173         });
174     }
175     return sortedTeams;
176 }
177