/* * file menu_network.c - user interface for setting up networks games * * $Id: menu_network.c,v 1.7 2004/07/07 10:24:20 iskywalker Exp $ * * Program XBLAST * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2; or (at your option) * any later version * * This program is distributed in the hope that it will be entertaining, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "menu_network.h" #include "atom.h" #include "menu.h" #include "menu_game.h" #include "menu_layout.h" #include "mi_tool.h" #include "server.h" #include "central.h" /* XBCC */ #include "random.h" /* XBCC */ #include "str_util.h" #ifndef W32 #include #endif /* * local constants */ #define ANIME_LENGTH 4 /* * local variables */ /* all koen's shit for teams */ #define largeNUMBER 254 static MENU_ID teamItem[MAX_HOSTS][NUM_LOCAL_PLAYER]; static XBTeamState teamState[MAX_HOSTS][NUM_LOCAL_PLAYER]; static XBTeamState oldTeamState[MAX_HOSTS][NUM_LOCAL_PLAYER]; static unsigned teamID=-1, clientTeam=-1; static int teamMode = 0; // set to the .... /* server configuration */ static char serverName[128]; static int serverPort; static char serverGame[48]; static CFGGameHost cfgServer; static CFGGameHost cfgServerhis[10]; /* names of all possible players */ static char *hostName[MAX_HOSTS]; static const char *playerName[MAX_HOSTS][NUM_LOCAL_PLAYER]; static XBHostState hostState[MAX_HOSTS]; static XBHostState oldHostState[MAX_HOSTS]; static unsigned hostComplete[MAX_HOSTS]; static int hostPing[MAX_HOSTS]; /* host buttons */ #ifndef SMPF static MENU_ID hostItem[MAX_HOSTS]; #endif static MENU_ID lastFocus = 0; static unsigned lastHost = MAX_HOSTS; /* player graphics */ static XBBool playerValid[MAX_HOSTS][NUM_LOCAL_PLAYER]; static CFGPlayerGraphics playerGfx[MAX_HOSTS][NUM_LOCAL_PLAYER]; static const CFGPlayerGraphics *pPlayerGfx[NUM_LOCAL_PLAYER]; //static const CFGPlayerGraphics *pPlayerGfx[MAX_PLAYER]; static BMSpriteAnimation playerAnime[ANIME_LENGTH] = { SpriteStopDown, SpriteWinner3, SpriteWinner2, SpriteWinner, }; /* network games */ static const XBNetworkGame *networkGame[NUM_SEARCH_ROWS]; static XBNetworkGame **networkGamehis; static MENU_ID networkItem[NUM_SEARCH_ROWS]; static XBAtom networkAtom; static void CreateHostItems (XBBool server); static void CreateTeamItems (); static XBBool CreateCentralWaitMenu (void *par); static XBBool ButtonCentralUpdate (void *par); static XBBool ButtonStartLanGamehis (void *par); static XBBool ButtonStartLanGame (void *par); XBBool ButtonRefreshSearchCentral (void *par); char title[256]; // XBCC char stat0[256]; // XBCC char stat1[256]; // XBCC char stat2[256]; // XBCC char stat3[256]; // XBCC char stat4[256]; // XBCC XBBool autoCentral2=XBFalse; /* * */ static void ClearHosts (void) { int i; for (i = 0; i < MAX_HOSTS; i ++) { if (NULL != hostName[i]) { free (hostName[i]); hostName[i] = NULL; } } } /* ClearHosts */ /* * start network game as client */ static XBBool ButtonClientStart (void *par) { ClearHosts (); /* clean up */ MenuClear (); return XBTrue; } /* ButtonClientStart */ /* * start network game as server */ static XBBool ButtonServerStart (void *par) { int i, j, k, reinco, N; XBPlayerHost host; XBAtom gameAtom; CFGGamePlayers cfgAllPlayers, cfgHostPlayers; CFGGameSetup cfgSetup; N=0; if(teamMode) { reinco=0; for (i = 0; i < MAX_HOSTS; i ++) { for (j = 0; j < NUM_LOCAL_PLAYER; j ++) { if (teamState[i][j] >= XBTS_Red) { if(!(reinco&(1 << teamState[i][j]))) { reinco|=1 << teamState[i][j]; N++; } } } } if(N <= 1) { GUI_ErrorMessage ("Only one team you dumb fuck!"); return XBFalse; } } /* retrieve all player configs */ j = 0; for (i = 0, host = XBPH_Server; i < MAX_HOSTS; i ++, host ++) { if (i == 0) { gameAtom = atomLocal; } else if (hostState[i] == XBHS_In) { gameAtom = atomArrayHost0[i]; } else { continue; } if (! RetrieveGamePlayers (CT_Remote, gameAtom, &cfgHostPlayers) ) { continue; } for (k = 0; k < cfgHostPlayers.num; k ++) { cfgAllPlayers.player[j] = Network_GetPlayer (i, k); cfgAllPlayers.control[j] = cfgHostPlayers.control[k]; cfgAllPlayers.playerID[j]= cfgHostPlayers.playerID[k]; cfgAllPlayers.host[j] = host; cfgAllPlayers.team[j] = (teamMode?teamState[i][k]:XBPT_None); j ++; } } cfgAllPlayers.num = j; /* and store it */ StoreGamePlayers (CT_Remote, atomArrayHost0[0], &cfgAllPlayers); /* now the other configs */ if (RetrieveGameSetup (CT_Remote, atomLocal, &cfgSetup)) { StoreGameSetup (CT_Remote, atomArrayHost0[0], &cfgSetup); } /* close port for listening */ Server_StopListen (); /* send data to clients */ if(teamMode) { for (i = 0; i < MAX_HOSTS; i ++) { for (j = 0; j < NUM_LOCAL_PLAYER; j ++) { Server_SendTeamState(i*NUM_LOCAL_PLAYER+j, (unsigned) teamState[i][j]); } } } for (i = 1; i < MAX_HOSTS; i ++) { switch (hostState[i]) { case XBHS_In: Server_SendStart (i); break; default: Server_SendDisconnect (i); break; } } /* clean up */ ClearHosts (); MenuClear (); return XBTrue; } /* ButtonServerStart */ /* * handle network event "player config" */ static void HandlePlayerConfig (unsigned clientID, int player) { int i,j; XBAtom playerAtom; assert (clientID < MAX_HOSTS); assert (player >= 0); assert (player < NUM_LOCAL_PLAYER); /* get player graphics */ playerAtom = Network_GetPlayer (clientID, player); playerName[clientID][player] = GetPlayerName (CT_Remote, playerAtom); playerValid[clientID][player] = XBTrue; RetrievePlayerGraphics (CT_Remote, playerAtom, COLOR_INVALID, &playerGfx[clientID][player]); /* todo: check completeness */ hostComplete[clientID] &= ~ (1 << player); Dbg_Out ("HandlePlayerConfig: %u %02u\n", clientID, hostComplete[clientID]); if (0 == hostComplete[clientID]) { hostState[clientID] = XBHS_In; #ifndef SMPF MenuSetActive (hostItem[clientID], XBTrue); #endif } if(teamMode) { teamState[clientID][player] = XBTS_Red; MenuSetActive (teamItem[clientID][player], XBTrue); for (i = 0; i < MAX_HOSTS; i ++) { for (j = 0; j < NUM_LOCAL_PLAYER; j ++) { Server_SendTeamState(i*NUM_LOCAL_PLAYER+j, (unsigned) teamState[i][j]); } } } } /* HandlePlayerConfig */ /* * handle network event "game config" */ static void HandleGameConfig (unsigned clientID) { int i; CFGGamePlayers cfgPlayers; assert (clientID < MAX_HOSTS); /* get host name */ if (NULL != hostName[clientID]) { free (hostName[clientID]); } hostName[clientID] = DupString (GetHostName (CT_Remote, atomArrayHost0[clientID])); hostState[clientID] = XBHS_Wait; hostComplete[clientID] = 0; /* start check for completion */ if (RetrieveGamePlayers (CT_Remote, atomArrayHost0[clientID], &cfgPlayers) ) { for (i = 0; i < cfgPlayers.num && i < NUM_LOCAL_PLAYER; i ++) { if (ATOM_INVALID == cfgPlayers.player[i]) { break; } hostComplete[clientID] |= (1 << i); } } Dbg_Out ("HandleGameConfig: %u %02X\n", clientID, hostComplete[clientID]); /* resend hoststates for other clients */ memset (oldHostState, 0, sizeof (oldHostState)); } /* HandleGameConfig */ /* * handle network event "disconnected" */ static void HandleShutdown (unsigned clientID) { int j; assert (clientID < MAX_HOSTS); /* cleat host entry */ if (NULL != hostName[clientID]) { free (hostName[clientID]); hostName[clientID] = NULL; } hostState[clientID] = XBHS_None; for (j = 0; j < NUM_LOCAL_PLAYER; j ++) { teamState[clientID][j] = XBTS_None; } hostPing[clientID] = -1; /* clear player data */ memset (playerValid[clientID], 0, sizeof (playerValid[clientID])); memset (playerName[clientID], 0, sizeof (playerName[clientID])); /* disable button */ #ifndef SMPF MenuSetActive (hostItem[clientID], XBFalse); #endif for (j = 0; j < NUM_LOCAL_PLAYER; j ++) { MenuSetActive (teamItem[clientID][j], XBFalse); } /* exit menu if server has disconnected */ if (0 == clientID) { Client_Disconnect (); MenuExecFunc (CreateMainMenu, NULL); } } /* HandleShutdown */ /* * Handle network event "start game" */ static void HandleStartGame (unsigned clientID) { assert (clientID < MAX_HOSTS); SetHostType (XBPH_Client1 + clientID - 1); MenuExecFunc (ButtonClientStart, NULL); } /* HandleStartGame */ /* * Handle network events "host state" */ static void HandleHostState (unsigned clientID, XBBool isIn) { assert (clientID < MAX_HOSTS); if (isIn) { hostState[clientID] = XBHS_In; } else { hostState[clientID] = XBHS_Out; } Dbg_Out ("server changed host %u to %s\n", clientID, isIn ? "in" : "out"); } /* HandleHostState */ /* * Handle network events "team state" */ static void HandleTeamChange (unsigned clientID, unsigned teamID) { assert (clientID < MAX_HOSTS*NUM_LOCAL_PLAYER); teamState[clientID / NUM_LOCAL_PLAYER][clientID % NUM_LOCAL_PLAYER] = teamID; /* Dbg_Out ("server changed team %u (host %u, player %u) state to %u\n", clientID, (clientID / NUM_LOCAL_PLAYER),(clientID % NUM_LOCAL_PLAYER), teamID); */ } /* HandleHostState */ /* * handle network event "ping received" */ static void HandlePingReceived (unsigned clientID, XBBool isServer) { assert (clientID < MAX_HOSTS); if (isServer) { hostPing[clientID] = Server_GetPingTime (clientID); } else { hostPing[clientID] = Client_GetPingTime (clientID); } } /* HandlePingReceived */ /* * Handle any networks events */ static void HandleNetworkEvents (XBBool isServer) { XBNetworkEvent msg; unsigned clientID; while (XBNW_None != (msg = Network_GetEvent (&clientID) ) ) { switch (msg) { /* player data received */ case XBNW_RightPlayerConfig: HandlePlayerConfig (clientID, 0); break; case XBNW_LeftPlayerConfig: HandlePlayerConfig (clientID, 1); break; case XBNW_Joy1PlayerConfig: HandlePlayerConfig (clientID, 2); break; case XBNW_Joy2PlayerConfig: HandlePlayerConfig (clientID, 3); break; /* game config received */ case XBNW_GameConfig: HandleGameConfig (clientID); break; /* one host has disconnected */ case XBNW_Disconnected: HandleShutdown (clientID); break; /* error in connection to host */ case XBNW_Error: HandleShutdown (clientID); break; /* ping received from client */ case XBNW_PingReceived: HandlePingReceived (clientID, isServer); break; /* server wants to start game */ case XBNW_StartGame: HandleStartGame (clientID); break; /* server has changed host state */ case XBNW_HostIsIn: if (! isServer) { HandleHostState (clientID, XBTrue); } break; case XBNW_HostIsOut: if (! isServer) { HandleHostState (clientID, XBFalse); } break; case XBNW_TeamChange: //Dbg_Out("--- Team %u %u %u---\n", clientID, clientTeam, teamID); if(teamMode==0) { teamMode=1; CreateTeamItems(); } if (!isServer) { if(clientTeam>largeNUMBER) { if(teamIDlargeNUMBER) { if(clientTeam=10){ ButtonRefreshSearchCentral(NULL); old=tv; } #endif while (XBNW_None != (msg = Network_GetEvent (&gameID) ) ) { if (msg == XBNW_NetworkGame) { const XBNetworkGame *game = Client_NextNetworkGame (); if (gameID < NUM_SEARCH_ROWS) { networkGame[gameID] =( XBNetworkGame *)game; MenuSetActive (networkItem [gameID], ((NULL != game) && (game->frameRate!=0)&& (game->frameRate!=255))); } } } } /* PollNetworkGame */ /* * */ static XBBool ButtonExitSearchLan (void *par) { /* stop network search */ Client_StopQuery (); teamMode=0; /* back to client menu */ return CreateJoinNetGameMenu (par); } /* ButtonExitSearchLan */ /* * */ static XBBool ButtonRefreshSearchLan (void *par) { unsigned i; /* delete old games */ teamMode=0; memset (networkGame, 0, sizeof (networkGame)); for (i = 0; i < NUM_SEARCH_ROWS; i ++) { MenuSetActive (networkItem[i], XBFalse); } /* starts new query */ Client_RestartQuery (); return XBFalse; } /* ButtonRefreshSearchLan */ /* * XBCC */ static XBBool ButtonExitSearchCentral (void *par) { /* stop network search */ Client_StopQuery (); teamMode=0; /* back to client menu */ return CreateJoinNetGameMenu (par); } /* ButtonExitSearchLan */ /* * */ XBBool ButtonRefreshSearchCentral (void *par) { unsigned i; /* delete old games */ teamMode=0; memset (networkGame, 0, sizeof (networkGame)); for (i = 0; i < NUM_SEARCH_ROWS; i ++) { MenuSetActive (networkItem[i], XBFalse); } /* starts new query */ Client_RestartQuery (); return XBFalse; } /* ButtonRefreshSearchLan */ /* * */ static XBBool ButtonStartLanGame (void *par) { const XBNetworkGame **ptr = par; XBBool connect; assert (NULL != ptr); if (NULL == *ptr) { return XBFalse; } /* get server connection */ cfgServer.name = (*ptr)->host; cfgServer.port = (*ptr)->port; /* store in database */ StoreGameHost (CT_Local, networkAtom, &cfgServer); /* now try connection */ connect = Client_Connect (&cfgServer); /* clean up */ Client_StopQuery (); memset (networkGame, 0, sizeof (networkGame)); if (! connect) { /* connection failed */ GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort); return CreateSearchLanMenu (&networkAtom); } return CreateClientWaitMenu (&networkAtom); } /* * */ static XBBool ButtonStartLanGamehis (void *par) { const XBNetworkGame **ptr = par; XBBool connect; int i=0; assert (NULL != ptr); if (NULL == *ptr) { return XBFalse; } /* get server connection */ cfgServer.name = (*ptr)->host; cfgServer.port = (*ptr)->port; /* store in database */ StoreGameHost (CT_Local, networkAtom, &cfgServer); /* now try connection */ connect = Client_Connect (&cfgServer); /* clean up */ Client_StopQuery (); memset (networkGame, 0, sizeof (networkGame)); if (! connect) { /* connection failed */ GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort); return CreateHistoryNetGameMenu (&networkAtom); } /* free networkgamehis, should be implemented!!! somehow i couldnt... for(i=0;ihost; cfgServer.port = (*ptr)->port; /* store in database */ StoreGameHost (CT_Local, networkAtom, &cfgServer); /* now try connection */ connect = Client_Connect (&cfgServer); /* clean up */ Client_StopQuery (); memset (networkGame, 0, sizeof (networkGame)); if (! connect) { /* connection failed */ GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort); return CreateSearchCentralMenu (&networkAtom); } return CreateClientWaitMenu (&networkAtom); } /* * search LAN for network games */ XBBool CreateSearchLanMenu (void *par) { XBAtom *atom = par; int i; assert (NULL != atom); networkAtom = *atom; /* setup */ memset (networkGame, 0, sizeof (networkGame)); (void) RetrieveGameHost (CT_Local, networkAtom, &cfgServer); /* build menu */ MenuClear (); /* Title */ MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Search LAN for Games"); /* list of games */ MenuSetActive (MenuAddGameHeader (SEARCH_LEFT, SEARCH_TOP, SEARCH_WIDTH), XBFalse); for (i = 0; i < NUM_SEARCH_ROWS; i ++) { networkItem[i] = MenuAddGameEntry (SEARCH_LEFT, SEARCH_ROW(i), SEARCH_WIDTH,(const XBNetworkGame **) networkGame + i, ButtonStartLanGame); MenuSetActive (networkItem[i], XBFalse); } /* Buttons */ MenuSetAbort (MenuAddHButton ( 5 * CELL_W/2, MENU_BOTTOM, 4*CELL_W, "Back", ButtonExitSearchLan, par) ); MenuSetDefault (MenuAddHButton (17 * CELL_W/2, MENU_BOTTOM, 4*CELL_W, "Refresh", ButtonRefreshSearchLan, par) ); /* add polling routine */ MenuAddCyclic (PollNetworkGame, NULL); /* query for local games */ Client_StartQuery (); // MenuSetLinks (); should work infinite loop ?? /* that's all*/ return XBFalse; } /* CreateSearchLanMenu */ /* * search CENTRAL for network games XBCC */ XBBool CreateSearchCentralMenu (void *par) { XBAtom *atom = par; int i; assert (NULL != atom); networkAtom = *atom; /* setup */ memset (networkGame, 0, sizeof (networkGame)); (void) RetrieveGameHost (CT_Local, networkAtom, &cfgServer); /* build menu */ MenuClear (); /* Title */ MenuAddLabel2 (TITLE_LEFT-25, TITLE_TOP-15, TITLE_WIDTH+50, "Lamer Rado waits for you in http://irc.xblast-center.com"); MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Central Games"); /* list of games */ MenuSetActive (MenuAddGameHeader (SEARCH_LEFT, SEARCH_TOP, SEARCH_WIDTH), XBFalse); for (i = 0; i < NUM_SEARCH_ROWS; i ++) { networkItem[i] = MenuAddGameEntry (SEARCH_LEFT, SEARCH_ROW(i), SEARCH_WIDTH,( const XBNetworkGame **)networkGame + i, ButtonStartCentralGame); MenuSetActive (networkItem[i], XBFalse); } /* Buttons */ MenuSetAbort (MenuAddHButton ( 5 * CELL_W/2, MENU_BOTTOM, 4*CELL_W, "Back", ButtonExitSearchCentral, par) ); MenuSetDefault (MenuAddHButton (17 * CELL_W/2, MENU_BOTTOM, 4*CELL_W, "Refresh", ButtonRefreshSearchCentral, par) ); /* add polling routine */ MenuAddCyclic (PollNetworkGame, NULL); /* query for local games */ Client_StartCentralQuery (); // MenuSetLinks (); should work infinite loop ?? /* that's all*/ return XBFalse; } /* CreateSearchLanMenu */ /* * end of file menu_network.c */