/* $Id: network.c,v 1.63 2004/05/20 16:55:30 stpohle Exp $ */
/*
	network routines.
*/

#include "bomberclone.h"
#include "network.h"
#include "chat.h"
#include "packets.h"
#include "ogcache-client.h"
#include "menu.h"

int
network_server_port (char *server, char *host, int hostlen, char *port, int portlen)
{
    char *pos,
     *pos2;

    if (host == NULL)
        return -1;

    pos2 = pos = strchr (server, ':');

    if (pos != NULL)
        while (pos2 != NULL) {
            pos = pos2;
            pos2 = strchr (pos + 1, ':');
        }

    if (pos != NULL) {
        // : für Portangabe gefunden
        if (pos - server < hostlen) {
            strncpy (host, server, pos - server);
            host[pos - server] = 0;
            if (pos[1] == 0)
                sprintf (port, "11000");
            else
                strcpy (port, pos + 1);
        }
        else {
            return -1;
        }
    }
    else {
        // Portangabe wurde nicht gefunden und wird auf 0 gesetzt
        strncpy (host, server, hostlen);
        sprintf (port, "11000");
    }

    return 0;
};


/*
	try to work better with the network packet option
*/
void
net_dyn_pkgoption ()
{
    int p;
    _net_pkgopt *npkg;

    for (p = 0; p < MAX_PLAYERS; p++)
        if (PS_IS_netplayer (players[p].state) && !PS_IS_aiplayer(players[p].state)) {
            npkg = &players[p].net.pkgopt;

            if (npkg->to_2sec > DYN_PKG_MAX_MISSING) {
                if (npkg->send_set < 10)
                    npkg->send_set++;
                npkg->to_2sec = 0;
                npkg->to_timestamp = timestamp;
            }

            if ((timestamp - npkg->to_timestamp > 2000) && npkg->to_2sec <= DYN_PKG_MIN_MISSING) {
                if (npkg->send_set > PKG_SENDSETOPT)
                    npkg->send_set--;
                npkg->to_2sec = 0;
                npkg->to_timestamp = timestamp;
            }
        }
};




/*
	setup everything for the network loop
*/
int
network_init ()
{
	char host[LEN_SERVERNAME];
	char port[LEN_PORT];
	
/*   we need it for the windows winsock */
#ifdef _WIN32
    WSADATA wsaData;

    if (WSAStartup (MAKEWORD (1, 1), &wsaData) != 0) {
        d_printf ("WSAStartup failed.\n");
        exit (1);
    }
#endif

	if (bman.net_ai_family == PF_INET)
		sprintf (host, "IPv4");
#ifndef _WIN32
	else if (bman.net_ai_family == PF_INET6)
		sprintf (host, "IPv6");
#endif
	else
		sprintf (host, "IPv (unknown)");
	d_printf ("Network Init with %s.\n", host);

    bman.sock = -1;
    timestamp = SDL_GetTicks ();

    // start the udp server
    bman.sock = udp_server (bman.port, bman.net_ai_family);

    if (bman.sock < 0) {
#ifdef _WIN32
        WSACleanup ();
#endif
        return -1;
    }

	if (bman.notifygamemaster) {
		network_server_port (bman.ogcserver, host, LEN_SERVERNAME, port, LEN_PORT);
		if (ogc_init (bman.ogc_port, host, port, "BomberClone", bman.net_ai_family) == 0)
			bman.notifygamemaster = 0;
	}

    // we have got our socket.. so now allocate the memory for the resend_cache
    resend_cache.data = (char *) malloc (PKG_RESENDCACHE_SIZE);
    resend_cache.fill = 0;

    return 0;
};


