Streamline building Tennix on Mac OS X (static)
[tennix.git] / tennix.c
blobe8c9e771d2af41d11026f999a8d301a1aa5ca0a2
2 /**
4 * Tennix! SDL Port
5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
22 **/
24 #include <stdio.h>
25 #include <time.h>
26 #include <libgen.h>
27 #include <string.h>
28 #include <stdlib.h>
30 #ifdef WIN32
31 #include <windows.h>
32 #endif
34 #include "tennix.h"
35 #include "game.h"
36 #include "graphics.h"
37 #include "sound.h"
38 #include "input.h"
39 #include "util.h"
40 #include "animation.h"
42 #include "locations.h"
44 SDL_Surface *screen;
46 #ifdef WIN32
48 /* IDs from the resource file */
49 #define START_BUTTON 1
50 #define CHECKBOX_FULLSCREEN 2
51 #define QUIT_BUTTON 3
53 BOOL CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
55 static int checkbox_is_checked;
57 switch (uMsg) {
58 case WM_CLOSE:
59 EndDialog(hwndDlg, IDCANCEL);
60 break;
61 case WM_COMMAND:
62 switch (wParam) {
63 case START_BUTTON:
64 EndDialog(hwndDlg, (checkbox_is_checked)?(IDYES):(IDNO));
65 break;
66 case QUIT_BUTTON:
67 EndDialog(hwndDlg, IDCANCEL);
68 break;
69 case CHECKBOX_FULLSCREEN:
70 checkbox_is_checked ^= 1;
71 break;
73 break;
74 default:
75 return FALSE;
77 return TRUE;
79 #endif
81 #ifdef WIN32
82 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
83 LPSTR lpCmdLine, int nCmdShow) {
84 #else
85 int main( int argc, char** argv) {
86 #endif
87 int i, slide, slide_direction;
88 unsigned int x;
89 Uint32 ticks;
90 int mx, my;
91 unsigned int worldmap_xpos, worldmap_ypos;
92 Uint8 *keys;
93 Uint8 mb;
94 SDL_Event e;
95 int sdl_flags = SDL_SWSURFACE;
96 int btn_hovering = 0, btn_hovering_old = 0;
97 int slide_start;
98 bool mouse_pressed = false;
99 bool quit = false;
100 bool benchmark = false;
101 unsigned int night_start, night_end;
102 GameState *current_game = NULL, *prepared_game = NULL;
103 InputDevice* input_devices;
104 unsigned int input_device_count, input_device_id;
105 Animation *intro;
106 AnimationState *intro_playback;
107 float wiggle;
109 MenuButton btn_back = {
110 NULL, /* not needed for image-based button */
111 MENU_OPTIONS_BORDER,
112 HEIGHT-MENU_OPTIONS_BORDER,
113 0, -1, /* width and height will be set by menu_button_init */
114 255, 0, 0,
115 GR_BACK
117 MenuButton btn_start = {
118 NULL, /* not needed for image-based button */
119 WIDTH-MENU_OPTIONS_BORDER,
120 HEIGHT-MENU_OPTIONS_BORDER,
121 -1, -1, /* width and height will be set by menu_button_init */
122 0, 255, 0,
123 GR_FORWARD
125 MenuButton btn_player1 = {
126 NULL,
127 CONTROLLER_SETUP_BORDER,
128 HEIGHT/2 + CONTROLLER_SETUP_SIZE/2 + 10,
129 CONTROLLER_SETUP_SIZE, MENU_OPTIONS_BUTTON_HEIGHT,
130 50, 50, 255,
131 GR_COUNT
133 MenuButton btn_player2 = {
134 NULL,
135 WIDTH-CONTROLLER_SETUP_SIZE-CONTROLLER_SETUP_BORDER,
136 HEIGHT/2 + CONTROLLER_SETUP_SIZE/2 + 10,
137 CONTROLLER_SETUP_SIZE, MENU_OPTIONS_BUTTON_HEIGHT,
138 255, 50, 50,
139 GR_COUNT
142 int highlight_location = -1;
143 float highlight_location_distance = 0.0;
144 float new_location_distance = 0.0;
145 bool location_info_visible = false;
146 unsigned int location_info_xpos = 0, location_info_ypos = 0;
148 const SDL_VideoInfo* vi = NULL;
150 bool do_help = false;
152 int state = MENU_STATE_STARTED;
154 #ifdef ENABLE_FPS_LIMIT
155 Uint32 ft, frames; /* frame timer and frames */
156 #endif
158 #if defined(MAEMO) || defined(MACOSX)
159 sdl_flags |= SDL_FULLSCREEN;
160 #endif
162 #ifdef WIN32
163 int mb_result;
164 mb_result = DialogBox(hInstance, "CONFIG", 0, (DLGPROC)ConfigDialogProc);
166 switch (mb_result) {
167 case IDYES:
168 sdl_flags |= SDL_FULLSCREEN;
169 break;
170 case IDCANCEL:
171 return 0;
172 break;
173 default:
174 break;
176 #else
177 fprintf(stderr, "Tennix 2009 World Tennis Championship Tour (v" VERSION ")\n" COPYRIGHT "\n" URL "\n\n");
179 i = 1;
180 while (i < argc) {
181 /* A poor/lazy man's getopt */
182 #define OPTION_SET(longopt,shortopt) \
183 (strcmp(argv[i], longopt)==0 || strcmp(argv[i], shortopt)==0)
184 #define OPTION_VALUE \
185 ((i+1 < argc)?(argv[i+1]):(NULL))
186 #define OPTION_VALUE_PROCESSED \
187 (i++)
188 if (OPTION_SET("--fullscreen", "-f")) {
189 sdl_flags |= SDL_FULLSCREEN;
191 else if (OPTION_SET("--help", "-h")) {
192 do_help = true;
194 else if (OPTION_SET("--benchmark", "-b")) {
195 benchmark = true;
197 else {
198 fprintf(stderr, "Ignoring unknown option: %s\n", argv[i]);
200 i++;
203 if (do_help == true) {
204 fprintf(stderr, "Usage: %s [--fullscreen|-f] [--help|-h]\n", argv[0]);
205 return 0;
207 #endif
209 if (benchmark) {
210 srand(100);
211 } else {
212 srand((unsigned)time(NULL));
215 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) == -1) {
216 fprintf( stderr, "Can't init SDL: %s\n", SDL_GetError());
217 exit( 1);
220 vi = SDL_GetVideoInfo();
221 if( (screen = SDL_SetVideoMode( WIDTH, HEIGHT, vi->vfmt->BitsPerPixel, sdl_flags)) == NULL) {
222 fprintf( stderr, "Can't set video mode: %s\n", SDL_GetError());
223 exit( 1);
226 SDL_WM_SetCaption( "Tennix 2009 World Tennis Championship Tour", "Tennix 2009");
227 SDL_ShowCursor( SDL_DISABLE);
228 SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, 1);
230 init_graphics();
231 init_sound();
232 init_input();
234 menu_button_init(&btn_back);
235 menu_button_init(&btn_start);
236 menu_button_init(&btn_player1);
237 menu_button_init(&btn_player2);
239 input_devices = find_input_devices(&input_device_count);
241 current_game = gamestate_load(GAMESTATE_FILE);
242 if (current_game != NULL) {
243 /* restore pointer to location */
244 current_game->location = &(locations[current_game->current_location]);
245 /* */
246 for (i=1; i<=MAXPLAYERS; i++) {
247 if (PLAYER(current_game, i).type == PLAYER_TYPE_HUMAN) {
248 input_device_id = PLAYER(current_game, i).input_device_index;
249 if (input_device_id < input_device_count) {
250 /* ok, we still have that device around */
251 PLAYER(current_game, i).input = &(input_devices[input_device_id]);
252 } else {
253 /* the device vanished - set to AI (FIXME: select new device) */
254 PLAYER(current_game, i).type = PLAYER_TYPE_AI;
255 PLAYER(current_game, i).input = NULL;
261 #ifdef ENABLE_FPS_LIMIT
262 frames = 0;
263 ft = SDL_GetTicks();
264 #endif
266 if (benchmark) {
267 GameState* g = gamestate_new();
268 PLAYER(g, 1).type = PLAYER_TYPE_AI;
269 PLAYER(g, 2).type = PLAYER_TYPE_AI;
270 g->timelimit = BENCHMARK_TIMELIMIT*1000;
271 g->location = &(locations[0]);
272 gameloop(g);
273 free(g);
274 exit(0);
277 intro = create_intro();
278 intro_playback = animation_state_new(intro);
279 animation_state_run(intro_playback, 1);
280 animation_state_free(intro_playback);
281 animation_free(intro);
282 start_fade();
284 worldmap_xpos = (WIDTH-get_image_width(GR_WORLDMAP))/2;
285 worldmap_ypos = (HEIGHT-get_image_height(GR_WORLDMAP))/2;
287 i = 0;
288 /* Sliding initialization */
289 ticks = SDL_GetTicks();
290 slide = slide_start = get_image_width(GR_SIDEBAR);
291 slide_direction = 0;
292 while(!quit) {
293 /* State transitions */
294 switch (state) {
295 case MENU_STATE_STARTED:
296 state = MENU_STATE_SLIDE_TO_MAINMENU;
297 break;
298 case MENU_STATE_SLIDE_TO_MAINMENU:
299 clear_screen();
300 rectangle(0, 0, WIDTH, HEIGHT, 80, 80, 80);
301 store_screen();
302 slide = slide_start;
303 slide_direction = -1;
304 state = MENU_STATE_SLIDE_TO_MAINMENU_IN_PROGRESS;
305 break;
306 case MENU_STATE_SLIDE_TO_MAINMENU_IN_PROGRESS:
307 if (slide == 0) {
308 slide_direction = 0;
309 state = MENU_STATE_MAINMENU;
311 break;
312 case MENU_STATE_MAINMENU:
313 free(prepared_game);
314 prepared_game = NULL;
315 break;
316 case MENU_STATE_SLIDE_TO_LOCATION:
317 slide = 1;
318 slide_direction = 3;
319 state = MENU_STATE_SLIDE_TO_LOCATION_IN_PROGRESS;
320 break;
321 case MENU_STATE_SLIDE_TO_LOCATION_IN_PROGRESS:
322 if (slide == slide_start) {
323 state = MENU_STATE_FADE_TO_LOCATION;
325 break;
326 case MENU_STATE_FADE_TO_LOCATION:
327 start_fade();
328 state = MENU_STATE_LOCATION;
329 clear_screen();
331 rectangle(0, 0, WIDTH, HEIGHT, 80, 80, 80);
332 /* Draw and store the worldmap with day/night times */
333 show_image(GR_WORLDMAP, WIDTH/2-get_image_width(GR_WORLDMAP)/2, HEIGHT/2-get_image_height(GR_WORLDMAP)/2, 255);
334 day_night(get_image_width(GR_WORLDMAP), &night_start, &night_end);
335 if (night_start > night_end) {
336 rectangle_alpha(worldmap_xpos, worldmap_ypos, night_end, get_image_height(GR_WORLDMAP), 0, 0, 0, 150);
337 rectangle_alpha(worldmap_xpos+night_start, worldmap_ypos, get_image_width(GR_WORLDMAP)-night_start, get_image_height(GR_WORLDMAP), 0, 0, 0, 150);
338 } else {
339 rectangle_alpha(worldmap_xpos+night_start, worldmap_ypos, night_end-night_start, get_image_height(GR_WORLDMAP), 0, 0, 0, 150);
342 /* add misc items to screen */
343 font_draw_string(FONT_XLARGE, "Pick a location", (WIDTH-font_get_string_width(FONT_XLARGE, "Pick a location"))/2, 20);
345 store_screen();
346 break;
347 case MENU_STATE_FADE_TO_OPTIONS:
348 start_fade();
349 clear_screen();
350 rectangle(0, 0, WIDTH, HEIGHT, 80, 80, 80);
351 rectangle(CONTROLLER_SETUP_BORDER, HEIGHT/2-CONTROLLER_SETUP_SIZE/2, CONTROLLER_SETUP_SIZE, CONTROLLER_SETUP_SIZE, 150, 150, 150);
352 rectangle(WIDTH-CONTROLLER_SETUP_BORDER-CONTROLLER_SETUP_SIZE, (HEIGHT-CONTROLLER_SETUP_SIZE)/2, CONTROLLER_SETUP_SIZE, CONTROLLER_SETUP_SIZE, 150, 150, 150);
353 font_draw_string(FONT_XLARGE, "Controller setup", (WIDTH-font_get_string_width(FONT_XLARGE, "Controller setup"))/2, 20);
354 font_draw_string(FONT_MEDIUM, "Player 1", 130 - font_get_string_width(FONT_MEDIUM, "Player 1")/2, (HEIGHT-CONTROLLER_SETUP_SIZE)/2 - 10 - font_get_height(FONT_MEDIUM));
355 font_draw_string(FONT_MEDIUM, "Player 1", 130 - font_get_string_width(FONT_MEDIUM, "Player 1")/2, (HEIGHT-CONTROLLER_SETUP_SIZE)/2 - 10 - font_get_height(FONT_MEDIUM));
356 font_draw_string(FONT_MEDIUM, "Player 2", WIDTH - CONTROLLER_SETUP_SIZE/2 - CONTROLLER_SETUP_BORDER - font_get_string_width(FONT_MEDIUM, "Player 2")/2, (HEIGHT-CONTROLLER_SETUP_SIZE)/2 - 10 - font_get_height(FONT_MEDIUM));
357 store_screen();
358 start_fade();
359 state = MENU_STATE_OPTIONS;
360 break;
361 case MENU_STATE_LOCATION:
362 case MENU_STATE_OPTIONS:
363 /* Prepare a new game */
364 if (prepared_game == NULL) {
365 prepared_game = gamestate_new();
366 prepared_game->location = NULL;
367 /* FIXME - this should not be written here, but taken from the input devices */
368 btn_player1.text = "Keyboard (arrows)";
369 btn_player2.text = "Carl Van Court";
370 #ifdef MAEMO
371 PLAYER(prepared_game, 1).input_device_index = 0;
372 #else
373 PLAYER(prepared_game, 1).input_device_index = 2;
374 #endif
375 PLAYER(prepared_game, 1).type = PLAYER_TYPE_HUMAN;
376 PLAYER(prepared_game, 1).input = &(input_devices[PLAYER(prepared_game, 1).input_device_index]);
377 location_info_visible = false;
378 prepared_game->current_location = -1;
379 highlight_location = -1;
381 break;
382 case MENU_STATE_SLIDE_TO_GAME:
383 /*slide = 1;
384 slide_direction = 2;
385 state = MENU_STATE_SLIDE_TO_GAME_IN_PROGRESS;
386 break;
387 case MENU_STATE_SLIDE_TO_GAME_IN_PROGRESS:
388 if (slide == slide_start) {
389 state = MENU_STATE_GAME;
391 state = MENU_STATE_GAME;
392 break;
393 case MENU_STATE_SLIDE_TO_RESUME:
394 slide = 1;
395 slide_direction = 2;
396 state = MENU_STATE_SLIDE_TO_RESUME_IN_PROGRESS;
397 break;
398 case MENU_STATE_SLIDE_TO_RESUME_IN_PROGRESS:
399 if (slide == slide_start) {
400 state = MENU_STATE_RESUME;
402 break;
403 case MENU_STATE_GAME:
404 if (prepared_game == NULL) {
405 fprintf(stderr, "Game not yet prepared!\n");
406 exit(EXIT_FAILURE);
408 /* Set the day/night status */
409 if (night_start < night_end) {
410 prepared_game->night = (prepared_game->location->worldmap_x > night_start && prepared_game->location->worldmap_x < night_end);
411 } else {
412 prepared_game->night = (prepared_game->location->worldmap_x < night_end || prepared_game->location->worldmap_x > night_start);
415 /* Cancel a possibly started game */
416 free(current_game);
417 current_game = prepared_game;
418 prepared_game = NULL;
419 /* no break - we are continuing with "resume" */
420 case MENU_STATE_RESUME:
421 if (current_game == NULL) {
422 fprintf(stderr, "Cannot resume game!\n");
423 exit(EXIT_FAILURE);
425 start_fade();
426 gameloop(current_game);
427 SDL_Delay(150);
428 while(SDL_PollEvent(&e));
429 #ifdef ENABLE_FPS_LIMIT
430 frames = 0;
431 ft = SDL_GetTicks();
432 #endif
433 start_fade();
434 state = MENU_STATE_SLIDE_TO_MAINMENU;
435 break;
436 case MENU_STATE_SLIDE_TO_QUIT:
437 slide = 1;
438 slide_direction = 3;
439 state = MENU_STATE_SLIDE_TO_QUIT_IN_PROGRESS;
440 break;
441 case MENU_STATE_SLIDE_TO_QUIT_IN_PROGRESS:
442 if (slide == slide_start) {
443 state = MENU_STATE_QUIT;
445 break;
446 case MENU_STATE_QUIT:
447 quit = true;
448 break;
449 default:
450 fprintf(stderr, "State error: %d\n", state);
451 exit(EXIT_FAILURE);
454 /* Sliding */
455 if (SDL_GetTicks() > ticks + 20) {
456 if (slide >= 1 && slide <= slide_start) {
457 slide += slide_direction+(slide_direction*slide/(sqrt(2*slide)));
458 slide = MAX(0, MIN(slide_start, slide));
459 } else if (slide_direction != 0) {
460 slide_direction = 0;
462 ticks = SDL_GetTicks();
465 /* Graphics */
466 #ifdef DEBUG
467 if (state != MENU_STATE_OPTIONS) {
468 fill_image_offset(GR_FOG, 0, 0, WIDTH, HEIGHT, -i, 0);
470 #endif
471 show_image(GR_SIDEBAR, WIDTH-get_image_width(GR_SIDEBAR)+slide, 0, 255);
472 show_image(GR_TENNIXLOGO, WIDTH-get_image_width(GR_SIDEBAR)-10, 20-slide, 255);
473 if (state != MENU_STATE_OPTIONS && state != MENU_STATE_LOCATION) {
474 /* Main Menu */
475 show_image(GR_BTN_PLAY, WIDTH-get_image_width(GR_BTN_PLAY)+slide+(slide/7)+3-(3*(btn_hovering==MENU_START)), 150, 255);
476 if (current_game != NULL) {
477 show_image(GR_BTN_RESUME, WIDTH-get_image_width(GR_BTN_RESUME)+slide+(slide/7)+3-(3*(btn_hovering==MENU_RESUME)), 230, 255);
478 font_draw_string(FONT_SMALL, "current match:", 10, 10);
479 font_draw_string(FONT_SMALL, current_game->sets_score_str, 10, 40);
480 } else {
481 font_draw_string(FONT_MEDIUM, "Tennix 2009 World Tennis Championship Tour", 10, 10);
483 font_draw_string_color(FONT_MEDIUM, URL, 10-1, HEIGHT-10-1-font_get_height(FONT_MEDIUM), 130, 130, 130);
484 font_draw_string_color(FONT_MEDIUM, URL, 10, HEIGHT-10-font_get_height(FONT_MEDIUM), 30, 30, 30);
485 show_image(GR_BTN_QUIT, WIDTH-get_image_width(GR_BTN_QUIT)+slide+(slide/7)+3-(3*(btn_hovering==MENU_QUIT)), 350, 255);
486 } else if (state == MENU_STATE_OPTIONS) {
487 /* Options screen */
488 draw_button_object(&btn_back, mx, my);
489 draw_button_object(&btn_start, mx, my);
490 draw_button_object(&btn_player1, mx, my);
491 draw_button_object(&btn_player2, mx, my);
492 wiggle = 15*sinf((float)ticks/300.);
493 if (PLAYER(prepared_game, 1).input_device_index > -1) {
494 show_image_rotozoom(input_devices[PLAYER(prepared_game, 1).input_device_index].icon, CONTROLLER_SETUP_BORDER + CONTROLLER_SETUP_SIZE/2, HEIGHT/2, wiggle, 1.0);
495 } else {
496 show_image_rotozoom(GR_INPUT_AI, CONTROLLER_SETUP_BORDER + CONTROLLER_SETUP_SIZE/2, HEIGHT/2, wiggle, 1.0);
498 if (PLAYER(prepared_game, 2).input_device_index > -1) {
499 show_image_rotozoom(input_devices[PLAYER(prepared_game, 2).input_device_index].icon, WIDTH-CONTROLLER_SETUP_BORDER-CONTROLLER_SETUP_SIZE/2, HEIGHT/2, -wiggle, 1.0);
500 } else {
501 show_image_rotozoom(GR_INPUT_AI, WIDTH-CONTROLLER_SETUP_BORDER-CONTROLLER_SETUP_SIZE/2, HEIGHT/2, -wiggle, 1.0);
503 } else if (state == MENU_STATE_LOCATION) {
504 /* Location selection screen */
505 for (x=0; x<location_count(); x++) {
506 new_location_distance = SQUARE_DISTANCE(mx-worldmap_xpos-locations[x].worldmap_x,
507 my-worldmap_ypos-locations[x].worldmap_y);
508 if (highlight_location == -1) {
509 if (new_location_distance < 20*20) {
510 highlight_location = x;
512 } else {
513 highlight_location_distance = SQUARE_DISTANCE(mx-worldmap_xpos-locations[highlight_location].worldmap_x,
514 my-worldmap_ypos-locations[highlight_location].worldmap_y);
515 if (highlight_location_distance > 20*20) {
516 highlight_location = -1;
518 if (highlight_location_distance > new_location_distance && new_location_distance < 20*20) {
519 highlight_location = x;
523 if (prepared_game != NULL) {
524 if (!location_info_visible) {
525 for (x=0; x<location_count(); x++) {
526 /* draw rectangle for location at "x"*/
527 if (highlight_location != -1 && (unsigned int)highlight_location == x) {
528 rectangle(worldmap_xpos + locations[x].worldmap_x-3, worldmap_ypos + locations[x].worldmap_y-3, 7, 7, 255*((i/10)%2), 0, 255*((i/10)%2));
531 rectangle(worldmap_xpos + locations[x].worldmap_x-2, worldmap_ypos + locations[x].worldmap_y-2, 5, 5, 255, 255*(prepared_game->current_location != -1 && x==(unsigned int)(prepared_game->current_location)), 0);
533 } else {
534 rectangle_alpha(location_info_xpos-5, location_info_ypos-5, 10+get_image_width(prepared_game->location->photo), get_image_height(prepared_game->location->photo)+100, 30, 30, 30, 200);
535 show_sprite(prepared_game->location->photo, (i/1000)%(prepared_game->location->photo_frames), prepared_game->location->photo_frames, location_info_xpos, location_info_ypos, 255);
536 font_draw_string(FONT_SMALL, prepared_game->location->name, location_info_xpos+MENU_OPTIONS_BORDER, location_info_ypos+MENU_OPTIONS_BORDER+200);
537 font_draw_string(FONT_SMALL, prepared_game->location->area, location_info_xpos+MENU_OPTIONS_BORDER, location_info_ypos+MENU_OPTIONS_BORDER+200+font_get_height(FONT_SMALL));
538 font_draw_string(FONT_SMALL, prepared_game->location->city, location_info_xpos+MENU_OPTIONS_BORDER, location_info_ypos+MENU_OPTIONS_BORDER+200+2*font_get_height(FONT_SMALL));
539 font_draw_string(FONT_SMALL, prepared_game->location->court_type_name, location_info_xpos+MENU_OPTIONS_BORDER, location_info_ypos+MENU_OPTIONS_BORDER+200+3*font_get_height(FONT_SMALL));
541 if (prepared_game->location != NULL) {
542 draw_button_object(&btn_start, mx, my);
545 draw_button_object(&btn_back, mx, my);
548 SDL_PollEvent( &e);
549 if( e.type == SDL_QUIT) {
550 state = MENU_STATE_SLIDE_TO_QUIT;
551 /*break;*/
554 keys = SDL_GetKeyState( NULL);
555 mb = SDL_GetMouseState( &mx, &my);
557 btn_hovering_old = btn_hovering;
558 if (state == MENU_STATE_MAINMENU) {
559 btn_hovering = M_POS_DECODE(mx, my);
560 if (current_game == NULL) {
561 btn_hovering &= ~MENU_RESUME;
563 } else if (state == MENU_STATE_LOCATION) {
564 if (M_POS_BUTTON(btn_back, mx, my)) {
565 btn_hovering = MENU_QUIT;
566 } else if (M_POS_BUTTON(btn_start, mx, my)) {
567 btn_hovering = MENU_START;
568 } else {
569 btn_hovering = 0;
571 } else if (state == MENU_STATE_OPTIONS) {
572 if (M_POS_BUTTON(btn_back, mx, my)) {
573 btn_hovering = MENU_QUIT;
574 } else if (M_POS_BUTTON(btn_start, mx, my)) {
575 btn_hovering = MENU_START;
576 } else if (M_POS_BUTTON(btn_player1, mx, my)) {
577 btn_hovering = MENU_PLAYER1;
578 } else if (M_POS_BUTTON(btn_player2, mx, my)) {
579 btn_hovering = MENU_PLAYER2;
580 } else {
581 btn_hovering = 0;
583 } else {
584 /* No menu screen - no hovering. */
585 btn_hovering = 0;
587 #ifndef MAEMO /* On Maemo, we cannot really "hover" (touchscreen!) */
588 if (btn_hovering_old != btn_hovering && btn_hovering != 0) {
589 #ifdef HAVE_VOICE_FILES
590 if (btn_hovering == MENU_QUIT) {
591 play_sample(VOICE_QUIT_IT);
592 } else if (btn_hovering == MENU_START) {
593 play_sample(VOICE_NEW_GAME);
594 } else {
595 play_sample(SOUND_MOUSEOVER);
597 #else
598 /*play_sample(SOUND_MOUSEOVER);*/
599 #endif
601 #endif
603 if( keys[SDLK_ESCAPE] || keys['q']) {
604 /* FIXME: do the state thingie! */
605 break;
608 if( keys['f']) {
609 SDL_WM_ToggleFullScreen( screen);
612 #ifndef MAEMO /* No mouse cursor on Maemo (we have a touchscreen) */
613 if (state == MENU_STATE_MAINMENU || state == MENU_STATE_OPTIONS || state == MENU_STATE_LOCATION) {
614 show_image(GR_CURSOR, mx-2, my-1, 255);
616 #endif
618 /* Draw the "real" mouse coordinates */
619 /*rectangle(mx-1, my-1, 2, 2, 255, 255, 255);*/
621 /* Store the screen, because we are fading after this screen update */
622 /*if (!(mb & SDL_BUTTON(SDL_BUTTON_LEFT)) && btn_hovering != MENU_NONE && mouse_pressed == true) store_screen();*/
624 updatescr();
626 if( mb & SDL_BUTTON(SDL_BUTTON_LEFT)) {
627 if (!mouse_pressed) {
628 play_sample(SOUND_MOUSEOVER);
630 mouse_pressed = true;
631 } else if (mouse_pressed == true) {
632 /* Mouse button released */
633 if (state == MENU_STATE_MAINMENU || state == MENU_STATE_OPTIONS || state == MENU_STATE_LOCATION) {
634 #ifdef HAVE_VOICE_FILES
635 if (btn_hovering == MENU_START) {
636 play_sample(VOICE_LETS_GO);
637 } else {
638 play_sample(SOUND_MOUSECLICK);
640 #else
641 /*play_sample(SOUND_MOUSEOVER);*/
642 #endif
644 if (state == MENU_STATE_MAINMENU) {
645 switch (btn_hovering) {
646 case MENU_START:
647 state = MENU_STATE_SLIDE_TO_LOCATION;
648 break;
649 case MENU_RESUME:
650 state = MENU_STATE_SLIDE_TO_RESUME;
651 break;
652 case MENU_QUIT:
653 state = MENU_STATE_SLIDE_TO_QUIT;
654 break;
656 } else if (state == MENU_STATE_LOCATION) {
657 switch (btn_hovering) {
658 case MENU_START:
659 if (prepared_game->location != NULL) {
660 state = MENU_STATE_FADE_TO_OPTIONS;
662 break;
663 case MENU_QUIT:
664 state = MENU_STATE_SLIDE_TO_MAINMENU;
665 break;
666 default:
667 if (!location_info_visible && highlight_location != -1) {
668 prepared_game->current_location = highlight_location;
669 prepared_game->location = &(locations[prepared_game->current_location]);
670 location_info_xpos = MAX(0, MIN(WIDTH-320-50, mx-320/2));
671 location_info_ypos = MAX(0, MIN(HEIGHT-200-160, my-200/2));
672 location_info_visible = true;
673 } else {
674 location_info_visible = false;
675 highlight_location = -1;
676 prepared_game->current_location = -1;
677 prepared_game->location = NULL;
679 break;
681 } else if (state == MENU_STATE_OPTIONS) {
682 switch (btn_hovering) {
683 case MENU_START:
684 state = MENU_STATE_SLIDE_TO_GAME;
685 break;
686 case MENU_QUIT:
687 state = MENU_STATE_FADE_TO_LOCATION;
688 break;
689 case MENU_PLAYER1:
690 /* advance the input device index */
691 PLAYER(prepared_game, 1).input_device_index++;
692 if (PLAYER(prepared_game, 1).input_device_index == (signed int)input_device_count) {
693 PLAYER(prepared_game, 1).input_device_index = -1;
696 if (input_devices[PLAYER(prepared_game, 1).input_device_index].exclusive_to_player == 2) {
697 PLAYER(prepared_game, 1).input_device_index++;
700 /* determine the selected input device */
701 if (PLAYER(prepared_game, 1).input_device_index == -1) {
702 PLAYER(prepared_game, 1).type = PLAYER_TYPE_AI;
703 PLAYER(prepared_game, 1).input = NULL;
704 btn_player1.text = "Carl Van Court";
705 } else {
706 PLAYER(prepared_game, 1).type = PLAYER_TYPE_HUMAN;
707 PLAYER(prepared_game, 1).input = &(input_devices[PLAYER(prepared_game, 1).input_device_index]);
708 btn_player1.text = input_device_get_name(PLAYER(prepared_game, 1).input);
710 break;
711 case MENU_PLAYER2:
712 /* advance the input device index */
713 PLAYER(prepared_game, 2).input_device_index++;
715 if (input_devices[PLAYER(prepared_game, 2).input_device_index].exclusive_to_player == 1) {
716 PLAYER(prepared_game, 2).input_device_index++;
719 if (PLAYER(prepared_game, 2).input_device_index == (signed int)input_device_count) {
720 PLAYER(prepared_game, 2).input_device_index = -1;
723 /* determine the selected input device */
724 if (PLAYER(prepared_game, 2).input_device_index == -1) {
725 PLAYER(prepared_game, 2).type = PLAYER_TYPE_AI;
726 PLAYER(prepared_game, 2).input = NULL;
727 btn_player2.text = "Carl Van Court";
728 } else {
729 PLAYER(prepared_game, 2).type = PLAYER_TYPE_HUMAN;
730 PLAYER(prepared_game, 2).input = &(input_devices[PLAYER(prepared_game, 2).input_device_index]);
731 btn_player2.text = input_device_get_name(PLAYER(prepared_game, 2).input);
733 break;
736 mouse_pressed = false;
738 i++;
739 #ifdef ENABLE_FPS_LIMIT
740 while (frames*1000.0/((float)(SDL_GetTicks()-ft+1))>(float)(DEFAULT_FPS)) {
741 SDL_Delay(10);
743 frames++;
744 #endif
747 if (current_game != NULL) {
748 if (gamestate_save(current_game, GAMESTATE_FILE) != 0) {
749 fprintf(stderr, "Warning: cannot save gamestate to %s\n", GAMESTATE_FILE);
753 /* Play the credits */
754 intro = create_credits();
755 intro_playback = animation_state_new(intro);
756 animation_state_run(intro_playback, 1);
757 animation_state_free(intro_playback);
758 animation_free(intro);
760 uninit_graphics();
761 uninit_input();
763 SDL_Quit();
764 return 0;
768 void menu_button_init(MenuButton* b)
770 int w, h;
772 if (b->image_id != GR_COUNT) {
774 * If the button is an image, the "w" and "h" attributes of the
775 * MenuButton struct are simply factors with which the real width
776 * and height of the image (=button) should be multiplied and added
777 * to the "x" and "y" position and the "w" and "h" are replaced with
778 * the real size of the image for the collision detection
780 w = b->w;
781 h = b->h;
783 b->w = get_image_width(b->image_id);
784 b->h = get_image_height(b->image_id);
785 b->x += w*b->w;
786 b->y += h*b->h;