/* $Id: game.c,v 1.88 2004/06/16 00:41:29 stpohle Exp $ 
  game.c - procedures for the game. */

#include <string.h>
#include <SDL.h>

#include "bomberclone.h"
#include "gfx.h"
#include "network.h"
#include "packets.h"
#include "chat.h"
#include "flyingitems.h"
#include "menu.h"
#include "keyb.h"
#include "single.h"

extern int blitdb_nr,
  blitrects_nr;

Uint32 game_timediff, game_timediff1;
static float hurrywarn_to;
static int hurrywarn_state;
static _menu *menu;

void
game_draw_info ()
{
    int i,
      x,
      j,
	  col;
    char text[255];
    char scrtext[255];
    SDL_Rect src,
      dest;

    if (GT_MP && (chat.oldscreen == NULL || chat.window.x != 4 || chat.window.y != 4.5*16)) {
		chat_show (4, 4.5*16, gfx.res.x - 8, gfx.offset.y - 4.5*16);
		chat_setactive (0, 0);
	}

	
    if (bman.updatestatusbar) {
        redraw_logo (0, 0, gfx.res.x, (4.5 * 16));
        dest.x = dest.y = 0;
        dest.h = 4.5 *16;
        dest.w = gfx.res.x;
        gfx_blitupdaterectadd (&dest);

        bman.players_nr = 0;

        /* In Multiplayer mode draw Player names and 
           count the players who are still alife. */
        for (x = 0, j = 0, i = 0; i < MAX_PLAYERS; i++)
            if ((players[i].state & PSFM_used) != 0) {

                if (players[i].gfx_nr != -1 && PS_IS_used (players[i].state)) {
                    src.x = 3 * players[i].gfx->smal_size.x;
                    src.y = 0;
                    src.w = dest.w = players[i].gfx->smal_size.x;
                    src.h = dest.h = players[i].gfx->smal_size.y;

                    dest.x = x;
                    dest.y = j - 4;

                    SDL_BlitSurface (players[i].gfx->smal_image, &src, gfx.screen, &dest);
                }

                sprintf (scrtext, "%10s:%2d", players[i].name, players[i].points);
                if (!PS_IS_alife (players[i].state)) { // Player is dead
                    if ((players[i].state & PSF_used) != PSF_used)
						col = 4;
                    else
                        col = 3;
                }
                else {          // players is alife
					col = 0;
                    bman.players_nr++;
                }

                font_draw (x, j, scrtext, 0, col);

                x = x + 170;
                if (x >= gfx.res.x - (120 + 170)) {
                    x = 0;
                    j = j + 1.5 * font[0].size.x;
                }
            }

        x = gfx.res.x - 120;
        sprintf (text, "Bombs: %2d", players[bman.p_nr].bombs_n);
        font_draw (x, 0, text, 0, 0);
        sprintf (text, "Range: %2d", players[bman.p_nr].range);
        font_draw (x, 16, text, 0, 0);
        sprintf (text, "Speed: %1.1f", players[bman.p_nr].speed*10);
        font_draw (x, 32, text, 0, 0);
        if (players[bman.p_nr].special.type != 0) {
            dest.x = x - 32;
            dest.y = 16;
            dest.w = gfx.smal_special[players[bman.p_nr].special.type - 1]->w;
            dest.h = gfx.smal_special[players[bman.p_nr].special.type - 1]->h;

            SDL_BlitSurface (gfx.smal_special[players[bman.p_nr].special.type - 1], NULL,
                             gfx.screen, &dest);
        }

        if (bman.state == GS_ready && GT_MP_PTPM)
            font_gfxdraw (100, 32, "Press F4 to start the game", 0, COLOR_yellow, 0xFFFF);
        else if (bman.state == GS_ready)
            font_gfxdraw (100, 32, "Waiting for the Server to Start", 0, COLOR_yellow, 0xFFFF);
		
    }

	/* draw the warning part */
	if (map.state != MS_normal) {
		hurrywarn_to -= timediff;
		
		if (bman.updatestatusbar || hurrywarn_to <= 0.0 || hurrywarn_to > HURRYWARN_TO_BLINKING) {
			hurrywarn_to = HURRYWARN_TO_BLINKING;			
			hurrywarn_state = !hurrywarn_state;
			
			if (hurrywarn_state) {
				font_drawbold ((gfx.res.x - strlen ("HURRY HURRY")*font[1].size.x)/2, 40, "HURRY HURRY", 1, 0, 2);
				font_draw ((gfx.res.x - strlen ("HURRY HURRY")*font[1].size.x)/2, 40, "HURRY HURRY", 1, 1);
			}
			else {
				font_drawbold ((gfx.res.x - strlen ("HURRY HURRY")*font[1].size.x)/2, 40, "HURRY HURRY", 1, 1, 2);
				font_draw ((gfx.res.x - strlen ("HURRY HURRY")*font[1].size.x)/2, 40, "HURRY HURRY", 1, 0);
			}
	        dest.x = dest.y = 0;
    	    dest.h = 4.5 *16;
        	dest.w = gfx.res.x;
        	gfx_blitupdaterectadd (&dest);
		}
	}
	
	if (debug) 
		debug_ingameinfo();

    bman.updatestatusbar = 0;
};


