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