/*
	shutdown the network part
*/
void
network_shutdown ()
{
    int i;

	d_printf ("network_shutdown\n");

    if (GT_MP_PTPM) {
		d_printf ("Server Quit Send information\n");
        for (i = 0; i < MAX_PLAYERS; i++)
            if (i != bman.p_servnr && PS_IS_netplayer (players[i].state) && !PS_IS_aiplayer (players[i].state))
                send_quit (&players[i].net.addr, bman.p_servnr);
    }
    else if (players[bman.p_servnr].net.addr.host[0] != 0) {
        send_quit (&players[bman.p_servnr].net.addr, bman.p_nr);
		if (IS_LPLAYER2)
			send_quit (&players[bman.p_servnr].net.addr, bman.p2_nr);
	}

	if (bman.notifygamemaster) {
        ogc_sendgamequit (bman.sock);
		ogc_shutdown ();
	} 
	
    udp_close (bman.sock);

    if (resend_cache.data != NULL)
        free (resend_cache.data);

    resend_cache.data = NULL;
    resend_cache.fill = -1;

    bman.p_nr = -1;
	bman.sock = -1;
#ifdef _WIN32
    WSACleanup ();
#endif
};


int
net_check_timeout (int pl_nr)
{
    int timeout = UDP_TIMEOUT;

    if ((players[pl_nr].state & (PSF_net + PSF_used + PSF_ai)) == (PSF_used + PSF_net)
		&& ((players[pl_nr].net.flags & NETF_local2) == 0)
        && timestamp - players[pl_nr].net.timestamp > timeout
        && players[pl_nr].net.pingreq != players[pl_nr].net.pingack) {
        d_printf ("net_check_timeout pl_nr=%d, ack=%d, req=%d, timediff=%d\n", pl_nr,
                  players[pl_nr].net.pingack, players[pl_nr].net.pingreq,
                  timestamp - players[pl_nr].net.timestamp);
        players[pl_nr].net.timestamp = timestamp;
        players[pl_nr].net.pingack = players[pl_nr].net.pingreq;
        send_ping (&players[pl_nr].net.addr, players[pl_nr].net.pingack + 100,
                   PKG_pingreq);
    }
    if ((players[pl_nr].state & (PSF_net + PSF_used + PSF_ai)) == (PSF_used + PSF_net)
		&& ((players[pl_nr].net.flags & NETF_local2) == 0)
        && timestamp - players[pl_nr].net.timestamp > timeout
        && players[pl_nr].net.pingreq == players[pl_nr].net.pingack) {
        d_printf ("net_check_timeout pl_nr=%d, ack=%d, req=%d, timediff=%d\n", pl_nr,
                  players[pl_nr].net.pingack, players[pl_nr].net.pingreq,
                  timestamp - players[pl_nr].net.timestamp);
        return 1;
    }
    return 0;
};



/*
	Read data from the network and work with it
*/
int
network_loop ()
{
    char data[MAX_UDPDATA];
    struct pkg *packet = (struct pkg *) data;
    int inlen,
      i;

    _net_addr addr;

    if (bman.state != GS_running && bman.state != GS_ready)
        timestamp = SDL_GetTicks ();

    /* 
       as long as we get any new data, work with them
     */
    inlen = udp_get (bman.sock, data, MAX_UDPDATA, &addr.sAddr, bman.net_ai_family);
    addr.port[0] = addr.host[0] = 0;
    if (inlen > 0)
        dns_filladdr (addr.host, LEN_SERVERNAME, addr.port, LEN_PORT, bman.net_ai_family,
                      &addr.sAddr);

    while (inlen > 0) {
        do_pkg (packet, &addr);
		
        //  printf ("Network : inlen (%d) typ (%d) Size (%d)\n", inlen, packet->typ, pkglen);
        inlen = udp_get (bman.sock, data, MAX_UDPDATA, &addr.sAddr, bman.net_ai_family);
        addr.port[0] = addr.host[0] = 0;
        if (inlen > 0)
            dns_filladdr (addr.host, LEN_SERVERNAME, addr.port, LEN_PORT, bman.net_ai_family,
                          &addr.sAddr);
    }

    /*
       check here for old connections who aren't answering
     */
    if (bman.state == GS_wait || bman.state == GS_ready || bman.state == GS_running) {
        if (GT_MP_PTPS) {
            if (net_check_timeout (bman.p_servnr)) {
                d_printf ("Server Timed Out\n");
                bman.state = GS_startup;
            }
        }
        else if (GT_MP_PTPM) {
            for (i = 1; i < MAX_PLAYERS; i++)
                if (i != bman.p_nr && net_check_timeout (i)) {
                    d_printf ("Player %d Timed Out\n", i);
                    player_delete (i);
                }
        }
    }

    /*
       resend_cache.... 
     */
    rscache_loop ();

    /*
       dynamic calibration of the network traffic option
     */
    net_dyn_pkgoption ();

    return 0;
};