/*
 * keyboard handling for keys which have nothing to do with the playerkeys
 * before calling this function make sure keyb_loop (); was called.
 *
 * chat mode: the chatmode should only be disabled in the game mode
 *   in the GS_wait mode the chat will always be active.
 */
void game_keys_loop () {
	
	if (menu != NULL) {

		/* delete all movement keys */

		int i;
		for (i = 0; i < BCPK_max * 2; i++)
			keyb_gamekeys.state[i] = 0;
	}
	else {
		
		/* don't go into the game_keys if there is no menu displayed */

		if (GT_MP_PTPM && bman.state == GS_ready && keyb_gamekeys.state[BCK_pause]  && !keyb_gamekeys.old[BCK_pause]) {
			/* Server is starting the game */
            bman.state = GS_running;
            net_send_servermode ();
            bman.updatestatusbar = 1; // force an update
		}

		if (keyb_gamekeys.state[BCK_fullscreen]  && !keyb_gamekeys.old[BCK_fullscreen]) {
            /* Switch Fullscreen */
			SDL_WM_ToggleFullScreen(gfx.screen);
			gfx.fullscreen = !gfx.fullscreen;
            bman.updatestatusbar = 1; // force an update
		}

		/*
		if (keys[SDLK_F9] && event.type == SDL_KEYDOWN) {
            // Switch Debugmode
			debug = !debug;
            bman.updatestatusbar = 1; // force an update
			}
		*/
	
		if (keyb_gamekeys.state[BCK_esc] && !keyb_gamekeys.old[BCK_esc]) {
			if (chat.active && (bman.state == GS_ready || bman.state == GS_running)) {
				chat.active = 0;
				d_printf ("Chatmode Disabled\n");
			}
			else
				game_menu_create ();
		}
	
		if ((GT_MP_PTPM || GT_MP_PTPS) && keyb_gamekeys.state[BCK_chat] && !keyb_gamekeys.old[BCK_chat]) {
			chat_setactive (1, 0);
			chat.changed = 1;
			d_printf ("Chatmode Enabled\n");
		}
	}
};



