Version 1.2.0 with new build/configure system
[tennix.git] / src / tennix.cc
blob9090d43a491eb624b635df58465839e133382e47
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 #include "tennix.h"
31 #include "archive.h"
32 #include "game.h"
33 #include "graphics.h"
34 #include "sound.h"
35 #include "input.h"
36 #include "network.h"
37 #include "util.h"
38 #include "animation.h"
40 #include "locations.h"
42 SDL_Surface *screen;
44 int main( int argc, char** argv) {
45 int i, slide, slide_direction;
46 unsigned int x;
47 Uint32 ticks;
48 int mx, my;
49 unsigned int worldmap_xpos, worldmap_ypos;
50 Uint8 *keys;
51 Uint8 mb;
52 SDL_Event e;
53 int sdl_flags = SDL_SWSURFACE;
54 int btn_hovering = 0, btn_hovering_old = 0;
55 int slide_start;
56 bool mouse_pressed = false;
57 bool quit = false;
58 bool benchmark = false;
59 unsigned int night_start, night_end;
60 GameState *current_game = NULL, *prepared_game = NULL;
61 InputDevice* input_devices;
62 unsigned int input_device_count, input_device_id;
63 Animation *intro;
64 AnimationState *intro_playback;
65 float wiggle;
66 TennixNet* connection = NULL;
67 #ifdef HAVE_SDL_NET
68 char* net_host = NULL;
69 bool net_master = false;
70 #endif /* HAVE_SDL_NET */
71 TennixArchive* tnxar = NULL;
73 MenuButton btn_back = {
74 NULL, /* not needed for image-based button */
75 MENU_OPTIONS_BORDER,
76 HEIGHT-MENU_OPTIONS_BORDER,
77 0, -1, /* width and height will be set by menu_button_init */
78 255, 0, 0,
79 GR_BACK
81 MenuButton btn_start = {
82 NULL, /* not needed for image-based button */
83 WIDTH-MENU_OPTIONS_BORDER,
84 HEIGHT-MENU_OPTIONS_BORDER,
85 -1, -1, /* width and height will be set by menu_button_init */
86 0, 255, 0,
87 GR_FORWARD
89 MenuButton btn_player1 = {
90 NULL,
91 CONTROLLER_SETUP_BORDER,
92 HEIGHT/2 + CONTROLLER_SETUP_SIZE/2 + 10,
93 CONTROLLER_SETUP_SIZE, MENU_OPTIONS_BUTTON_HEIGHT,
94 50, 50, 255,
95 GR_COUNT
97 MenuButton btn_player2 = {
98 NULL,
99 WIDTH-CONTROLLER_SETUP_SIZE-CONTROLLER_SETUP_BORDER,
100 HEIGHT/2 + CONTROLLER_SETUP_SIZE/2 + 10,
101 CONTROLLER_SETUP_SIZE, MENU_OPTIONS_BUTTON_HEIGHT,
102 255, 50, 50,
103 GR_COUNT
106 int highlight_location = -1;
107 float highlight_location_distance = 0.0;
108 float new_location_distance = 0.0;
109 bool location_info_visible = false;
110 unsigned int location_info_xpos = 0, location_info_ypos = 0;
112 const SDL_VideoInfo* vi = NULL;
114 bool do_help = false;
116 int state = MENU_STATE_STARTED;
118 #ifdef ENABLE_FPS_LIMIT
119 Uint32 ft, frames; /* frame timer and frames */
120 #endif
122 fprintf(stderr, "Tennix Classic Championship Tour 2011 (v" VERSION ")\n" COPYRIGHT "\n" URL "\n\n");
124 i = 1;
125 while (i < argc) {
126 /* A poor/lazy man's getopt */
127 #define OPTION_SET(longopt,shortopt) \
128 (strcmp(argv[i], longopt)==0 || strcmp(argv[i], shortopt)==0)
129 #define OPTION_VALUE \
130 ((i+1 < argc)?(argv[i+1]):(NULL))
131 #define OPTION_VALUE_PROCESSED \
132 (i++)
133 if (OPTION_SET("--fullscreen", "-f")) {
134 sdl_flags |= SDL_FULLSCREEN;
136 else if (OPTION_SET("--help", "-h")) {
137 do_help = true;
139 else if (OPTION_SET("--benchmark", "-b")) {
140 benchmark = true;
142 #ifdef HAVE_SDL_NET
143 else if (OPTION_SET("--slave", "-s")) {
144 net_host = OPTION_VALUE;
145 if (OPTION_VALUE != NULL) {
146 OPTION_VALUE_PROCESSED;
147 net_master = false;
148 } else {
149 fprintf(stderr, "Missing option parameter.\n");
150 do_help = true;
151 break;
154 else if (OPTION_SET("--master", "-m")) {
155 net_host = OPTION_VALUE;
156 if (OPTION_VALUE != NULL) {
157 OPTION_VALUE_PROCESSED;
158 net_master = true;
159 } else {
160 fprintf(stderr, "Missing option parameter.\n");
161 do_help = true;
162 break;
165 #endif /* HAVE_SDL_NET */
166 else {
167 fprintf(stderr, "Unknown option: %s\n", argv[i]);
168 do_help = true;
170 i++;
173 if (do_help == true) {
174 fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
175 " Where [OPTIONS] are zero or more of the following:\n\n"
176 " [--fullscreen|-f] Fullscreen mode\n"
177 " [--benchmark|-b] Run in benchmark/attract mode\n"
178 #ifdef HAVE_SDL_NET
179 " [--master|-m <IP-of-slave>] Network play as master\n"
180 " [--slave|-s <IP-of-master>] Network play as slave\n"
181 #endif /* HAVE_SDL_NET */
182 " [--help|-h] Show help information\n\n"
183 " See tennix(6) for details.\n", argv[0]);
184 return 0;
187 if (benchmark) {
188 srand(100);
189 } else {
190 srand((unsigned)time(NULL));
193 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) == -1) {
194 fprintf( stderr, "Can't init SDL: %s\n", SDL_GetError());
195 exit( 1);
198 vi = SDL_GetVideoInfo();
199 if( (screen = SDL_SetVideoMode( WIDTH, HEIGHT, vi->vfmt->BitsPerPixel, sdl_flags)) == NULL) {
200 fprintf( stderr, "Can't set video mode: %s\n", SDL_GetError());
201 exit( 1);
204 SDL_WM_SetCaption( "Tennix Classic Championship Tour 2011", "Tennix 2011");
205 SDL_ShowCursor( SDL_DISABLE);
206 SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, 1);
208 tnxar = new TennixArchive(ARCHIVE_FILE, ARCHIVE_FILE_INSTALLED);
209 init_graphics(*tnxar);
210 init_sound(*tnxar);
211 init_input(*tnxar);
212 #ifdef HAVE_SDL_NET
213 init_network();
214 #endif /* HAVE_SDL_NET */
215 delete tnxar;
217 #ifdef HAVE_SDL_NET
218 if (net_host != NULL) {
219 connection = network_connect(net_host, net_master);
221 #endif /* HAVE_SDL_NET */
223 menu_button_init(&btn_back);
224 menu_button_init(&btn_start);
225 menu_button_init(&btn_player1);
226 menu_button_init(&btn_player2);
228 input_devices = find_input_devices(&input_device_count);
230 current_game = gamestate_load(GAMESTATE_FILE);
231 if (current_game != NULL) {
232 /* restore pointer to location */
233 current_game->location = &(locations[current_game->current_location]);
234 /* */
235 for (i=1; i<=MAXPLAYERS; i++) {
236 if (PLAYER(current_game, i).type == PLAYER_TYPE_HUMAN) {
237 input_device_id = PLAYER(current_game, i).input_device_index;
238 if (input_device_id < input_device_count) {
239 /* ok, we still have that device around */
240 PLAYER(current_game, i).input = &(input_devices[input_device_id]);
241 } else {
242 /* the device vanished - set to AI (FIXME: select new device) */
243 PLAYER(current_game, i).type = PLAYER_TYPE_AI;
244 PLAYER(current_game, i).input = NULL;
250 #ifdef ENABLE_FPS_LIMIT
251 frames = 0;
252 ft = SDL_GetTicks();
253 #endif
255 if (benchmark) {
256 GameState* g = gamestate_new();
257 PLAYER(g, 1).type = PLAYER_TYPE_AI;
258 PLAYER(g, 2).type = PLAYER_TYPE_AI;
259 g->location = &(locations[0]);
260 gameloop(g, connection);
261 free(g);
262 exit(0);
265 /*intro = create_intro();
266 intro_playback = animation_state_new(intro);
267 animation_state_run(intro_playback, 1);
268 animation_state_free(intro_playback);
269 animation_free(intro);
270 start_fade();*/
272 worldmap_xpos = (WIDTH-get_image_width(GR_WORLDMAP))/2;
273 worldmap_ypos = (HEIGHT-get_image_height(GR_WORLDMAP))/2;
275 i = 0;
276 /* Sliding initialization */
277 ticks = SDL_GetTicks();
278 slide = slide_start = get_image_width(GR_SIDEBAR);
279 slide_direction = 0;
280 while(!quit) {
281 /* State transitions */
282 switch (state) {
283 case MENU_STATE_STARTED:
284 state = MENU_STATE_SLIDE_TO_MAINMENU;
285 break;
286 case MENU_STATE_SLIDE_TO_MAINMENU:
287 clear_screen();
288 //rectangle(0, 0, WIDTH, HEIGHT, 80, 80, 80);
289 store_screen();
290 slide = slide_start;
291 slide_direction = -1;
292 state = MENU_STATE_SLIDE_TO_MAINMENU_IN_PROGRESS;
293 break;
294 case MENU_STATE_SLIDE_TO_MAINMENU_IN_PROGRESS:
295 if (slide == 0) {
296 slide_direction = 0;
297 state = MENU_STATE_MAINMENU;
299 break;
300 case MENU_STATE_MAINMENU:
301 free(prepared_game);
302 prepared_game = NULL;
303 break;
304 case MENU_STATE_SLIDE_TO_LOCATION:
305 slide = 1;
306 slide_direction = 3;
307 state = MENU_STATE_SLIDE_TO_LOCATION_IN_PROGRESS;
308 break;
309 case MENU_STATE_SLIDE_TO_LOCATION_IN_PROGRESS:
310 if (slide == slide_start) {
311 state = MENU_STATE_FADE_TO_LOCATION;
313 break;
314 case MENU_STATE_FADE_TO_LOCATION:
315 start_fade();
316 state = MENU_STATE_LOCATION;
317 clear_screen();
319 //rectangle(0, 0, WIDTH, HEIGHT, 80, 80, 80);
320 /* Draw and store the worldmap with day/night times */
321 show_image(GR_WORLDMAP, WIDTH/2-get_image_width(GR_WORLDMAP)/2, HEIGHT/2-get_image_height(GR_WORLDMAP)/2, 255);
322 day_night(get_image_width(GR_WORLDMAP), &night_start, &night_end);
323 if (night_start > night_end) {
324 rectangle_alpha(worldmap_xpos, worldmap_ypos, night_end, get_image_height(GR_WORLDMAP), 0, 0, 0, 150);
325 rectangle_alpha(worldmap_xpos+night_start, worldmap_ypos, get_image_width(GR_WORLDMAP)-night_start, get_image_height(GR_WORLDMAP), 0, 0, 0, 150);
326 } else {
327 rectangle_alpha(worldmap_xpos+night_start, worldmap_ypos, night_end-night_start, get_image_height(GR_WORLDMAP), 0, 0, 0, 150);
330 /* add misc items to screen */
331 font_draw_string(FONT_XLARGE, "Pick a location", (WIDTH-font_get_string_width(FONT_XLARGE, "Pick a location"))/2, 20);
333 store_screen();
334 break;
335 case MENU_STATE_FADE_TO_OPTIONS:
336 start_fade();
337 clear_screen();
338 //rectangle(0, 0, WIDTH, HEIGHT, 80, 80, 80);
339 rectangle(CONTROLLER_SETUP_BORDER, HEIGHT/2-CONTROLLER_SETUP_SIZE/2, CONTROLLER_SETUP_SIZE, CONTROLLER_SETUP_SIZE, 150, 150, 150);
340 rectangle(WIDTH-CONTROLLER_SETUP_BORDER-CONTROLLER_SETUP_SIZE, (HEIGHT-CONTROLLER_SETUP_SIZE)/2, CONTROLLER_SETUP_SIZE, CONTROLLER_SETUP_SIZE, 150, 150, 150);
341 font_draw_string(FONT_XLARGE, "Controller setup", (WIDTH-font_get_string_width(FONT_XLARGE, "Controller setup"))/2, 20);
342 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));
343 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));
344 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));
345 store_screen();
346 start_fade();
347 state = MENU_STATE_OPTIONS;
348 break;
349 case MENU_STATE_LOCATION:
350 case MENU_STATE_OPTIONS:
351 /* Prepare a new game */
352 if (prepared_game == NULL) {
353 prepared_game = gamestate_new();
354 prepared_game->location = NULL;
355 /* FIXME - this should not be written here, but taken from the input devices */
356 btn_player1.text = "Keyboard (arrows)";
357 btn_player2.text = "Carl Van Court";
358 PLAYER(prepared_game, 1).input_device_index = 2;
359 PLAYER(prepared_game, 1).type = PLAYER_TYPE_HUMAN;
360 PLAYER(prepared_game, 1).input = &(input_devices[PLAYER(prepared_game, 1).input_device_index]);
361 location_info_visible = false;
362 prepared_game->current_location = -1;
363 highlight_location = -1;
365 break;
366 case MENU_STATE_SLIDE_TO_GAME:
367 /*slide = 1;
368 slide_direction = 2;
369 state = MENU_STATE_SLIDE_TO_GAME_IN_PROGRESS;
370 break;
371 case MENU_STATE_SLIDE_TO_GAME_IN_PROGRESS:
372 if (slide == slide_start) {
373 state = MENU_STATE_GAME;
375 state = MENU_STATE_GAME;
376 break;
377 case MENU_STATE_SLIDE_TO_RESUME:
378 slide = 1;
379 slide_direction = 2;
380 state = MENU_STATE_SLIDE_TO_RESUME_IN_PROGRESS;
381 break;
382 case MENU_STATE_SLIDE_TO_RESUME_IN_PROGRESS:
383 if (slide == slide_start) {
384 state = MENU_STATE_RESUME;
386 break;
387 case MENU_STATE_GAME:
388 if (prepared_game == NULL) {
389 fprintf(stderr, "Game not yet prepared!\n");
390 exit(EXIT_FAILURE);
393 /* Cancel a possibly started game */
394 free(current_game);
395 current_game = prepared_game;
396 prepared_game = NULL;
397 /* no break - we are continuing with "resume" */
398 case MENU_STATE_RESUME:
399 if (current_game == NULL) {
400 fprintf(stderr, "Cannot resume game!\n");
401 exit(EXIT_FAILURE);
403 start_fade();
404 gameloop(current_game, connection);
405 SDL_Delay(150);
406 while (SDL_PollEvent(&e)) {};
407 #ifdef ENABLE_FPS_LIMIT
408 frames = 0;
409 ft = SDL_GetTicks();
410 #endif
411 start_fade();
412 state = MENU_STATE_SLIDE_TO_MAINMENU;
413 break;
414 case MENU_STATE_SLIDE_TO_QUIT:
415 slide = 1;
416 slide_direction = 3;
417 state = MENU_STATE_SLIDE_TO_QUIT_IN_PROGRESS;
418 break;
419 case MENU_STATE_SLIDE_TO_QUIT_IN_PROGRESS:
420 if (slide == slide_start) {
421 state = MENU_STATE_QUIT;
423 break;
424 case MENU_STATE_QUIT:
425 quit = true;
426 break;
427 default:
428 fprintf(stderr, "State error: %d\n", state);
429 exit(EXIT_FAILURE);
432 /* Sliding */
433 if (SDL_GetTicks() > ticks + 20) {
434 if (slide >= 1 && slide <= slide_start) {
435 slide += slide_direction+(slide_direction*slide/(sqrt(2*slide)));
436 slide = MAX(0, MIN(slide_start, slide));
437 } else if (slide_direction != 0) {
438 slide_direction = 0;
440 ticks = SDL_GetTicks();
443 /* Graphics */
444 #ifdef DEBUG
445 if (state != MENU_STATE_OPTIONS) {
446 fill_image_offset(GR_FOG, 0, 0, WIDTH, HEIGHT, -i, 0);
448 #endif
449 show_image(GR_SIDEBAR, WIDTH-get_image_width(GR_SIDEBAR)+slide, 0, 255);
450 show_image(GR_TENNIXLOGO, WIDTH-get_image_width(GR_SIDEBAR)-10, 20-slide, 255);
451 if (state != MENU_STATE_OPTIONS && state != MENU_STATE_LOCATION) {
452 /* Main Menu */
453 show_image(GR_BTN_PLAY, WIDTH-get_image_width(GR_BTN_PLAY)+slide+(slide/7)+3-(3*(btn_hovering==MENU_START)), 150, 255);
454 if (current_game != NULL) {
455 show_image(GR_BTN_RESUME, WIDTH-get_image_width(GR_BTN_RESUME)+slide+(slide/7)+3-(3*(btn_hovering==MENU_RESUME)), 230, 255);
456 font_draw_string(FONT_SMALL, "match paused", 10, 10);
457 } else {
458 font_draw_string(FONT_MEDIUM, "Tennix Classic Championship Tour 2011", 10, 10);
460 //font_draw_string_color(FONT_MEDIUM, URL, 10-1, HEIGHT-10-1-font_get_height(FONT_MEDIUM), 130, 130, 130);
461 font_draw_string_color(FONT_MEDIUM, URL, 10, HEIGHT-10-font_get_height(FONT_MEDIUM), 100, 100, 100);
462 show_image(GR_BTN_QUIT, WIDTH-get_image_width(GR_BTN_QUIT)+slide+(slide/7)+3-(3*(btn_hovering==MENU_QUIT)), 350, 255);
463 } else if (state == MENU_STATE_OPTIONS) {
464 /* Options screen */
465 draw_button_object(&btn_back, mx, my);
466 draw_button_object(&btn_start, mx, my);
467 draw_button_object(&btn_player1, mx, my);
468 draw_button_object(&btn_player2, mx, my);
469 wiggle = 15*sinf((float)ticks/300.);
470 if (PLAYER(prepared_game, 1).input_device_index > -1) {
471 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);
472 } else {
473 show_image_rotozoom(GR_INPUT_AI, CONTROLLER_SETUP_BORDER + CONTROLLER_SETUP_SIZE/2, HEIGHT/2, wiggle, 1.0);
475 if (PLAYER(prepared_game, 2).input_device_index > -1) {
476 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);
477 } else {
478 show_image_rotozoom(GR_INPUT_AI, WIDTH-CONTROLLER_SETUP_BORDER-CONTROLLER_SETUP_SIZE/2, HEIGHT/2, -wiggle, 1.0);
480 } else if (state == MENU_STATE_LOCATION) {
481 /* Location selection screen */
482 for (x=0; x<location_count(); x++) {
483 new_location_distance = SQUARE_DISTANCE(mx-worldmap_xpos-locations[x].worldmap_x,
484 my-worldmap_ypos-locations[x].worldmap_y);
485 if (highlight_location == -1) {
486 if (new_location_distance < 20*20) {
487 highlight_location = x;
489 } else {
490 highlight_location_distance = SQUARE_DISTANCE(mx-worldmap_xpos-locations[highlight_location].worldmap_x,
491 my-worldmap_ypos-locations[highlight_location].worldmap_y);
492 if (highlight_location_distance > 20*20) {
493 highlight_location = -1;
495 if (highlight_location_distance > new_location_distance && new_location_distance < 20*20) {
496 highlight_location = x;
500 if (prepared_game != NULL) {
501 if (!location_info_visible) {
502 for (x=0; x<location_count(); x++) {
503 /* draw rectangle for location at "x"*/
504 if (highlight_location != -1 && (unsigned int)highlight_location == x) {
505 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));
508 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);
510 } else {
511 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);
512 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);
513 font_draw_string(FONT_SMALL, prepared_game->location->name, location_info_xpos+MENU_OPTIONS_BORDER, location_info_ypos+MENU_OPTIONS_BORDER+200);
514 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));
515 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));
516 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));
518 if (prepared_game->location != NULL) {
519 draw_button_object(&btn_start, mx, my);
522 draw_button_object(&btn_back, mx, my);
525 SDL_PollEvent( &e);
526 if( e.type == SDL_QUIT) {
527 state = MENU_STATE_SLIDE_TO_QUIT;
528 /*break;*/
531 keys = SDL_GetKeyState( NULL);
532 mb = SDL_GetMouseState( &mx, &my);
534 btn_hovering_old = btn_hovering;
535 if (state == MENU_STATE_MAINMENU) {
536 btn_hovering = M_POS_DECODE(mx, my);
537 if (current_game == NULL) {
538 btn_hovering &= ~MENU_RESUME;
540 } else if (state == MENU_STATE_LOCATION) {
541 if (M_POS_BUTTON(btn_back, mx, my)) {
542 btn_hovering = MENU_QUIT;
543 } else if (M_POS_BUTTON(btn_start, mx, my)) {
544 btn_hovering = MENU_START;
545 } else {
546 btn_hovering = 0;
548 } else if (state == MENU_STATE_OPTIONS) {
549 if (M_POS_BUTTON(btn_back, mx, my)) {
550 btn_hovering = MENU_QUIT;
551 } else if (M_POS_BUTTON(btn_start, mx, my)) {
552 btn_hovering = MENU_START;
553 } else if (M_POS_BUTTON(btn_player1, mx, my)) {
554 btn_hovering = MENU_PLAYER1;
555 } else if (M_POS_BUTTON(btn_player2, mx, my)) {
556 btn_hovering = MENU_PLAYER2;
557 } else {
558 btn_hovering = 0;
560 } else {
561 /* No menu screen - no hovering. */
562 btn_hovering = 0;
564 if (btn_hovering_old != btn_hovering && btn_hovering != 0) {
565 #ifdef HAVE_VOICE_FILES
566 if (btn_hovering == MENU_QUIT) {
567 play_sample(VOICE_QUIT_IT);
568 } else if (btn_hovering == MENU_START) {
569 play_sample(VOICE_NEW_GAME);
570 } else {
571 play_sample(SOUND_MOUSEOVER);
573 #else
574 play_sample(SOUND_MOUSEOVER);
575 #endif
578 if( keys[SDLK_ESCAPE] || keys['q']) {
579 /* FIXME: do the state thingie! */
580 break;
583 if( keys['f']) {
584 SDL_WM_ToggleFullScreen( screen);
587 if (state == MENU_STATE_MAINMENU || state == MENU_STATE_OPTIONS || state == MENU_STATE_LOCATION) {
588 show_image(GR_CURSOR, mx-2, my-1, 255);
591 /* Draw the "real" mouse coordinates */
592 /*rectangle(mx-1, my-1, 2, 2, 255, 255, 255);*/
594 /* Store the screen, because we are fading after this screen update */
595 /*if (!(mb & SDL_BUTTON(SDL_BUTTON_LEFT)) && btn_hovering != MENU_NONE && mouse_pressed == true) store_screen();*/
597 updatescr();
599 if( mb & SDL_BUTTON(SDL_BUTTON_LEFT)) {
600 if (!mouse_pressed) {
601 play_sample(SOUND_MOUSEOVER);
603 mouse_pressed = true;
604 } else if (mouse_pressed == true) {
605 /* Mouse button released */
606 if (state == MENU_STATE_MAINMENU || state == MENU_STATE_OPTIONS || state == MENU_STATE_LOCATION) {
607 #ifdef HAVE_VOICE_FILES
608 if (btn_hovering == MENU_START) {
609 play_sample(VOICE_LETS_GO);
610 } else {
611 play_sample(SOUND_MOUSECLICK);
613 #else
614 /*play_sample(SOUND_MOUSEOVER);*/
615 #endif
617 if (state == MENU_STATE_MAINMENU) {
618 switch (btn_hovering) {
619 case MENU_START:
620 state = MENU_STATE_SLIDE_TO_LOCATION;
621 break;
622 case MENU_RESUME:
623 state = MENU_STATE_SLIDE_TO_RESUME;
624 break;
625 case MENU_QUIT:
626 state = MENU_STATE_SLIDE_TO_QUIT;
627 break;
629 } else if (state == MENU_STATE_LOCATION) {
630 switch (btn_hovering) {
631 case MENU_START:
632 if (prepared_game->location != NULL) {
633 state = MENU_STATE_FADE_TO_OPTIONS;
635 break;
636 case MENU_QUIT:
637 state = MENU_STATE_SLIDE_TO_MAINMENU;
638 break;
639 default:
640 if (!location_info_visible && highlight_location != -1) {
641 prepared_game->current_location = highlight_location;
642 /* Set the day/night status */
643 if (night_start < night_end) {
644 locations[prepared_game->current_location].night = (locations[prepared_game->current_location].worldmap_x > night_start && locations[prepared_game->current_location].worldmap_x < night_end);
645 } else {
646 locations[prepared_game->current_location].night = (locations[prepared_game->current_location].worldmap_x < night_end || locations[prepared_game->current_location].worldmap_x > night_start);
648 prepared_game->location = &(locations[prepared_game->current_location]);
649 location_info_xpos = MAX(0, MIN(WIDTH-320-50, mx-320/2));
650 location_info_ypos = MAX(0, MIN(HEIGHT-200-160, my-200/2));
651 location_info_visible = true;
652 } else {
653 location_info_visible = false;
654 highlight_location = -1;
655 prepared_game->current_location = -1;
656 prepared_game->location = NULL;
658 break;
660 } else if (state == MENU_STATE_OPTIONS) {
661 switch (btn_hovering) {
662 case MENU_START:
663 state = MENU_STATE_SLIDE_TO_GAME;
664 break;
665 case MENU_QUIT:
666 state = MENU_STATE_FADE_TO_LOCATION;
667 break;
668 case MENU_PLAYER1:
669 /* advance the input device index */
670 PLAYER(prepared_game, 1).input_device_index++;
671 if (PLAYER(prepared_game, 1).input_device_index == (signed int)input_device_count) {
672 PLAYER(prepared_game, 1).input_device_index = -1;
675 if (input_devices[PLAYER(prepared_game, 1).input_device_index].exclusive_to_player == 2) {
676 PLAYER(prepared_game, 1).input_device_index++;
679 /* determine the selected input device */
680 if (PLAYER(prepared_game, 1).input_device_index == -1) {
681 PLAYER(prepared_game, 1).type = PLAYER_TYPE_AI;
682 PLAYER(prepared_game, 1).input = NULL;
683 btn_player1.text = "Carl Van Court";
684 } else {
685 PLAYER(prepared_game, 1).type = PLAYER_TYPE_HUMAN;
686 PLAYER(prepared_game, 1).input = &(input_devices[PLAYER(prepared_game, 1).input_device_index]);
687 btn_player1.text = input_device_get_name(PLAYER(prepared_game, 1).input);
689 break;
690 case MENU_PLAYER2:
691 /* advance the input device index */
692 PLAYER(prepared_game, 2).input_device_index++;
694 if (input_devices[PLAYER(prepared_game, 2).input_device_index].exclusive_to_player == 1) {
695 PLAYER(prepared_game, 2).input_device_index++;
698 if (PLAYER(prepared_game, 2).input_device_index == (signed int)input_device_count) {
699 PLAYER(prepared_game, 2).input_device_index = -1;
702 /* determine the selected input device */
703 if (PLAYER(prepared_game, 2).input_device_index == -1) {
704 PLAYER(prepared_game, 2).type = PLAYER_TYPE_AI;
705 PLAYER(prepared_game, 2).input = NULL;
706 btn_player2.text = "Carl Van Court";
707 } else {
708 PLAYER(prepared_game, 2).type = PLAYER_TYPE_HUMAN;
709 PLAYER(prepared_game, 2).input = &(input_devices[PLAYER(prepared_game, 2).input_device_index]);
710 btn_player2.text = input_device_get_name(PLAYER(prepared_game, 2).input);
712 break;
715 mouse_pressed = false;
717 i++;
718 #ifdef ENABLE_FPS_LIMIT
719 while (frames*1000.0/((float)(SDL_GetTicks()-ft+1))>(float)(DEFAULT_FPS)) {
720 SDL_Delay(10);
722 frames++;
723 #endif
726 if (current_game != NULL) {
727 if (gamestate_save(current_game, GAMESTATE_FILE) != 0) {
728 fprintf(stderr, "Warning: cannot save gamestate to %s\n", GAMESTATE_FILE);
732 /* Play the credits */
733 intro = create_credits();
734 intro_playback = animation_state_new(intro);
735 animation_state_run(intro_playback, 1);
736 animation_state_free(intro_playback);
737 animation_free(intro);
739 uninit_graphics();
740 uninit_input();
741 #ifdef HAVE_SDL_NET
742 uninit_network();
743 #endif /* HAVE_SDL_NET */
745 SDL_Quit();
746 return 0;
750 void menu_button_init(MenuButton* b)
752 int w, h;
754 if (b->image_id != GR_COUNT) {
756 * If the button is an image, the "w" and "h" attributes of the
757 * MenuButton struct are simply factors with which the real width
758 * and height of the image (=button) should be multiplied and added
759 * to the "x" and "y" position and the "w" and "h" are replaced with
760 * the real size of the image for the collision detection
762 w = b->w;
763 h = b->h;
765 b->w = get_image_width(b->image_id);
766 b->h = get_image_height(b->image_id);
767 b->x += w*b->w;
768 b->y += h*b->h;