/*
   this is needed to draw the whole uppdate of everything 
*/
void
draw_netupdatestate (char st)
{
    char text[255];
	unsigned char b;
    int y = 0,
	  b1,
	  z,
	  zx=200,
      i,
	  j,
      s=map.size.y+MAX_PLAYERS+GAME_MAX_TUNNELS;
    SDL_Rect src,
      dest;
	z=gfx.res.x-zx-30-8;
	for (i = 0; i < MAX_PLAYERS; i++)
        if (PS_IS_used (players[i].state)) {
            y += 50;
            if (st) {
				redraw_logo (0, y, gfx.res.x, y + 50);

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

                	dest.x = 50;
                	dest.y = y;

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

				dest.x = zx;
				dest.y = y;
				dest.w = menulistimages[1][0]->w;
				dest.h = menulistimages[1][0]->h;
				gfx_blit (menulistimages[1][0], NULL, gfx.screen, &dest, 10000);
				dest.x = z+zx+4;
				gfx_blit (menulistimages[1][2], NULL, gfx.screen, &dest, 10000);
				// draw the bottom left and right of the list
				dest.y = y+29;
				gfx_blit (menulistimages[1][8], NULL, gfx.screen, &dest, 10000);
				dest.x = zx;
				gfx_blit (menulistimages[1][6], NULL, gfx.screen, &dest, 10000);
				//top & bottom
				for (j=4;j<z+4;j+=4) {
					dest.x=j+zx;dest.y=y;
					gfx_blit (menulistimages[1][1], NULL, gfx.screen, &dest, 10000);
					dest.y = y+29;
					gfx_blit (menulistimages[1][7], NULL, gfx.screen, &dest, 10000);
				}
				//left &right
				for (j=4;j<29;j+=4) {
					dest.x=zx;dest.y=y+j;
					gfx_blit (menulistimages[1][3], NULL, gfx.screen, &dest, 10000);
					dest.x = z+zx+4;
					gfx_blit (menulistimages[1][5], NULL, gfx.screen, &dest, 10000);
				}
                sprintf (text, "%s", players[i].name);
	            font_draw (80, y, text, 0, 4);
			}
			// calc percentage, this a range from 0 to 255)			
			switch(players[i].net.net_istep){
               	case 3:
					sprintf (text, "Getting Tunnel Data %d.", players[i].net.net_status);
					b=(players[i].net.net_status+1)*255/s;
					break;
           		case 2:
               		sprintf (text, "Getting Field Data %d of %d.", players[i].net.net_status,
                        map.size.y);
					b=(players[i].net.net_status+1+GAME_MAX_TUNNELS)*255/s;
					break;
				case 1:
               		sprintf (text, "Getting Player Data %d of %d.", players[i].net.net_status,
                        MAX_PLAYERS);
					b=(players[i].net.net_status+1+GAME_MAX_TUNNELS+map.size.y)*255/s;
					break;
				default:
               		sprintf (text, "Ready");
					b=255;
					break;
				}
			
				//draw bar
			if (b>0) {
					b1=b*z/255;
					dest.x = zx+4;
					dest.y = y+4;
					dest.w = menubuttonimages[2][0]->w;
					dest.h = menubuttonimages[2][0]->h;
					gfx_blit (menubuttonimages[2][0], NULL, gfx.screen, &dest, 10000);									
					dest.x = zx+4+b1-menubuttonimages[1][2]->w;
					if (dest.x<zx+4) dest.x=zx+4;
					dest.w = menubuttonimages[2][2]->w;
					dest.h = menubuttonimages[2][2]->h;
					gfx_blit (menubuttonimages[2][2], NULL, gfx.screen, &dest, 10000);				
				    if (b1>menubuttonimages[2][0]->w+menubuttonimages[2][2]->w) {
						dest.w = menubuttonimages[2][1]->w;
						dest.h = menubuttonimages[2][1]->h;					
						for(j=menubuttonimages[2][0]->w;j<b1-menubuttonimages[2][2]->w;
							j+=menubuttonimages[2][1]->w) {
							dest.x=j+zx+4;
							gfx_blit (menubuttonimages[2][1], NULL, gfx.screen, &dest, 10000);				
						}
					}
				}
		// draw old status in case of debug
			if (!players[i].net.net_istep)
				font_draw (80, y + 20, text, 0, 4);
			else 
				if (debug) {
					redraw_logo (80, y+35, gfx.res.x-80, 15);
					font_draw (80, y + 35, text, 0, 4);
			}
		}
	gfx_blitdraw ();
	return;
}

