/* * file game_client.c - run game as client * * $Id: game_client.c,v 1.9 2004/06/28 10:16:34 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 "game_client.h" #include "atom.h" #include "bomb.h" #include "client.h" #include "intro.h" #include "demo.h" #include "cfg_level.h" #include "game.h" #include "level.h" #include "status.h" #include "geom.h" #include "bot.h" /* * local variables */ static CFGGame clientGame; static PlayerAction clientAction[MAX_PLAYER]; static XBBool playerLinked[MAX_PLAYER]; /* * */ static void InitPlayerLink (void) { int i; assert (clientGame.players.num <= MAX_PLAYER); for (i = 0; i < clientGame.players.num; i ++) { playerLinked[i] = XBTrue; } for (; i < MAX_PLAYER; i ++) { playerLinked[i] = XBFalse; } } /* InitPlayerLink */ /* * */ static XBBool UpdatePlayerLink (void) { int i; XBBool result = XBFalse; for (i = 0; i < clientGame.players.num; i ++) { if (! playerLinked[i] && ! player_stat[i].in_active) { player_stat[i].in_active = XBTrue; result = XBTrue; } } return result; } /* UpdatePlayerLink */ /* * wait for level data from server */ static int WaitForServerEvent (XBNetworkEvent waitEvent, XBBool needFlush) { XBEventData eData; XBNetworkEvent netEvent; unsigned id; XBPlayerHost host; int i,j; /* set event handling */ GUI_SetTimer (FRAME_TIME, XBTrue); GUI_SetKeyboardMode (KB_NONE); GUI_SetMouseMode (XBFalse); while (1) { /* update window */ GameUpdateWindow (); /* wait for next event */ if (XBE_TIMER == GUI_WaitEvent (&eData) ) { /* try to flush udp connections */ if (needFlush) { needFlush = Client_FlushPlayerAction (); } /* check for incong network events */ while (XBNW_None != (netEvent = Network_GetEvent (&id) ) ) { if (netEvent == waitEvent) { #ifdef DEBUG if(waitEvent>=XBNW_P0) Dbg_Out(" player won here %i remote %i\n",waitEvent,netEvent); #endif return 0; } else if (netEvent == XBNW_Disconnected) { /* check if any host has disconnected ... */ if (id == 0) { Dbg_Out(" wait event %i netevent %i\n",waitEvent,netEvent); /* ... the server, game is over */ Client_Disconnect (); return 1; } else { /* just one of the clients ... */ host = XBPH_Client1 + id - 1; for (i = 0; i < clientGame.players.num; i ++) { if (clientGame.players.host[i] == host) { playerLinked[i] = XBFalse; Dbg_Out ("unlink player %d\n", i + 1); } } } } else if (netEvent == XBNW_Error) { Dbg_Out(" returning 1\n"); Dbg_Out ("lost connection in wait for server \n"); return 1; /* lost connection */ } else if(netEvent == XBNW_ASYNC){ Dbg_Out(" returning 2\n"); Dbg_Out ("async in wait for server \n"); return 2; /* async */ }else{ /* it shouldnt get here the server should send async and not wrong player if there are problems and it gets here, maybe a solution would be return 2 but the game score in the server would be incorrect(async game) !*/ // fprintf(stderr," wait event %i netevent %i\n",waitEvent,netEvent); if(waitEvent>=XBNW_P0){ for(j=0;jlocal) { break; } } if(clientGame.setup.bot||ps->bot==XBTrue){ gestionBot (player_stat,clientAction,counter-1,clientGame.players.num); } /* handle game turn */ GameTurn (gameTime, clientGame.players.num, &numActive); /* send own keys to server */ Client_SendPlayerAction (gameTime, clientAction); /* insert keys from server */ Client_GetPlayerAction (gameTime, clientAction); /* record demo if needed */ if (clientGame.setup.recordDemo) { DemoRecordFrame (gameTime, clientAction); } /* evaluate input data */ (void) GameEvalAction (clientGame.players.num, clientAction); /* update window */ GameUpdateWindow (); } while (1); Finish: Dbg_Out("End of Level \n"); /* send finish message */ Client_FinishPlayerAction (gameTime + 1); /* wait for server to acknowledge */ LevelResult (gameTime, &lastTeam, clientGame.players.num, level, XBFalse); event=XBNW_P0; if (lastTeam <= MAX_PLAYER) { for (ps = player_stat,counter=1; ps < player_stat + clientGame.players.num; ps ++,counter++) { if (ps->team == lastTeam) { event=XBNW_P0+counter; winner=counter; } } } /* finisg demo file if needed */ if (clientGame.setup.recordDemo) { DemoFinishLevel (gameTime,winner); } Dbg_Out("Level End waiting event %i \n",event); if (SyncWithServer (event, XBTrue, XBFalse)==0) { /* calc result etc */ msg = LevelResult (gameTime, &lastTeam, clientGame.players.num, level, XBTrue); /* show message and winner Animation */ if (! LevelEnd (clientGame.players.num, lastTeam, msg, XBTrue) ) { lastTeam = -1; } } /* clean up */ Exit: DeleteAllExplosions (); FinishLevel (); /* fade out image */ DoFade (XBFM_BLACK_OUT, PIXH+1); /* thatīs all */ return lastTeam; } /* ClientRunLevel */ /* * */ void RunClientGame (XBPlayerHost hostType) { const DBRoot *level; int lastTeam; int teamActive, reinco; int i, maxNumWins; int numActive; XBBool connected = XBTrue; XBBool initDone = XBFalse; /* get game configs */ if (! RetrieveGame (CT_Remote, atomArrayHost0[0], &clientGame) ) { goto Exit; } /* common inits */ if (! InitGame (hostType, CT_Remote, &clientGame, clientAction)) { goto Exit; } initDone = XBTrue; /* init connection status */ InitPlayerLink (); /* clear level data for next run */ ClearRemoteLevelConfig (); /* sync with server */ Dbg_Out(" syncendofinit \n"); if (SyncWithServer (XBNW_SyncEndOfInit, XBFalse, XBFalse)==1 ) { connected = XBFalse; goto Exit; } /* game loop */ maxNumWins = 0; numActive = clientGame.players.num; teamActive=0; reinco=0; if(clientGame.setup.teamMode) { for (i = 0; i < clientGame.players.num; i ++) { if (! player_stat[i].in_active) { if(!(reinco&(1 << player_stat[i].team))) { reinco|=1 << player_stat[i].team; teamActive++; } } } } else { for (i = 0; i < clientGame.players.num; i ++) { if (! player_stat[i].in_active) { teamActive ++; } } } Dbg_Out ("There are according to reinco %i teams\n", teamActive); do { /* load and run next level */ if (NULL == (level = LevelFromServer () ) ) { connected = XBFalse; goto Exit; } Dbg_Out (" starting level\n"); lastTeam = ClientRunLevel (teamActive, level); /* check for quick exit */ if (-1 == lastTeam) { goto Exit; } /* calculate new maxmium # of victories */ for (i = 0; i < clientGame.players.num; i ++) { if (player_stat[i].victories > maxNumWins) { maxNumWins = player_stat[i].victories; } } /* clear level data for next run */ ClearRemoteLevelConfig (); /* sync before showing score board */ Client_SendSync (XBNW_SyncLevelEnd); if (SyncWithServer (XBNW_SyncLevelEnd, XBFalse, XBTrue)==1 ) { goto Exit; } /* correct number of players */ UpdatePlayerLink (); /* show scores */ if (! ShowScoreBoard (lastTeam, maxNumWins, clientGame.players.num, player_stat, XBTrue)) { goto Exit; } /* clear level data for next run */ ClearRemoteLevelConfig (); /* sync after showing score board */ if (SyncWithServer (XBNW_SyncScoreboard, XBFalse, XBTrue)==1 ) { goto Exit; } /* determine number of active players */ reinco=0; teamActive=0; numActive = 0; for (i = 0; i < clientGame.players.num; i ++) { if (! player_stat[i].in_active) { numActive ++; if(clientGame.setup.teamMode) { if(!(reinco&(1 << player_stat[i].team))) { reinco|=1 << player_stat[i].team; teamActive++; } } else { teamActive++; } } } Dbg_Out ("%d active teams\n", teamActive); Dbg_Out ("%d active players\n", numActive); } while (numActive > 1 && teamActive > 1 && maxNumWins < clientGame.setup.numWins); /* TODO: socket is not closed properly here !!! */ SetMessage ("Waiting for server", XBTrue); (void) WaitForServerEvent (XBNW_None, XBFalse); /* and the winner is ... */ // XBCC send password or someting ?? InitWinner (clientGame.players.num); ShowWinner (lastTeam, clientGame.players.num, player_stat); /* that' all */ FinishGame (&clientGame); return; /* * fast exit via Escape key ... */ Exit: Dbg_Out ("aborting client game\n"); if (connected) { Client_Disconnect (); } else { GUI_ErrorMessage ("Lost connection to server\n"); } if (initDone) { FinishGame (&clientGame); } return; } /* RunClientGame */ /* * end of file game_client.c */