void
game_loop ()
{
    SDL_Event event;
    int done = 0, i, eventstate;

	gfx_blitupdaterectclear ();
	
    draw_logo ();
    draw_field ();
    if (GT_MP)
        net_game_fillsockaddr ();
    SDL_Flip (gfx.screen);

	menu = NULL;

    bman.updatestatusbar = 1;   // force an update
    timestamp = SDL_GetTicks (); // needed for time sync.
    d_gamedetail ("GAME START");
    draw_players ();

    while (!done && (bman.state == GS_running || bman.state == GS_ready)) {
        if ((eventstate = SDL_PollEvent (&event)) != 0)
            switch (event.type) {
            case (SDL_QUIT):
                done = 1;
                bman.state = GS_quit;
            }

		/*
		 *	input handling 
		 */
		keyb_loop (&event);

		game_keys_loop ();

		chat_loop (&event);
        restore_players_screen ();
		
		player_check (bman.p_nr);			
		if (IS_LPLAYER2)
			player_check (bman.p2_nr);
		
        dead_playerani ();
        special_loop ();

		player_move (bman.p_nr);
		if (IS_LPLAYER2)
			player_move (bman.p2_nr);

        if (GT_MP) {
            player_calcpos ();
            network_loop ();
		}
        
		if (bman.state == GS_running)
			single_loop ();

        bomb_loop ();
        field_loop ();
		flitems_loop ();
        draw_players ();
        game_draw_info ();  // will set the var bman.player_nr

        /* check if there is only one player left and the game is in multiplayer mode
           and if there the last dieing animation is done */
		for (i = 0; (i < MAX_PLAYERS && (!PS_IS_used (players[i].state) 
										|| PS_IS_aiplayer (players[i].state)
										|| (PS_IS_used (players[i].state) && !PS_IS_alife (players[i].state)))); i++);
		if (i == MAX_PLAYERS)  /* only AI Players alife, make sure the game is going to an end */
			bman.players_nr = 1;
        if (((bman.players_nr < 2
             && (GT_MP || (GT_SP && bman.ai_players > 0)))
			|| (GT_SP && bman.ai_players == 0 && bman.players_nr < 1))
			&& bman.timeout >= 0.0 && (bman.gametype == GT_bomberman || map.state != MS_normal))
            bman.timeout = 0.0f;
		
        if ((GT_SP || GT_MP_PTPM) && bman.timeout < -GAME_OVERTIMEOUT) {
            d_printf ("GAME: Game Over\n");
            done = 1;
        }
		
        stonelist_draw ();
		
		/* if there is any menu displayed do so */
		if (menu != NULL) 
			game_menu_loop (&event, eventstate);
		
        gfx_blitdraw ();
		s_calctimesync ();
		bman.timeout -= timediff;
    }

	if (menu != NULL)
		menu_delete (menu);
	gfx_blitdraw ();
	
    chat_show (-1, -1, -1, -1);

    d_gamedetail ("GAME END");
    d_printf ("done = %d\n", done);
	draw_logo ();
	gfx_blitupdaterectclear ();
	SDL_Flip (gfx.screen);
};


/* check which player won and free all unnneded data */
void
game_end ()
{
    int i;

    gfx_free_players ();
    tileset_free ();
	snd_music_stop ();	
    snd_free ();

    /* count the points */
    for (i = 0; i < MAX_PLAYERS; i++)
        if (PS_IS_used (players[i].state)) {
            if (PS_IS_alife (players[i].state)) {
                bman.lastwinner = i;
                players[i].wins++;
                players[i].points += bman.players_nr_s;
            }
        }

	if (GT_SP)
		game_showresult ();
		
    /* check which player is now free,i.e. disconnected during the game and was playing */
    for (i = 0; i < MAX_PLAYERS; i++)
        if ((players[i].state & PSF_used) == 0)
            players[i].state = 0;
}