/*
	used to update settings at startup 
*/
void
net_change_playerid (int pl_nr, unsigned char senddata)
{
    int i;
	
    if (GT_MP_PTPM) {
        /*
           Send to all connected clients the update
         */
        for (i = 1; i < MAX_PLAYERS; i++)
            if (!PS_IS_aiplayer (players[i].state) && players[i].net.addr.host[0] != 0)
                send_playerid (&players[i].net.addr, players[pl_nr].name,
                               players[pl_nr].net.addr.host, players[pl_nr].net.addr.port,
                               pl_nr, players[pl_nr].gfx_nr, players[pl_nr].net.flags);
    }
    else {
        /*
           Send only to the Server the update and only if in_nr == bman.in_nr
         */
        if ((pl_nr == bman.p_nr || (IS_LPLAYER2 && pl_nr == bman.p2_nr)) && senddata)
            send_playerid (&players[bman.p_servnr].net.addr, players[pl_nr].name,
                           players[pl_nr].net.addr.host, players[pl_nr].net.addr.port,
                           pl_nr, players[pl_nr].gfx_nr, players[pl_nr].net.flags);
    }

    player_set_gfx (&players[pl_nr], players[pl_nr].gfx_nr);
};


/*
    sets up everything for the network game..
	on servers the game field will be created and the clients will wait for the game data
	within the network loop
*/
void
net_transmit_gamedata ()
{
    int done = 0,
      keypressed = 0,
      x,
      y,						// network upload status for one step
      p,
      i,
      net_istep;                // network init step
    SDL_Event event;
    Uint8 *keys;
    Uint32 downtimestamp = 0;

    draw_logo ();

    if (GT_MP_PTPM)
        font_draw (100, 0, "Waiting for the Clients", 1, 0);
    else
        font_draw (100, 0, "Downloading Data", 1, 0);

    /* 
       prepare everything for the loop 
     */
    for (x = 0; x < MAX_PLAYERS; x++) {
        players[x].net.timestamp = 0;
        players[x].net.net_status = -1;
		if ((PS_IS_aiplayer (players[x].state)) || (x==bman.p_servnr) || (x == bman.p2_nr) || (players[x].net.flags & NETF_local2) == NETF_local2)
			players[x].net.net_istep = 0;
		else 
			players[x].net.net_istep = 3;
    }

    y = -1;
    if (GT_MP_PTPM)
        net_istep = 0;
    else
        net_istep = 3;
	
    draw_netupdatestate (1);
	SDL_Flip (gfx.screen);
	downtimestamp = timestamp;
    while (!done && (bman.state == GS_update || (GT_MP_PTPS && net_istep != 0))) {
        /* the network thing */

        network_loop ();

        /* if PTPM check if all players are ready */
        if (GT_MP_PTPM) {
			if (timestamp - downtimestamp > TIME_UPDATEINFO) {
				downtimestamp = timestamp;
				net_send_updateinfo();
			}
            for (p = 1, i = 1; p < MAX_PLAYERS; p++)
                if (PS_IS_playing (players[p].state) && players[p].net.net_istep != 0)
                    i = 0;
            if (i == 1) {       /* all players are ready */
                done = 1;
                bman.state = GS_ready;
            }
        }

        /* if PTPS get all data */
        if (GT_MP_PTPS) {
			if (net_istep == 3) {
				/* 
				   get tunneldata 
				*/
				if ((y < GAME_MAX_TUNNELS - 1 && y == players[bman.p_nr].net.net_status)
					|| y == -1) {
						y++;
						downtimestamp = timestamp;
						send_tunneldata (&players[bman.p_servnr].net.addr, y, -1, -1);
				}
				else if (y < GAME_MAX_TUNNELS && y != players[bman.p_nr].net.net_status
                         && y >= 0 && timestamp - downtimestamp > DOWNLOAD_TIMEOUT) {
                    /* we have got no tunnel data*/
                    y--;
                }
                else if (y == GAME_MAX_TUNNELS - 1 && players[bman.p_nr].net.net_status == y) {
                    /* we have got all tunnel data */
                    y = -1;
                    players[bman.p_nr].net.net_istep = --net_istep;
                    players[bman.p_nr].net.net_status = -1;
                }
			}
			
            if (net_istep == 2) {
				/* 
				   get field data
				*/
                if ((y < map.size.y - 1 && y == players[bman.p_nr].net.net_status)
                    || y == -1) {
                    /* send field data req */
                    y++;
                    downtimestamp = timestamp;
                    send_getfield (&players[bman.p_servnr].net.addr, y);
                }
                else if (y < map.size.y && y != players[bman.p_nr].net.net_status
                         && y >= 0 && timestamp - downtimestamp > DOWNLOAD_TIMEOUT) {
                    /* getdata timed out - we have got no field data */
                    y--;
                }
                else if (y == map.size.y - 1 && players[bman.p_nr].net.net_status == y) {
                    /* we have got all field data */
                    y = -1;
                    players[bman.p_nr].net.net_istep = --net_istep;
                    players[bman.p_nr].net.net_status = -1;
                }
            }

            if (net_istep == 1) {
				/*
					get player data
				*/
                if ((y < MAX_PLAYERS - 1 && y == players[bman.p_nr].net.net_status) || y == -1) {
                    /* send player date req */
                    y++;
                    downtimestamp = timestamp;
                    send_getplayerdata (&players[bman.p_servnr].net.addr, y);
                }
                if (y < MAX_PLAYERS && y != players[bman.p_nr].net.net_status && y >= 0
                    && timestamp - downtimestamp > DOWNLOAD_TIMEOUT) {
                    /* we have got no player data */
                    y--;
                }
                if (y == MAX_PLAYERS - 1 && players[bman.p_nr].net.net_status == y) {
                    /* we have got all playerdata */
                    y = -1;
                    players[bman.p_nr].net.net_istep = --net_istep;
                    players[bman.p_nr].net.net_status = -1;
                    downtimestamp = timestamp;
                    send_playerstatus (&players[bman.p_servnr].net.addr, bman.p_nr, 0, 0);
                }
            }
            if (net_istep == 0 && players[bman.p_nr].net.net_status == -1
                && timestamp - downtimestamp > DOWNLOAD_TIMEOUT) {
                /* server did not send informations back */
                downtimestamp = timestamp;
                send_playerstatus (&players[bman.p_servnr].net.addr, bman.p_nr, 0, 0);
            }
		}

        /* do the grafik work */
        draw_netupdatestate (0);

        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) {
            done = 1;
            bman.p_nr = -1;
            keypressed = 1;
            bman.state = GS_startup;
        }

        if (event.type == SDL_KEYUP)
            keypressed = 0;

        timestamp = SDL_GetTicks (); // needed for time sync.
        SDL_Delay (1);          // we don't need here anything better

        /* player is only watching so just go after we have got everything
           go to show the field */
        if (GT_MP_PTPS && bman.state == GS_update && net_istep == 0
            && players[bman.p_nr].gfx_nr == -1) {
            done = 1;
            bman.state = GS_running;
        }
    }
};


