/*
* Copyright (c) 2008-2010 Bertrand Janin <tamentis@neopulsar.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <time.h>
#ifdef __WII__
# include <fat.h>
#endif
#include "SDL.h"
#include "rezerwar.h"
#include "config.h"
Board *board;
Configuration *conf;
SDL_Surface *screen;
SDL_Surface *sprites;
Uint32 key;
/**
* Fade the initial studio screen.
*/
void
intro_studio(void)
{
SDL_Surface *intro;
char *path;
int x;
path = dpath("gfx/tdc.bmp");
intro = SDL_LoadBMP(path);
r_free(path);
if (intro == NULL)
fatal("Unable to load tdc intro image.");
x = gfx_fadein(intro, 4);
if (x == 0)
x = cancellable_delay(1);
gfx_free(intro);
}
/**
* Check for the presence of an cmd line flag.
*/
bool
has_flag(int ac, char **av, char *flag)
{
int i;
if (ac <= 1)
return false;
for (i = 0; i < ac; i++) {
if (strcmp(av, flag) == 0)
return true;
}
return false;
}
/**
* Configuration constructor.
*/
void
init_conf(int ac, char **av)
{
conf = r_malloc(sizeof(Configuration));
conf->current_level = NULL;
conf->next_level = NULL;
conf->sound = true;
conf->fullscreen = has_flag(ac, av, "-f");
}
/**
* This is the game loop, it is called whenever a game has to be started,
* it will instanciate a board and return when the game is over.
*/
int
game_loop(char *levelname, enum ttype trans)
{
Level *level;
uint32_t start, // when the game loop starts
now, // time at the start of each loops
framecount = 0, // nr of frame drawn in this TICK
lastframe = 0, // whenever the last frame was drawn
lastfps = 0; // whenever the last fps was drawn
int elapsed; // how long did the loop take
char fpsbuf[16]; // temp char* for the fps
enum mtype status = 0; // current mode (menu, game, etc..)
SDL_Event event; // last loop event
sfx_play_music("music/level1.ogg");
/*
* Without explicit level name, start the board with 4 lines of cubes
* and two moles.
*/
if (levelname == NULL) {
board = board_new();
board_prepopulate(board, 4);
/* With a level name, load everything from the level. */
} else {
level = lvl_load(levelname);
board = board_new_from_level(level);
/* lvl_dump(level); */
lvl_kill(level);
}
board->transition = trans;
board_load_next_cube(board);
board_launch_next_cube(board);
/*
* Main loop, every TICK (~10ms)
* - poll events and handle them, updating the game internals if needed.
* - go through the normal internal updates (not event-related).
* - draw the screen according to MAXFPS
* - wait whatever is left to get to a 10ms TICK.
*/
start = SDL_GetTicks();
while (status == MTYPE_NOP) {
while (SDL_PollEvent(&event)) {
status = handle_events(&event);
}
/* If a user event triggered a loop exit, do it now */
if (status != MTYPE_NOP)
break;
now = SDL_GetTicks();
status = board_update(board, now);
if (status != MTYPE_NOP)
break;
/* Print FPS... every seconds. */
if (now - lastfps > 1000) {
if (board->show_fps) {
snprintf(fpsbuf, 16, "FPS: %u\n", framecount);
text_set_value(board->fps_t, fpsbuf);
} else {
text_set_value(board->fps_t, "");
}
lastfps = now;
framecount = 0;
}
/* Every 1.0 / MAXFPS seconds, refresh the screen. */
if (lastframe < (now - (1000/MAXFPS))) {
framecount++;
lastframe = now;
board_render(board);
}
elapsed = SDL_GetTicks() - now;
if (elapsed < TICK) {
SDL_Delay(TICK - elapsed);
}
}
board_kill(board);
sfx_stop_music();
return status;
}
/**
* Return whether the user requested sound to run or not.
*/
bool
need_audio(int ac, char **av)
{
return !has_flag(ac, av, "-q");
}
/**
* Run when the user instanciate the executable with -h.
*/
void
help(const char *progname)
{
printf("usage: %s [-hvqf] levelfile\n", progname);
printf(" -h This help screen\n");
printf(" -v Just version number\n");
printf(" -q Quiet, no sound\n");
printf(" -f Fullscreen\n");
}
/**
* Big bang.
*/
int
main(int ac, char **av)
{
int status = MTYPE_SUBMENU;
bool loop = true;
char *path;
SDL_Joystick *js;
/* Version number only */
if (has_flag(ac, av, "-v")) {
printf("%s\n", VERSION);
return 0;
}
/* Help request */
if (has_flag(ac, av, "-h") || has_flag(ac, av, "--help") ||
has_flag(ac, av, "-help")) {
help(av[0]);
return 0;
}
/* Load the sprites first, avoid running init if something is fishy */
path = dpath("gfx/sprites.bmp");
sprites = SDL_LoadBMP(path);
if (sprites == NULL)
fatal("Unable to load the sprites, did you install rezerwar properly?");
SDL_SetColorKey(sprites, SDL_SRCCOLORKEY|SDL_RLEACCEL,
SDL_MapRGB(sprites->format, 0, 255, 255));
r_free(path);
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) != 0)
fatal("Unable to initialize SDL: %s\n", SDL_GetError());
SDL_JoystickEventState(SDL_ENABLE);
js = SDL_JoystickOpen(0);
#ifdef __WII__
fatInitDefault();
#endif
SDL_EnableUNICODE(1);
init_conf(ac, av);
gfx_init();
/* Initialize the cube randomizer */
cube_init_rmap();
atexit(SDL_Quit);
/* Seed rand, load the sprites and set the alpha. */
srand(time(NULL));
key = SDL_MapRGB(screen->format, 0, 255, 255);
SDL_WM_SetCaption(VERSION, NULL);
#ifdef WITH_SOUND
if (need_audio(ac, av))
sfx_init();
sfx_load_library();
sfx_play_horn();
#endif
/* DEBUG */
// return game_loop(NULL, 0);
// return game_loop("tuto_09", 0);
/* Normal flow... */
intro_studio();
/* Loop between game and menu as long as no "quit" was selected. */
do {
switch (status) {
case MTYPE_BREAK:
case MTYPE_SUBMENU:
status = main_menu();
break;
case MTYPE_NEXTLEVEL:
r_free(conf->current_level);
conf->current_level = r_strcp(conf->next_level);
status = game_loop(conf->next_level, TTYPE_NONE);
break;
case MTYPE_REPLAY:
status = game_loop(conf->current_level, TTYPE_NONE);
break;
case MTYPE_GAMEOVER_WIN:
status = gameover_menu(status);
break;
case MTYPE_GAMEOVER_LOSE:
status = gameover_menu(status);
break;
case MTYPE_GAMEOVER_TIMEOUT:
status = gameover_menu(status);
break;
case MTYPE_GAMEOVER_HISCORE:
status = hiscore_prompt();
break;
case MTYPE_HISCORES:
status = MTYPE_SUBMENU;
hiscore_show();
break;
case MTYPE_QUIT:
loop = false;
break;
case MTYPE_PLAIN:
gfx_shutter_close();
status = game_loop(NULL, TTYPE_SHUTTER_OPEN);
break;
case MTYPE_START:
gfx_shutter_close();
r_free(conf->current_level);
conf->current_level = r_strcp("tuto_01");
status = game_loop(conf->current_level, TTYPE_SHUTTER_OPEN);
break;
}
} while (loop);
/* Death and cleanup */
SDL_FreeSurface(sprites);
sfx_unload_library();
sfx_kill();
hiscore_free();
r_free(conf->next_level);
r_free(conf);
r_checkmem();
return 0;
}