/* load the images with the right scaleing */
void
game_start ()
{
	int p, i;
	
    menu_displaytext ("Loading..", "Please Wait");

	bman.players_nr_s = 0;

    for (p = 0; p < MAX_PLAYERS; p++) {
        if (PS_IS_used (players[p].state)) {
            bman.players_nr_s++;
            if (players[p].gfx_nr == -1) {
                players[p].gfx = NULL;
                players[p].state &= (0xff - (PSF_alife + PSF_playing));
            }
            else {
                players[p].state |= PSF_alife + PSF_playing;
                players[p].gfx = &gfx.players[players[p].gfx_nr];
            }
        }
        else
            players[p].state = 0;

        players[p].bombs_n = bman.start_bombs;
        players[p].range = bman.start_range;
        players[p].speed = bman.start_speed;
		players[p].collect_shoes = 0;
        players[p].special.type = SP_nothing;
        players[p].m = 0;
		players[p].old.x = 0;
		players[p].old.y = 0;
        bman.updatestatusbar=1;
        players[p].frame = 0.0f;
        players[p].d = 0;
        players[p].pos.x = -1;
        players[p].pos.y = -1;
		players[p].tunnelto = 0.0f;

		/* all types of illnes turn them off */
		for (i = 0; i < PI_max; i++)
            players[p].ill[i].to = 0.0f;
		
        // reset bombs
        for (i = 0; i < MAX_BOMBS; i++) {
            players[p].bombs[i].state = BS_off;
            players[p].bombs[i].ex_nr = -1;
			players[p].bombs[i].speed = 0;
			players[p].bombs[i].dest.x = 0;
			players[p].bombs[i].dest.y = 0;
			players[p].bombs[i].mode = BM_normal;
			players[p].bombs[i].id.p = p;
			players[p].bombs[i].id.b = i;
        }
    }
	
	flitems_reset ();
    init_map_tileset ();
    tileset_load (map.tileset, -1, -1);
    gfx_load_players (gfx.block.x, gfx.block.y);
    snd_load (map.tileset);
	snd_music_start ();	
	map.state = MS_normal;
	bman.timeout = bman.init_timeout;
	s_calctimesync (); // to clean up the timesyc 
	s_calctimesync (); // data run this twice
	if (GT_MP_PTPM)
		net_send_servermode ();
};


/* show result of the game */
void game_showresult () {
	SDL_Rect dest,
      src;
    char text[255];
    SDL_Event event;
    Uint8 *keys;
	int done = 0, keypressed = 0, x, y, i, p;
	
    menu_displaytext ("Loading..", "Please Wait");
    dest.x = dest.y = 0;
    dest.w = gfx.res.x;
    dest.h = gfx.res.y;
    gfx_load_players (40, 40);

    draw_logo ();
    strcpy (text, "Game Result");
    x = (gfx.res.x - (font[2].size.x * strlen (text)) - 64) / 2;
    y = 0;
    font_drawbold (x, y, text, 2, 6, 2);
    font_draw (x, y, text, 2, 5);
	y += font[2].size.x;
	
	for (i = 0, p = 0; p < MAX_PLAYERS; p++)
		if (PS_IS_alife (players[p].state))
			i++;

	if (i == 1) 
		strcpy (text, "Game Over");
	else
		strcpy (text, "Draw Game");

    x = (gfx.res.x - (font[2].size.x * strlen (text)) - 64) / 2;
    font_drawbold (x, y, text, 2, 6, 2);
    font_draw (x, y, text, 2, 5);
	y += font[2].size.x + 8;

	strcpy (text, "[CTRL],[RETURN] or [STRG] for another game");
    x = (gfx.res.x - (font[1].size.x * strlen (text)) - 64) / 2;
    font_drawbold (x, gfx.res.y - (2*font[0].size.y) - 2, text, 0, COLOR_brown, 1);
    font_draw (x, gfx.res.y - (2*font[0].size.y) - 2, text, 0, COLOR_yellow);
	
	strcpy (text, "or [ESC] to leave the game.");
    x = (gfx.res.x - (font[1].size.x * strlen (text)) - 64) / 2;
    font_drawbold (x, gfx.res.y - font[0].size.y - 2, text, 0, COLOR_brown, 1);
    font_draw (x, gfx.res.y - font[0].size.y - 2, text, 0, COLOR_yellow);
	
	for (i = 1, p = 0; p < MAX_PLAYERS; p++) {
		if (PS_IS_used (players[p].state)) {
			if (!i) {
				i = 1;
				x = (gfx.res.x / 2) + 16;
			}
			else if (i) {
				i = 0;
				y = y + 80;
				x = 16;
			}
			
			if (PS_IS_alife (players[p].state)) {
			    font_drawbold (x + 80, y + 4, players[p].name, 0, COLOR_brown, 1);
		    	font_draw (x + 80, y + 4, players[p].name, 0, COLOR_yellow);
			}
			else 
				font_draw (x + 80, y + 4, players[p].name, 0, COLOR_gray);

			sprintf (text, "%3d", players[p].wins);
			font_draw (x + 80 + (LEN_PLAYERNAME+2) * font[0].size.x, y + 4, text, 0, 0);
			sprintf (text, "%3d", players[p].points);
			font_draw (x + 80 + (LEN_PLAYERNAME+5) * font[0].size.x, y + 4, text, 0, 0);
			
			dest.x = x;
			dest.y = y - 32;
			src.w = dest.w = players[p].gfx->ani.w;
			src.h = dest.h = players[p].gfx->ani.h;
			src.x = players[p].gfx->ani.w * down;
			src.y = 0;
			gfx_blit (players[p].gfx->ani.image, &src, gfx.screen, &dest, 1);
		}
	}
	
	gfx_blitdraw ();
	SDL_Flip (gfx.screen);
	gfx_free_players ();

    while (!done) {
        /* do the keyboard handling */
        if (SDL_PollEvent (&event) != 0)
            switch (event.type) {
            case (SDL_QUIT):
                bman.state = GS_quit;
                bman.p_nr = -1;
                done = 1;
		}

        keys = SDL_GetKeyState (NULL);

        if (keys[SDLK_ESCAPE] && event.type == SDL_KEYDOWN) {
            /* we want to quit */
            done = 1;
            bman.p_nr = -1;
            keypressed = 1;
            bman.state = GS_startup;
        }

        if ((keys[SDLK_RETURN] || keys[SDLK_LCTRL] || keys[SDLK_RCTRL]) && (!keypressed) && (event.type = SDL_KEYDOWN)) {
            done = 1;
            keypressed = 1;
        }

        if (keys[SDLK_F8] && event.type == SDL_KEYDOWN) {
            /* Switch Fullscreen */
			SDL_WM_ToggleFullScreen(gfx.screen);
			gfx.fullscreen = !gfx.fullscreen;
            bman.updatestatusbar = 1; // force an update
        }

        if (event.type == SDL_KEYUP)
            keypressed = 0;
        else if (event.type == SDL_KEYDOWN) 
            keypressed = 1;

        s_delay (25);
    }
	
	if (bman.state != GS_quit && bman.state != GS_startup)
		bman.state = GS_running;
};