void
net_game_send_player (int p_nr)
{
    int p;

    if (GT_MP_PTPM) {
        for (p = 0; p < MAX_PLAYERS; p++)
            if (PS_IS_netplayer (players[p].state) && p != bman.p_nr && p != bman.p2_nr)
                send_playerdata (&players[p].net.addr, p_nr, &players[p_nr]);
    }
    else if (p_nr == bman.p_nr || p_nr == bman.p2_nr) {
        for (p = 0; p < MAX_PLAYERS; p++)
            if (NET_CANSEND(p))
                send_playerdata (&players[p].net.addr, p_nr, &players[p_nr]);
    }
};


void
net_game_send_playermove (int p_nr, int mustsend)
{
    int p;
	_player *pl;
	
    for (p = 0; p < MAX_PLAYERS; p++)
        if (NET_CANSEND(p)) {			
			pl = &players[p_nr];
		
            pl->net.pkgopt.send_to--;
			if ((pl->net.pkgopt.send_to <= 0 || mustsend))
				send_playermove (&players[p].net.addr, p_nr, pl);

			/* network packet send control */
            if (pl->net.pkgopt.send_to <= 0 || pl->net.pkgopt.send_to > pl->net.pkgopt.send_set)
                pl->net.pkgopt.send_to = pl->net.pkgopt.send_set;
        }
};

