20130427
[gdash.git] / src / framework / titlescreenactivity.cpp
blob2e717a22f7c94cc9057d38eef8448b70e582e855
1 /*
2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
19 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include "config.h"
26 #include <glib/gi18n.h>
28 #include "framework/titlescreenactivity.hpp"
29 #include "framework/app.hpp"
30 #include "misc/smartptr.hpp"
32 #include "misc/logger.hpp"
33 #include "misc/helptext.hpp"
34 #include "framework/replaymenuactivity.hpp"
35 #include "framework/commands.hpp"
36 #include "input/gameinputhandler.hpp"
37 #include "input/joystick.hpp"
38 #include "cave/caveset.hpp"
39 #include "cave/titleanimation.hpp"
40 #include "settings.hpp"
41 #include "gfx/screen.hpp"
42 #include "gfx/pixbuffactory.hpp"
43 #include "gfx/fontmanager.hpp"
44 #include "sound/sound.hpp"
47 TitleScreenActivity::TitleScreenActivity(App *app)
48 : Activity(app)
49 , PixmapStorage(*app->screen)
50 , scale(app->screen->get_pixmap_scale())
51 , image_centered_threshold(164 * scale)
52 , frames(0), time_ms(0), animcycle(0)
53 , which_status(0) {
54 caveset_has_levels = app->caveset->has_levels();
55 cavenum = app->caveset->last_selected_cave;
56 levelnum = app->caveset->last_selected_level;
60 TitleScreenActivity::~TitleScreenActivity() {
61 clear_animation();
65 void TitleScreenActivity::release_pixmaps() {
66 clear_animation();
70 void TitleScreenActivity::render_animation() const {
71 if (animation.empty()) {
72 animation = get_title_animation_pixmap(app->caveset->title_screen, app->caveset->title_screen_scroll, false, *app->screen, app->screen->pixbuf_factory);
73 /* this is required because the caveset might have changed since the last redraw, and
74 * thus the title screen might have changed, and the new title screen might have fewer
75 * frames than the original. */
76 animcycle = 0;
81 void TitleScreenActivity::clear_animation() {
82 for (unsigned x = 0; x < animation.size(); x++)
83 delete animation[x];
84 animation.clear();
88 void TitleScreenActivity::shown_event() {
89 int scale = app->screen->get_pixmap_scale();
90 app->screen->set_size(scale * 320, scale * 200, gd_fullscreen);
92 /* render title screen animation in memory pixmap */
93 render_animation();
95 /* height of title screen, then decide which lines to show and where */
96 image_h = animation[0]->get_height();
97 int font_h = app->font_manager->get_font_height();
98 /* less than 2 lines left - place for only one line of text. */
99 if (app->screen->get_height() - image_h < 2 * font_h) {
100 y_gameline = -1;
101 y_caveline = image_h + (app->screen->get_height() - image_h - font_h) / 2; /* centered in the small place */
102 show_status = false;
103 } else if (app->screen->get_height() - image_h < 3 * font_h) {
104 /* more than 2, less than 3 - place for status bar. game name is not shown, as this will */
105 /* only be true for a game with its own title screen, and i decided that in that case it */
106 /* would make more sense. */
107 y_gameline = -1;
108 y_caveline = image_h + (app->screen->get_height() - image_h - font_h * 2) / 2; /* centered there */
109 show_status = true;
110 } else {
111 /* more than 3, less than 4 - place for everything. */
112 y_gameline = image_h + (app->screen->get_height() - image_h - font_h - font_h * 2) / 2; /* centered with cave name */
113 y_caveline = y_gameline + font_h;
114 /* if there is some place, move the cave line one pixel lower. */
115 if (y_caveline + 2 * font_h < app->screen->get_height())
116 y_caveline += 1 * scale;
117 show_status = true;
120 app->screen->set_title(CPrintf("GDash - %s") % app->caveset->name);
121 gd_music_play_random();
125 void TitleScreenActivity::hidden_event() {
126 clear_animation();
130 void TitleScreenActivity::redraw_event(bool full) const {
131 app->clear_screen();
133 // If the screen was resized, the animation might have disappeared
134 render_animation();
136 if (y_gameline != -1) {
137 // TRANSLATORS: Game here is like caveset, the loaded game from which the user will select the cave to play
138 app->blittext_n(0, y_gameline, CPrintf("%c%s: %c%s %c%s") % GD_COLOR_INDEX_WHITE % _("Game") % GD_COLOR_INDEX_YELLOW % app->caveset->name % GD_COLOR_INDEX_RED % (app->caveset->edited ? "*" : ""));
141 int dx = (app->screen->get_width() - animation[animcycle]->get_width()) / 2; /* centered horizontally */
142 int dy;
143 if (animation[animcycle]->get_height() < image_centered_threshold)
144 dy = (image_centered_threshold - animation[animcycle]->get_height()) / 2; /* centered vertically */
145 else
146 dy = 0; /* top of screen, as not too much space was left for info lines */
147 app->screen->blit(*animation[animcycle], dx, dy);
149 if (show_status) {
150 if (get_active_logger().empty()) {
151 switch (which_status) {
152 case 0:
153 // TRANSLATORS: 40 chars max. Select the game to play.
154 app->status_line(_("Crsr: select Space: play H: help"));
155 break;
156 case 1:
157 #ifdef HAVE_GTK
158 /* the gtk version has an editor */
159 // TRANSLATORS: 40 chars max.
160 app->status_line(_("F: hall of fame E: editor R: replays"));
161 #else
162 /* the non-gtk version has no editor */
163 // TRANSLATORS: 40 chars max.
164 app->status_line(_("F: hall of fame R: replays"));
165 #endif
166 break;
167 case 2:
168 // TRANSLATORS: 40 chars max. Joy here is the joystick (that one can also select the cave)
169 app->status_line(_("Joy: select Fire: play"));
170 break;
172 } else {
173 app->status_line(_("Crsr: select Space: play X: errors"));
176 /* selected cave */
177 if (app->caveset->caves.size() == 0) {
178 app->blittext_n(0, y_caveline, CPrintf(_("%cNo caves.")) % GD_COLOR_INDEX_WHITE);
179 } else {
180 // TRANSLATORS: Cave is the name of the cave to play
181 if (caveset_has_levels) {
182 app->blittext_n(0, y_caveline, CPrintf(_("%cCave: %c%s%c/%c%d")) % GD_COLOR_INDEX_WHITE % GD_COLOR_INDEX_YELLOW % app->caveset->cave(cavenum).name % GD_COLOR_INDEX_WHITE % GD_COLOR_INDEX_YELLOW % (levelnum + 1));
183 } else {
184 app->blittext_n(0, y_caveline, CPrintf(_("%cCave: %c%s%c")) % GD_COLOR_INDEX_WHITE % GD_COLOR_INDEX_YELLOW % app->caveset->cave(cavenum).name);
188 app->screen->drawing_finished();
192 static int previous_selectable_cave(CaveSet &caveset, unsigned cavenum) {
193 unsigned cn = cavenum;
194 while (cn > 0) {
195 cn--;
196 if (gd_all_caves_selectable || caveset.cave(cn).selectable)
197 return cn;
200 /* if not found any suitable, return current */
201 return cavenum;
205 static int next_selectable_cave(CaveSet &caveset, unsigned cavenum) {
206 unsigned cn = cavenum;
207 while (cn + 1 < caveset.caves.size()) {
208 cn++;
209 if (gd_all_caves_selectable || caveset.cave(cn).selectable)
210 return cn;
213 /* if not found any suitable, return current */
214 return cavenum;
218 void TitleScreenActivity::timer_event(int ms_elapsed) {
219 time_ms += ms_elapsed;
220 if (time_ms >= 40) {
221 time_ms -= 40;
222 animcycle = (animcycle + 1) % animation.size();
223 frames++;
224 if (frames > 100) {
225 frames = 0;
226 which_status += 1;
227 if (which_status > 2 || (!Joystick::have_joystick() && which_status == 2))
228 which_status = 0;
231 /* on every 5th timer event... */
232 if (frames % 5 == 0) {
233 /* joystick or keyboard up */
234 if (caveset_has_levels && app->gameinput->up()) {
235 levelnum++;
236 if (levelnum > 4)
237 levelnum = 4;
239 /* joystick or keyboard down */
240 if (caveset_has_levels && app->gameinput->down()) {
241 levelnum--;
242 if (levelnum < 0)
243 levelnum = 0;
245 /* joystick or keyboard left */
246 if (app->gameinput->left())
247 cavenum = previous_selectable_cave(*app->caveset, cavenum);
248 /* joystick or keyboard right */
249 if (app->gameinput->right())
250 cavenum = next_selectable_cave(*app->caveset, cavenum);
252 /* for a fire event, maybe from the joystick, start the game immediately.
253 * when from the keyboard, we would ask the user name,
254 * but how would the user press the enter key? :) */
255 if (app->gameinput->fire1()) {
256 NewGameCommand *command = new NewGameCommand(app, cavenum, levelnum);
257 command->set_param1(gd_username);
258 app->enqueue_command(command);
262 queue_redraw();
267 void TitleScreenActivity::keypress_event(KeyCode keycode, int gfxlib_keycode) {
268 switch (keycode) {
269 case 'h':
270 case 'H':
271 app->show_help(titlehelp);
272 break;
273 case 'a':
274 case 'A':
275 app->show_about_info();
276 break;
277 case 'i':
278 case 'I':
279 app->enqueue_command(new ShowCaveInfoCommand(app));
280 break;
281 case 's':
282 case 'S':
283 app->enqueue_command(new SaveFileCommand(app));
284 break;
285 case 'n':
286 case 'N':
287 app->enqueue_command(new SaveFileAsCommand(app));
288 break;
289 case 'l':
290 case 'L':
291 case App::Tab:
292 app->enqueue_command(new SelectFileToLoadIfDiscardableCommand(app, gd_last_folder));
293 break;
294 case 'c':
295 case 'C':
296 app->enqueue_command(new SelectFileToLoadIfDiscardableCommand(app, gd_system_caves_dir));
297 break;
298 case 'e':
299 case 'E':
300 #ifdef HAVE_GTK
301 app->start_editor();
302 #endif
303 break;
304 case 'o':
305 case 'O':
306 app->show_settings(gd_get_game_settings_array());
307 break;
308 case 'k':
309 case 'K':
310 app->show_settings(gd_get_keyboard_settings_array(app->gameinput));
311 break;
312 case 'f':
313 case 'F':
314 app->enqueue_command(new ShowHighScoreCommand(app, NULL, -1));
315 break;
316 case 't':
317 case 'T':
318 app->enqueue_command(new ShowStatisticsCommand(app));
319 break;
320 case 'x':
321 case 'X':
322 app->enqueue_command(new ShowErrorsCommand(app, get_active_logger()));
323 break;
324 case 'r':
325 case 'R':
326 app->enqueue_command(new PushActivityCommand(app, new ReplayMenuActivity(app)));
327 break;
328 case App::Enter:
329 case ' ':
330 app->caveset->last_selected_cave = cavenum;
331 app->caveset->last_selected_level = levelnum;
332 app->input_text_and_do_command(_("Enter your name"), gd_username.c_str(), new NewGameCommand(app, cavenum, levelnum));
333 break;
334 case App::Escape:
335 case 'q':
336 case 'Q':
337 /* if edited, do as if a quit is requested. then the user will be asked if discards edit. */
338 /* otherwise, simply ask if he wants to quit. */
339 if (app->caveset->edited)
340 app->quit_event();
341 else
342 // TRANSLATORS: Game means the application here.
343 app->ask_yesorno_and_do_command(_("Quit game?"), _("yes"), _("no"), new PopAllActivitiesCommand(app),
344 SmartPtr<Command>());
345 break;