1 //
2 // Cross-platform free Puyo-Puyo clone.
3 // Copyright (C) 2006, 2007 Emma's Software
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 #if defined (HAVE_CONFIG_H)
20 #include <config.h>
21 #endif // HAVE_CONFIG_H
22 #include <SDL.h>
23 #include <sstream>
24 #include "File.h"
25 #include "HighScoreState.h"
26 #include "NewHighScoreState.h"
27 #include "Options.h"
28 #include "System.h"
29
30 using namespace Amoebax;
31
32 ///
33 /// \brief Default constructor.
34 ///
35 /// \param score The score that is a new high score.
36 ///
NewHighScoreState(uint32_t score)37 NewHighScoreState::NewHighScoreState (uint32_t score):
38 IState (),
39 m_Background (0),
40 m_BackgroundMusic (Music::fromFile (File::getMusicFilePath ("Congratulations.ogg"))),
41 m_CursorValueIndex (0),
42 m_CursorValues ("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?*-_. "),
43 m_CursorVisible (true),
44 m_CursorVisibleTime (k_CursorVisibleTime),
45 m_HighLightFont (0),
46 m_Name (""),
47 m_NameFont (0),
48 m_Score (score)
49 {
50 #if !defined (IS_GP2X_HOST)
51 System::getInstance ().enableUnicodeTranslation (true);
52 #endif // !IS_GP2X_HOST
53 loadGraphicResources ();
54 }
55
56 ///
57 /// \brief Destructor.
58 ///
~NewHighScoreState(void)59 NewHighScoreState::~NewHighScoreState (void)
60 {
61 #if !defined (IS_GP2X_HOST)
62 System::getInstance ().enableUnicodeTranslation (false);
63 #endif // !IS_GP2X_HOST
64 }
65
66 ///
67 /// \brief Adds the name to the high score list.
68 ///
69 /// When the name as been added to the high score list, this state is removed
70 /// from the system and the HighScoreState gets pushed to the System's stack.
71 ///
72 void
acceptName(void)73 NewHighScoreState::acceptName (void)
74 {
75 if ( m_Name.length () > 0 )
76 {
77 Options::getInstance ().setHighScore (getScore (), m_Name);
78 System::getInstance ().removeActiveState ();
79 System::getInstance ()
80 .setActiveState (new HighScoreState (getScore ()));
81 }
82 }
83
84 void
activate(void)85 NewHighScoreState::activate (void)
86 {
87 if ( Music::isPaused () )
88 {
89 Music::resume ();
90 }
91 else
92 {
93 m_BackgroundMusic->play ();
94 }
95 }
96
97 ///
98 /// \brief Adds the cursor character to the name and resets the cursor.
99 ///
100 void
addNewCharacter(void)101 NewHighScoreState::addNewCharacter (void)
102 {
103 if ( m_Name.length () < k_NameMaxLength )
104 {
105 m_Name += getCursorValue ();
106 m_CursorValueIndex = 0;
107 resetCursorVisibility ();
108 }
109 }
110
111 ///
112 /// \brief Tells if the cursor should be rendered or not.
113 ///
114 /// \return \a true if the cursor is visible and should be rendered,
115 /// \a false otherwise.
116 ///
117 bool
isCursorVisible(void) const118 NewHighScoreState::isCursorVisible (void) const
119 {
120 return m_CursorVisible && m_Name.length () < k_NameMaxLength;
121 }
122
123 ///
124 /// \brief Gets the current value of the cursor.
125 ///
126 /// The value of the cursor is the character that will added to
127 /// the name entered when selecting the next character to enter.
128 ///
129 /// \return The currently selected character for the cursor.
130 ///
131 const std::string
getCursorValue(void) const132 NewHighScoreState::getCursorValue (void) const
133 {
134 return m_CursorValues.substr (m_CursorValueIndex, 1);
135 }
136
137 ///
138 /// \brief Gets the time before change cursor's visibility.
139 ///
140 /// \return The time, in milliseconds, that the cursor will retain its current
141 /// visibility state.
142 ///
143 int32_t
getCursorVisibleTime(void) const144 NewHighScoreState::getCursorVisibleTime (void) const
145 {
146 return m_CursorVisibleTime;
147 }
148
149 ///
150 /// \brief Gets the score to set as high score.
151 ///
152 /// \return The score that is a new high score.
153 ///
154 uint32_t
getScore(void) const155 NewHighScoreState::getScore (void) const
156 {
157 return m_Score;
158 }
159
160 void
joyMotion(uint8_t joystick,uint8_t axis,int16_t value)161 NewHighScoreState::joyMotion (uint8_t joystick, uint8_t axis, int16_t value)
162 {
163 }
164
165 void
joyDown(uint8_t joystick,uint8_t button)166 NewHighScoreState::joyDown (uint8_t joystick, uint8_t button)
167 {
168 #if defined (IS_GP2X_HOST)
169 switch (button)
170 {
171 case GP2X_BUTTON_B:
172 case GP2X_BUTTON_RIGHT:
173 addNewCharacter ();
174 break;
175
176 case GP2X_BUTTON_DOWN:
177 selectNextCursorValue ();
178 break;
179
180 case GP2X_BUTTON_LEFT:
181 case GP2X_BUTTON_X:
182 removePreviousCharacter ();
183 break;
184
185 case GP2X_BUTTON_START:
186 acceptName ();
187 break;
188
189 case GP2X_BUTTON_UP:
190 selectPreviousCursorValue ();
191 break;
192 }
193 #endif // IS_GP2X_HOST
194 }
195
196 void
joyUp(uint8_t joystick,uint8_t button)197 NewHighScoreState::joyUp (uint8_t joystick, uint8_t button)
198 {
199 }
200
201 #if !defined (IS_GP2X_HOST)
202 void
keyDown(uint32_t key)203 NewHighScoreState::keyDown (uint32_t key)
204 {
205 switch ( key )
206 {
207 case SDLK_DOWN:
208 selectNextCursorValue ();
209 break;
210
211 case SDLK_ESCAPE:
212 System::getInstance ().removeActiveState ();
213 break;
214
215 case SDLK_LEFT:
216 case SDLK_BACKSPACE:
217 removePreviousCharacter ();
218 break;
219
220 case SDLK_RETURN:
221 acceptName ();
222 break;
223
224 case SDLK_RIGHT:
225 addNewCharacter ();
226 break;
227
228 case SDLK_UP:
229 selectPreviousCursorValue ();
230 break;
231 }
232 }
233
234 void
keyUp(uint32_t key)235 NewHighScoreState::keyUp (uint32_t key)
236 {
237 }
238 #endif // !IS_GP2X_HOST
239
240 ///
241 /// \brief Loads all graphics resources.
242 ///
243 void
loadGraphicResources(void)244 NewHighScoreState::loadGraphicResources (void)
245 {
246 const float screenScale = System::getInstance ().getScreenScaleFactor ();
247
248 // Load fonts.
249 m_HighLightFont.reset (
250 Font::fromFile (File::getFontFilePath ("fontMenuSelected")));
251 m_NameFont.reset (Font::fromFile (File::getFontFilePath ("fontMenu")));
252
253 // Load background image.
254 m_Background.reset (
255 Surface::fromFile (File::getGraphicsFilePath ("newhighscore.png")));
256 m_Background->resize (screenScale);
257
258 // Write the score into the background.
259 std::stringstream scoreString;
260 scoreString << getScore ();
261 m_NameFont->write (scoreString.str (),
262 static_cast<uint16_t>(k_ScorePosition * screenScale),
263 m_Background->toSDLSurface ());
264 }
265
266 void
redrawBackground(SDL_Rect * region,SDL_Surface * screen)267 NewHighScoreState::redrawBackground (SDL_Rect *region, SDL_Surface *screen)
268 {
269 m_Background->blit (region->x, region->y, region->w, region->h,
270 region->x, region->y, screen);
271 }
272
273 ///
274 /// \brief Removes the last character added to the name.
275 ///
276 /// The cursor index is set to the index of the removed character and its
277 /// visibility is reset.
278 ///
279 void
removePreviousCharacter(void)280 NewHighScoreState::removePreviousCharacter (void)
281 {
282 if ( m_Name.length () > 0 )
283 {
284 const std::string::size_type newLength = m_Name.length () - 1;
285 m_CursorValueIndex = m_CursorValues.find (m_Name.substr (newLength, 1));
286 m_Name = m_Name.substr (0, newLength);
287 }
288 else
289 {
290 m_CursorValueIndex = 0;
291 }
292 resetCursorVisibility ();
293 }
294
295 void
render(SDL_Surface * screen)296 NewHighScoreState::render (SDL_Surface *screen)
297 {
298 const float screenScale = System::getInstance ().getScreenScaleFactor ();
299 m_NameFont->write (m_Name,
300 static_cast<uint16_t>(k_NamePosition * screenScale),
301 screen);
302 if ( isCursorVisible () )
303 {
304 const uint16_t nameWidth = m_NameFont->getTextWidth (m_Name);
305 const uint16_t cursorPosition =
306 Options::getInstance ().getScreenWidth () / 2 + nameWidth / 2;
307 m_HighLightFont->write (getCursorValue (), cursorPosition,
308 static_cast<uint16_t>(k_NamePosition *
309 screenScale),
310 screen);
311 }
312 }
313
314 ///
315 /// \brief Resets the cursor visibility.
316 ///
317 /// Sets the cursor visible and the time to be visible to the default value.
318 ///
319 void
resetCursorVisibility(void)320 NewHighScoreState::resetCursorVisibility (void)
321 {
322 setCursorVisible (true);
323 setCursorVisibleTime (k_CursorVisibleTime);
324 }
325
326 ///
327 /// \brief Selects the next value for the cursor.
328 ///
329 /// If the cursor is already at the last possible value, it wraps around
330 /// at the begining.
331 ///
332 /// The cursor is set to be visible and the visibility time is reset to
333 /// the default.
334 ///
335 void
selectNextCursorValue(void)336 NewHighScoreState::selectNextCursorValue (void)
337 {
338 ++m_CursorValueIndex;
339 if ( m_CursorValueIndex > m_CursorValues.length () )
340 {
341 m_CursorValueIndex = 0;
342 }
343 resetCursorVisibility ();
344 }
345
346 ///
347 /// \brief Selects the previous value for the cursor.
348 ///
349 /// If the cursor is already at the first possible value, it wraps around
350 /// at the end.
351 ///
352 /// The cursor is set to be visible and the visibility time is reset to
353 /// the default.
354 ///
355 void
selectPreviousCursorValue(void)356 NewHighScoreState::selectPreviousCursorValue (void)
357 {
358 if ( m_CursorValueIndex > 0 )
359 {
360 --m_CursorValueIndex;
361 }
362 else
363 {
364 m_CursorValueIndex = m_CursorValues.length () - 1;
365 }
366 resetCursorVisibility ();
367 }
368
369 ///
370 /// \brief Sets the visibility status of the cursor.
371 ///
372 /// \param visible Set it to \a true to render the cursor. Set it to \a false
373 /// to hide the cursor.
374 ///
375 void
setCursorVisible(bool visible)376 NewHighScoreState::setCursorVisible (bool visible)
377 {
378 m_CursorVisible = visible;
379 }
380
381 ///
382 /// \brief Sets the time to retain cursor's visibility state.
383 ///
384 /// \param time The time, in milliseconds, that the cursor will retain its
385 /// current visibility state.
386 ///
387 void
setCursorVisibleTime(int32_t time)388 NewHighScoreState::setCursorVisibleTime (int32_t time)
389 {
390 m_CursorVisibleTime = time;
391 }
392
393 void
unicodeCharacterPressed(uint16_t code)394 NewHighScoreState::unicodeCharacterPressed (uint16_t code)
395 {
396 // FIXME: We are only interessted with ASCII values.
397 if ( 0 == (code & 0xff80) )
398 {
399 char character[2] = {static_cast<char>(toupper (static_cast<char>(code & 0x7f)), '\0')};
400 std::string::size_type characterPos =
401 m_CursorValues.find (std::string (character));
402 if ( std::string::npos != characterPos )
403 {
404 m_CursorValueIndex = characterPos;
405 addNewCharacter ();
406 }
407 }
408 }
409
410 void
update(uint32_t elapsedTime)411 NewHighScoreState::update (uint32_t elapsedTime)
412 {
413 setCursorVisibleTime (getCursorVisibleTime () - elapsedTime);
414 if ( getCursorVisibleTime () < 0 )
415 {
416 setCursorVisible (!isCursorVisible ());
417 do
418 {
419 setCursorVisibleTime (getCursorVisibleTime () +
420 k_CursorVisibleTime);
421 }
422 while ( getCursorVisibleTime () < 0 );
423 }
424 }
425
426 void
videoModeChanged(void)427 NewHighScoreState::videoModeChanged (void)
428 {
429 loadGraphicResources ();
430 }
431