void
net_game_send_bomb (int p, int b)
{
    int pl;

    /* check if we are slave and send something else as dropping a bomb */
    if (GT_MP_PTPS && players[p].bombs[b].state != BS_ticking && players[p].bombs[b].state != BS_trigger)
        return;

    d_printf ("Send BombData %d, %d\n", p, b);

    if (p < 0 || p >= MAX_PLAYERS || b < 0 || b >= MAX_BOMBS)
        return;

    for (pl = 0; pl < MAX_PLAYERS; pl++)
        if (NET_CANSEND(pl))
            send_bombdata (&players[pl].net.addr, p, b, &players[p].bombs[b]);
};


void
net_game_send_field (int x, int y)
{
    int pl;

    d_printf ("Send FieldData %d, %d\n", x, y);

    if (x < 0 || x >= MAX_FIELDSIZE_X || y < 0 || y >= MAX_FIELDSIZE_Y)
        return;

    for (pl = 0; pl < MAX_PLAYERS; pl++)
        if (NET_CANSEND(pl))
            send_field (&players[pl].net.addr, x, y, &map.field[x][y]);
};


/*
 * send the information about the deleted player to all clients
 */
void
net_game_send_delplayer (int pl_nr) {
    int i;

    d_printf ("net_game_send_delplayer (%d)\n", pl_nr);

    if (GT_MP_PTPM && (GS_WAITRUNNING || bman.state == GS_update)) {
	    for (i = 0; i < MAX_PLAYERS; i++)
    		if (NET_CANSEND(i) || pl_nr == i)
                send_quit (&players[i].net.addr, pl_nr);
		if (bman.notifygamemaster)
			send_ogc_update ();
		bman.updatestatusbar=1;
	}

    if (GT_MP_PTPM && bman.notifygamemaster)
        send_ogc_update ();
	
	inpkg_delplayer (pl_nr);
};


void
net_game_fillsockaddr ()
{
    /* Update all sockaddr before the game starts */
    int i;

    for (i = 0; i < MAX_PLAYERS; i++)
        if (!PS_IS_aiplayer (players[i].state) && players[i].net.addr.host[0] != 0 && players[i].net.addr.host[0] != 0)
            dns_filladdr (players[i].net.addr.host, LEN_SERVERNAME,
                          players[i].net.addr.port, LEN_PORT, bman.net_ai_family,
                          &players[i].net.addr.sAddr);
};


void
net_send_servermode ()
{
    int i;

    for (i = 0; i < MAX_PLAYERS; i++)
        if (NET_CANSEND(i))
            send_servermode (&players[i].net.addr, i);

	if (bman.notifygamemaster && GT_MP_PTPM)
		send_ogc_update ();
};


/* sends to everyone an up to date playerlist*/
void
net_send_players ()
{
    int i,
      j;

    for (j = 0; j < MAX_PLAYERS; j++)
        if (NET_CANSEND (j))
            for (i = 0; i < MAX_PLAYERS; i++)
                send_playerid (&players[j].net.addr, players[i].name,
                               players[i].net.addr.host, players[i].net.addr.port, i,
                               players[i].gfx_nr, players[i].net.flags);

};



