1 /*
2 ===========================================================================
3 blockattack - Block Attack - Rise of the Blocks
4 Copyright (C) 2005-2012 Poul Sander
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 2 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.  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 this program.  If not, see http://www.gnu.org/licenses/
18 
19 Source information and contacts persons can be found at
20 https://blockattack.net
21 ===========================================================================
22 */
23 
24 #include "highscore.h"
25 #include "os.hpp"
26 #include "cereal/cereal.hpp"
27 #include "cereal/types/vector.hpp"
28 #include "cereal/archives/json.hpp"
29 #include "sago/SagoMisc.hpp"
30 #include <algorithm>
31 #include "common.h"
32 
33 namespace cereal {
34 
35 template<class Archive>
save(Archive & archive,record const & m)36 void save(Archive& archive, record const& m) {
37 	archive( cereal::make_nvp("Name", m.name), cereal::make_nvp("Score", m.score) );
38 }
39 
40 template<class Archive>
load(Archive & archive,record & m)41 void load(Archive& archive, record& m) {
42 	archive( cereal::make_nvp("Name", m.name), cereal::make_nvp("Score", m.score) );
43 }
44 
45 }
46 
47 /*
48  This sorts in reverse order. So the highest will be first
49  */
record_sorter(const record & i,const record & j)50 bool record_sorter (const record& i,const record& j) {
51 	return (i.score > j.score);
52 }
53 
Highscore(const std::string & type,double speed)54 Highscore::Highscore(const std::string& type, double speed) : filename(type+".json.dat"), type(type), speed(speed) {
55 	if (speed < 0.4) {
56 		std::string old_locale = setlocale (LC_NUMERIC, nullptr);
57 		setlocale (LC_NUMERIC, "C");
58 		//Use special filenames for higher speeds (higher speed = lower number)
59 		filename = SPrintStringF("%s_%.4f.json.dat", type.c_str(), speed);
60 		setlocale(LC_NUMERIC, old_locale.c_str());
61 	}
62 	std::string readFileContent = sago::GetFileContent(filename.c_str());
63 	if (readFileContent.length() > 0) {
64 		try {
65 			std::stringstream ss(readFileContent);
66 			{
67 				cereal::JSONInputArchive archive(ss);
68 				archive(cereal::make_nvp("highscore", table));
69 			}
70 		}
71 		catch (cereal::Exception& e) {
72 			std::cerr << "Failed to read highscore " << filename << " due to formatting errors. Resetting the file. Reason: " <<
73 			          e.what() << "\n";
74 			table.clear();
75 		}
76 	}
77 	if (table.size() < top) {
78 		for (int i = 0; i<top; i++) {
79 			record r;
80 			r.name = "Poul Sander";
81 			r.score = 2000 - i*100;
82 			table.push_back(r);
83 		}
84 	}
85 	std::stable_sort(table.begin(), table.end(), record_sorter);
86 	table.resize(top);
87 	writeFile();
88 }
89 
90 
writeFile()91 void Highscore::writeFile() {
92 	std::stringstream ss;
93 	{
94 		cereal::JSONOutputArchive archive(ss);
95 		archive(cereal::make_nvp("highscore", table));
96 	}
97 	sago::WriteFileContent(filename.c_str(), ss.str());
98 }
99 
isHighScore(int newScore)100 bool Highscore::isHighScore(int newScore) {
101 	if (newScore>table.back().score) {
102 		return true;
103 	}
104 	return false;
105 }
106 
addScore(const std::string & newName,int newScore)107 void Highscore::addScore(const std::string& newName, int newScore) {
108 	record r;
109 	r.name = newName;
110 	r.score = newScore;
111 	table.push_back(r);
112 	std::stable_sort(table.begin(), table.end(), record_sorter);
113 	table.resize(top);
114 	Highscore::writeFile();
115 }
116 
getScoreNumber(int room)117 record Highscore::getScoreNumber(int room) {
118 	record ret;
119 	if (room < static_cast<int>(table.size()) ) {
120 		ret = table.at(room);
121 	}
122 	return ret;
123 }
124 
125