20130313
[gdash.git] / src / framework / titlescreenactivity.cpp
blob15cc9d3bd04ab7c53161ea5f92f18ef66cffe9e7
1 /*
2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "config.h"
19 #include <glib/gi18n.h>
21 #include "misc/logger.hpp"
22 #include "misc/printf.hpp"
23 #include "framework/titlescreenactivity.hpp"
24 #include "framework/gameactivity.hpp"
25 #include "framework/inputtextactivity.hpp"
26 #include "framework/settingsactivity.hpp"
27 #include "framework/replaymenuactivity.hpp"
28 #include "framework/commands.hpp"
29 #include "input/gameinputhandler.hpp"
30 #include "cave/caveset.hpp"
31 #include "cave/titleanimation.hpp"
32 #include "settings.hpp"
33 #include "gfx/screen.hpp"
34 #include "gfx/pixmap.hpp"
35 #include "gfx/pixbuffactory.hpp"
36 #include "gfx/fontmanager.hpp"
37 #include "sound/sound.hpp"
38 #include "misc/about.hpp"
39 #include "cave/gamecontrol.hpp"
40 #include "settings.hpp"
43 TitleScreenActivity::TitleScreenActivity(App *app)
45 Activity(app),
46 scale(app->pixbuf_factory->get_pixmap_scale()),
47 image_centered_threshold(164*scale),
48 frames(0), time_ms(0), animcycle(0),
49 alternate_status(false)
51 cavenum = app->caveset->last_selected_cave;
52 levelnum = app->caveset->last_selected_level;
56 TitleScreenActivity::~TitleScreenActivity() {
57 clear_animation();
61 void TitleScreenActivity::shown_event() {
62 int scale = app->pixbuf_factory->get_pixmap_scale();
63 app->screen->set_size(scale * 320, scale * 200);
65 /* render title screen animation in memory pixmap */
66 animation = get_title_animation_pixmap(app->caveset->title_screen, app->caveset->title_screen_scroll, false, *app->pixbuf_factory);
68 /* height of title screen, then decide which lines to show and where */
69 image_h=animation[0]->get_height();
70 int font_h=app->font_manager->get_font_height();
71 /* less than 2 lines left - place for only one line of text. */
72 if (app->screen->get_height()-image_h < 2*font_h) {
73 y_gameline=-1;
74 y_caveline=image_h + (app->screen->get_height()-image_h-font_h)/2; /* centered in the small place */
75 show_status=false;
77 else if (app->screen->get_height()-image_h < 3*font_h) {
78 /* more than 2, less than 3 - place for status bar. game name is not shown, as this will */
79 /* only be true for a game with its own title screen, and i decided that in that case it */
80 /* would make more sense. */
81 y_gameline=-1;
82 y_caveline=image_h + (app->screen->get_height()-image_h-font_h*2)/2; /* centered there */
83 show_status=true;
84 } else {
85 /* more than 3, less than 4 - place for everything. */
86 y_gameline=image_h + (app->screen->get_height()-image_h-font_h-font_h*2)/2; /* centered with cave name */
87 y_caveline=y_gameline+font_h;
88 /* if there is some place, move the cave line one pixel lower. */
89 if (y_caveline+2*font_h<app->screen->get_height())
90 y_caveline+=1*scale;
91 show_status=true;
94 app->screen->set_title(CPrintf("GDash - %s") % app->caveset->name);
95 gd_music_play_random();
99 void TitleScreenActivity::clear_animation() {
100 for (unsigned x=0; x<animation.size(); x++)
101 delete animation[x];
102 animation.clear();
106 void TitleScreenActivity::hidden_event() {
107 clear_animation();
111 void TitleScreenActivity::redraw_event() {
112 app->screen->start_drawing();
114 app->clear_screen();
116 if (y_gameline!=-1) {
117 // TRANSLATORS: Game here is like caveset, the loaded game from which the user will select the cave to play
118 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 ? "*" : ""));
121 int dx=(app->screen->get_width()-animation[animcycle]->get_width())/2; /* centered horizontally */
122 int dy;
123 if (animation[animcycle]->get_height()<image_centered_threshold)
124 dy=(image_centered_threshold - animation[animcycle]->get_height())/2; /* centered vertically */
125 else
126 dy=0; /* top of screen, as not too much space was left for info lines */
127 app->screen->blit(*animation[animcycle], dx, dy);
129 if (show_status) {
130 if (alternate_status) {
131 // TRANSLATORS: 40 chars max. Joy here is the joystick (that one can also select the cave)
132 app->status_line(_("Joy: select Fire: play"));
133 } else {
134 // TRANSLATORS: 40 chars max. Select the game to play.
135 app->status_line(_("Crsr: select Space: Play H: Help"));
138 if (!get_active_logger().empty()) {
139 /* show error flag */
140 app->set_color(GD_GDASH_RED);
141 app->blittext_n(app->screen->get_width()-app->font_manager->get_font_width_narrow(),
142 app->screen->get_height()-app->font_manager->get_font_height(), CPrintf("%c") % GD_BALL_CHAR);
145 /* selected cave */
146 if (app->caveset->caves.size() == 0) {
147 app->blittext_n(0, y_caveline, CPrintf(_("%cNo caves.")) % GD_COLOR_INDEX_WHITE);
148 } else {
149 // TRANSLATORS: Cave is the name of the cave to play
150 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));
153 app->screen->flip();
157 static int previous_selectable_cave(CaveSet& caveset, unsigned cavenum) {
158 unsigned cn=cavenum;
159 while (cn>0) {
160 cn--;
161 if (gd_all_caves_selectable || caveset.cave(cn).selectable)
162 return cn;
165 /* if not found any suitable, return current */
166 return cavenum;
170 static int next_selectable_cave(CaveSet& caveset, unsigned cavenum) {
171 unsigned cn=cavenum;
172 while (cn+1<caveset.caves.size()) {
173 cn++;
174 if (gd_all_caves_selectable || caveset.cave(cn).selectable)
175 return cn;
178 /* if not found any suitable, return current */
179 return cavenum;
183 void TitleScreenActivity::timer_event(int ms_elapsed) {
184 time_ms += ms_elapsed;
185 if (time_ms >= 40) {
186 time_ms -= 40;
187 animcycle=(animcycle+1)%animation.size();
188 frames++;
189 if (frames>100) {
190 frames=0;
191 alternate_status=!alternate_status;
194 /* on every 5th timer event... */
195 if (frames % 5 == 0) {
196 /* joystick or keyboard up */
197 if (app->gameinput->up()) {
198 levelnum++;
199 if (levelnum>4)
200 levelnum=4;
202 /* joystick or keyboard down */
203 if (app->gameinput->down()) {
204 levelnum--;
205 if (levelnum<0)
206 levelnum=0;
208 /* joystick or keyboard left */
209 if (app->gameinput->left())
210 cavenum = previous_selectable_cave(*app->caveset, cavenum);
211 /* joystick or keyboard right */
212 if (app->gameinput->right())
213 cavenum = next_selectable_cave(*app->caveset, cavenum);
215 /* for a fire event, maybe from the joystick, start the game immediately.
216 * when from the keyboard, we would ask the user name,
217 * but how would the user press the enter key? :) */
218 if (app->gameinput->fire1()) {
219 NewGameCommand *command = new NewGameCommand(app, cavenum, levelnum);
220 command->set_param1(gd_username);
221 app->enqueue_command(command);
225 redraw_event();
230 void show_errors(App *app, Logger &l) {
231 std::string text;
233 Logger::Container const& errors = l.get_messages();
234 for (Logger::Container::const_iterator it = errors.begin(); it != errors.end(); ++it) {
235 text += it->message;
236 text += "\n\n";
238 // TRANSLATORS: 40 chars max
239 app->show_text_and_do_command(_("GDASH ERROR CONSOLE"), text);
240 l.clear();
244 void TitleScreenActivity::keypress_event(KeyCode keycode, int gfxlib_keycode) {
245 switch (keycode) {
246 case 'h':
247 case 'H':
249 static char const *strings[]={
250 // TRANSLATORS: cursor keys selected for playing, or joystick movement
251 _("Cursor, joy"), _("Select cave & level"),
252 // TRANSLATORS: users press space of game/joystick fire button to play
253 _("Space, Fire1"), _("Play the game"),
254 "", "",
255 // TRANSLATORS: string should be short (~20 chars)
256 "L, Tab (C)", _("Load (installed caves)"),
257 // TRANSLATORS: string should be short (~20 chars)
258 "S (N)", _("Save (Save as)"),
259 "I", _("Caveset info"),
260 "F", _("Hall of fame"),
261 "R", _("Replays"),
262 "", "",
263 "E", _("Editor"),
264 "", "",
265 "F9", _("Sound volume"),
266 // TRANSLATORS: string should be short (~20 chars)
267 "F11", _("Fullscreen ON/OFF"),
268 "O", _("Options"),
269 "K", _("Keyboard options"),
270 "X", _("Error console"),
271 "A", _("About GDash"),
272 "", "",
273 "Escape", _("Quit game"),
274 NULL
276 app->show_text_and_do_command(_("GDash Help"), help_strings_to_string(strings));
278 break;
279 case 'a':
280 case 'A':
281 app->show_about_info();
282 break;
283 case 'i':
284 case 'I':
285 app->enqueue_command(new ShowCaveInfoCommand(app));
286 break;
287 case 's':
288 case 'S':
289 app->enqueue_command(new SaveFileCommand(app));
290 break;
291 case 'n':
292 case 'N':
293 app->enqueue_command(new SaveFileAsCommand(app));
294 break;
295 case 'l':
296 case 'L':
297 case App::Tab:
298 app->enqueue_command(new SelectFileToLoadIfDiscardableCommand(app, gd_last_folder));
299 break;
300 case 'c':
301 case 'C':
302 app->enqueue_command(new SelectFileToLoadIfDiscardableCommand(app, gd_system_caves_dir));
303 break;
304 case 'e':
305 case 'E':
306 app->start_editor();
307 break;
308 case 'o':
309 case 'O':
310 app->show_settings(gd_get_game_settings_array());
311 break;
312 case 'k':
313 case 'K':
314 app->show_settings(gd_get_keyboard_settings_array(app->gameinput));
315 break;
316 case 'f':
317 case 'F':
318 app->enqueue_command(new ShowHighScoreCommand(app, NULL, -1));
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 /* escape on the title screen is the same as closing the application */
336 app->quit_event();
337 break;