void
net_send_chat (char *text, signed char notigamesrv)
{
    int i;

    for (i = 0; i < MAX_PLAYERS; i++)
        if (NET_CANSEND(i))
            send_chat (&players[i].net.addr, text);
};


void
net_game_send_ill (int p_nr)
{
    int i;

    d_printf ("net_game_send_ill (%d)\n", p_nr);

    for (i = 0; i < MAX_PLAYERS; i++)
        if (NET_CANSEND(i))
            send_ill (&players[i].net.addr, p_nr, &players[p_nr]);
};



/* send to all players the drop item list */
void net_game_send_dropitems (int pl_nr, _flyingitem **fiptr, int cnt) {
    int i;

    d_printf ("net_game_send_dropitems (%d): %d items droppped\n", pl_nr, cnt);

    for (i = 0; i < MAX_PLAYERS; i++)
        if (NET_CANSEND(i))
            send_dropitems (&players[i].net.addr, pl_nr, fiptr, cnt);
};



/*
   this routine will set up some things for the network game
   after this the data should be transfered to the other clients.
*/
void
net_new_game ()
{
    int p;

	/* set all multiplayer depending datas */
    bman.players_nr = 0;
    bman.players_nr_s = 0;
    for (p = 0; p < MAX_PLAYERS; p++) {
        if (PS_IS_used (players[p].state))
            bman.players_nr_s++;
        else
            players[p].state = 0;
    }

    if (bman.p_nr != -1) 
		players[bman.p_nr].state &= (0xFF - PSF_net); // we are the local player
    bman.last_ex_nr = 1;
};



/* send special use elements into the network, 
   to make sure nothing bad happens with explosions
   we send the ex_nr number too */
void
net_game_send_special (int pl_nr, int ex_nr, int type)
{
    int pl;

    d_printf ("Send Special Data %d\n", pl_nr);

    if (pl_nr < 0 || pl_nr >= MAX_PLAYERS)
        return;

    for (pl = 0; pl < MAX_PLAYERS; pl++)
        if (NET_CANSEND(pl))
            send_special (&players[pl].net.addr, pl_nr, type, ex_nr);
};


/* Send update informations to all clients */
void
net_send_updateinfo ()
{
    int i;

	if (GT_MP_PTPS)
		return;

    d_printf ("Send Updateinfo\n");
	
    for (i = 0; i < MAX_PLAYERS; i++)
        if (NET_CANSEND(i))
            send_updateinfo (&players[i].net.addr);
};


/* Send mapinformations to all clients */
void
net_send_mapinfo ()
{
    int i;

	if (GT_MP_PTPS)
		return;

    d_printf ("Send Mapinfo\n");
	
    for (i = 0; i < MAX_PLAYERS; i++)
        if (NET_CANSEND(i))
            send_mapinfo (&players[i].net.addr);
};



/* send an update about the game to all clients */
void send_ogc_update () {
	int i, j;
	char status[10];
	
	if (!bman.notifygamemaster || GT_MP_PTPS)
		return;
	
    for (j = 0, i = 0; i < bman.maxplayer; i++)
          if (PS_IS_used (players[i].state))
               j++;

	switch (bman.state) {
		case (GS_running):
			sprintf (status, "running");
			break;
		case (GS_ready):
			sprintf (status, "ready");
			break;
		case (GS_wait):
			sprintf (status, "wait");
			break;
		case (GS_update):
			sprintf (status, "update");
			break;
		default:
			sprintf (status, "error");
			break;
	}
	
	ogc_sendgamestatus (bman.sock, "BomberClone", VERSION, bman.gamename, j, bman.maxplayer, status);
};


/* send the respawn data to all clients and with the new position of the player */
void net_game_send_respawn (int pl_nr) {
    int pl;

    d_printf ("Send Respawn Data %d New Position (%d,%d)\n", pl_nr);

    if (pl_nr < 0 || pl_nr >= MAX_PLAYERS)
        return;

    for (pl = 0; pl < MAX_PLAYERS; pl++)
        if (NET_CANSEND(pl))
        	send_respawn (&players[pl].net.addr, pl_nr);
};