/*
 * create the in game menu
 */
void game_menu_create () {
	if (menu != NULL)
		return;

	menu = menu_new ("Gamemenu", 300, 150);
	
	menu_create_button (menu, "Back to the Game", -1, 50, 200, 1);
	if (GT_SP || GT_MP_PTPM)
		menu_create_button (menu, "End this Round", -1, 80, 200, 2);
	menu_create_button (menu, "Quit the Game", -1, 110, 200, 3);
	
	menu_focus_id (menu, 1);
	menu->looprunning = 1;
};


/*
 * in game menu_loop, will called every game loop.
 * As long as this menu is displayed the gamekeys will not work.
 *
 * the drawings will be done from the main loop. So we won't
 * have to draw anything on our own.
 *
 * Pressing ESC will bring you back to the game.
 */
void game_menu_loop (SDL_Event *event, int eventstate) {
	int done;
	
	if (menu == NULL)
		return;
	
	menu_draw (menu);
	
	done = menu_event_loop (menu, event, eventstate);
	/* 
	 * check if one of the buttons was pressed
	 */
	
	if (done != 0) {
		if (menu->focus->id == 2 && (GT_MP_PTPM || GT_SP)) {	/* End Round */
			bman.timeout = -GAME_OVERTIMEOUT;
		}
		
		else if (menu->focus->id == 3) 							/* End Game */
			bman.state = GS_startup;
		
		else { 													/* Quit Menu */
			menu_delete (menu);
			menu = NULL;
			gfx_blitdraw ();
			draw_field ();
		}
	}
};
