1 /*
2  * This source file is part of libRocket, the HTML/CSS Interface Middleware
3  *
4  * For the latest information, see http://www.librocket.com
5  *
6  * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  *
26  */
27 
28 #include "HighScores.h"
29 #include <Rocket/Core/TypeConverter.h>
30 #include <stdio.h>
31 
32 HighScores* HighScores::instance = NULL;
33 
HighScores()34 HighScores::HighScores() : Rocket::Controls::DataSource("high_scores")
35 {
36 	ROCKET_ASSERT(instance == NULL);
37 	instance = this;
38 
39 	for (int i = 0; i < NUM_SCORES; i++)
40 	{
41 		scores[i].score = -1;
42 	}
43 
44 	LoadScores();
45 }
46 
~HighScores()47 HighScores::~HighScores()
48 {
49 	ROCKET_ASSERT(instance == this);
50 
51 	SaveScores();
52 
53 	instance = NULL;
54 }
55 
Initialise()56 void HighScores::Initialise()
57 {
58 	new HighScores();
59 }
60 
Shutdown()61 void HighScores::Shutdown()
62 {
63 	delete instance;
64 }
65 
GetRow(Rocket::Core::StringList & row,const Rocket::Core::String & table,int row_index,const Rocket::Core::StringList & columns)66 void HighScores::GetRow(Rocket::Core::StringList& row, const Rocket::Core::String& table, int row_index, const Rocket::Core::StringList& columns)
67 {
68 	if (table == "scores")
69 	{
70 		for (size_t i = 0; i < columns.size(); i++)
71 		{
72 			if (columns[i] == "name")
73 			{
74 				row.push_back(scores[row_index].name);
75 			}
76 			else if (columns[i] == "name_required")
77 			{
78 				row.push_back(Rocket::Core::String(4, "%d", scores[row_index].name_required));
79 			}
80 			else if (columns[i] == "score")
81 			{
82 				row.push_back(Rocket::Core::String(32, "%d", scores[row_index].score));
83 			}
84 			else if (columns[i] == "colour")
85 			{
86 				Rocket::Core::String colour_string;
87 				Rocket::Core::TypeConverter< Rocket::Core::Colourb, Rocket::Core::String >::Convert(scores[row_index].colour, colour_string);
88 				row.push_back(colour_string);
89 			}
90 			else if (columns[i] == "wave")
91 			{
92 				row.push_back(Rocket::Core::String(8, "%d", scores[row_index].wave));
93 			}
94 		}
95 	}
96 }
97 
GetNumRows(const Rocket::Core::String & table)98 int HighScores::GetNumRows(const Rocket::Core::String& table)
99 {
100 	if (table == "scores")
101 	{
102 		for (int i = 0; i < NUM_SCORES; i++)
103 		{
104 			if (scores[i].score == -1)
105 			{
106 				return i;
107 			}
108 		}
109 
110 		return NUM_SCORES;
111 	}
112 
113 	return 0;
114 }
115 
GetHighScore()116 int HighScores::GetHighScore()
117 {
118 	if (instance->GetNumRows("scores") == 0)
119 	{
120 		return 0;
121 	}
122 
123 	return instance->scores[0].score;
124 }
125 
SubmitScore(const Rocket::Core::String & name,const Rocket::Core::Colourb & colour,int wave,int score)126 void HighScores::SubmitScore(const Rocket::Core::String& name, const Rocket::Core::Colourb& colour, int wave, int score)
127 {
128 	instance->SubmitScore(name, colour, wave, score, false);
129 }
130 
SubmitScore(const Rocket::Core::Colourb & colour,int wave,int score)131 void HighScores::SubmitScore(const Rocket::Core::Colourb& colour, int wave, int score)
132 {
133 	instance->SubmitScore("", colour, wave, score, true);
134 }
135 
136 // Sets the name of the last player to submit their score.
SubmitName(const Rocket::Core::String & name)137 void HighScores::SubmitName(const Rocket::Core::String& name)
138 {
139 	for (int i = 0; i < instance->GetNumRows("scores"); i++)
140 	{
141 		if (instance->scores[i].name_required)
142 		{
143 			instance->scores[i].name = name;
144 			instance->scores[i].name_required = false;
145 			instance->NotifyRowChange("scores", i, 1);
146 		}
147 	}
148 }
149 
SubmitScore(const Rocket::Core::String & name,const Rocket::Core::Colourb & colour,int wave,int score,bool name_required)150 void HighScores::SubmitScore(const Rocket::Core::String& name, const Rocket::Core::Colourb& colour, int wave, int score, bool name_required)
151 {
152 	for (int i = 0; i < NUM_SCORES; i++)
153 	{
154 		if (score > scores[i].score)
155 		{
156 			// If we've already got the maximum number of scores, then we have
157 			// to send a RowsRemoved message as we're going to delete the last
158 			// row from the data source.
159 			bool max_rows = scores[NUM_SCORES - 1].score != -1;
160 
161 			// Push down all the other scores.
162 			for (int j = NUM_SCORES - 1; j > i; j--)
163 			{
164 				scores[j] = scores[j - 1];
165 			}
166 
167 			// Insert our new score.
168 			scores[i].name = name;
169 			scores[i].colour = colour;
170 			scores[i].wave = wave;
171 			scores[i].score = score;
172 			scores[i].name_required = name_required;
173 
174 			// Send the row removal message (if necessary).
175 			if (max_rows)
176 			{
177 				NotifyRowRemove("scores", NUM_SCORES - 1, 1);
178 			}
179 
180 			// Then send the rows added message.
181 			NotifyRowAdd("scores", i, 1);
182 
183 			return;
184 		}
185 	}
186 }
187 
LoadScores()188 void HighScores::LoadScores()
189 {
190 	// Open and read the high score file.
191 	FILE* scores_file = fopen("scores.txt", "rt");
192 
193 	if (scores_file)
194 	{
195 		char buffer[1024];
196 		while (fgets(buffer, 1024, scores_file))
197 		{
198 			Rocket::Core::StringList score_parts;
199 			Rocket::Core::StringUtilities::ExpandString(score_parts, Rocket::Core::String(buffer), '\t');
200 			if (score_parts.size() == 4)
201 			{
202 				Rocket::Core::Colourb colour;
203 				int wave;
204 				int score;
205 
206 				if (Rocket::Core::TypeConverter< Rocket::Core::String , Rocket::Core::Colourb >::Convert(score_parts[1], colour) &&
207 					Rocket::Core::TypeConverter< Rocket::Core::String, int >::Convert(score_parts[2], wave) &&
208 					Rocket::Core::TypeConverter< Rocket::Core::String, int >::Convert(score_parts[3], score))
209 				{
210 					SubmitScore(score_parts[0], colour, wave, score);
211 				}
212 			}
213 		}
214 
215 		fclose(scores_file);
216 	}
217 }
218 
SaveScores()219 void HighScores::SaveScores()
220 {
221 	FILE* scores_file = fopen("scores.txt", "wt");
222 
223 	if (scores_file)
224 	{
225 		for (int i = 0; i < GetNumRows("scores"); i++)
226 		{
227 			Rocket::Core::String colour_string;
228 			Rocket::Core::TypeConverter< Rocket::Core::Colourb, Rocket::Core::String >::Convert(scores[i].colour, colour_string);
229 
230 			Rocket::Core::String score(1024, "%s\t%s\t%d\t%d\n", scores[i].name.CString(), colour_string.CString(), scores[i].wave, scores[i].score);
231 			fputs(score.CString(), scores_file);
232 		}
233 
234 		fclose(scores_file);
235 	}
236 }
237