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