Implemented 'Ready' button for the lobby. The game starts when all players have clicked on it.

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@4555 4a71c877-e1ca-e34f-864e-861f7616d084
master
Roman C 2008-04-09 20:05:09 +00:00
parent 3c749e2ee3
commit 78f4b01231
8 changed files with 243 additions and 53 deletions

View File

@ -88,6 +88,7 @@ typedef enum
NET_PLAYER_JOINED, //55 notice about player joining
NET_PLAYER_LEFT, //56 notice about player leaving
NET_GAME_FLAGS, //57 game flags
NET_READY_REQUEST, //58 player ready to start an mp game
NUM_GAME_PACKETS
} MESSAGE_TYPES;

View File

@ -113,6 +113,8 @@ static BOOL safeSearch = false; // allow auto game finding.
static UDWORD hideTime=0;
BOOL bPlayerReadyGUI[MAX_PLAYERS] = {false};
#define DEFAULTCAMPAIGNMAP "Rush"
#define DEFAULTSKIRMISHMAP "Sk-Rush"
@ -132,6 +134,7 @@ void intDisplayFeBox (WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIEL
void displayRemoteGame (WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours);
void displayPlayer (WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours);
void displayTeamChooser (WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours);
void displayMultiReady (WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours);
void displayMultiEditBox (WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours);
void setLockedTeamsMode (void);
@ -147,7 +150,6 @@ void runConnectionScreen (void);
BOOL startConnectionScreen (void);
// Game option functions
static void addOkBut (void);
static void addGameOptions (BOOL bRedo); // options (rhs) boxV
UDWORD addPlayerBox (BOOL); // players (mid) box
static void addChatBox (void);
@ -167,6 +169,7 @@ static void closeTeamChooser (void);
static BOOL SendColourRequest (UBYTE player, UBYTE col,UBYTE chosenPlayer);
static BOOL safeToUseColour (UDWORD player,UDWORD col);
BOOL chooseColour (UDWORD);
static BOOL changeReadyStatus (UBYTE player, BOOL bReady);
// ////////////////////////////////////////////////////////////////////////////
// map previews..
@ -923,6 +926,9 @@ static void addColourChooser(UDWORD player)
// detele team chooser botton
widgDelete(psWScreen,MULTIOP_TEAMS_START+player);
// detele 'ready' button
widgDelete(psWScreen,MULTIOP_READY_START+player);
// add form.
addBlueForm(MULTIOP_PLAYERS,MULTIOP_COLCHOOSER_FORM,"",
10,
@ -1026,6 +1032,60 @@ BOOL recvTeamRequest()
return true;
}
static BOOL SendReadyRequest(UBYTE player, BOOL bReady)
{
if(NetPlay.bHost) // do or request the change.
{
return changeReadyStatus(player, bReady);
}
else
{
NETbeginEncode(NET_READY_REQUEST, NET_ALL_PLAYERS);
NETuint8_t(&player);
NETbool(&bReady);
NETend();
}
return true;
}
BOOL recvReadyRequest()
{
UBYTE player;
BOOL bReady;
if(!NetPlay.bHost) //only host should act.
{
return true;
}
NETbeginDecode(NET_READY_REQUEST);
NETuint8_t(&player);
NETbool(&bReady);
NETend();
if (player > MAX_PLAYERS)
{
debug(LOG_ERROR, "Invalid NET_READY_REQUEST from player %d: player id = %d",
NETgetSource(), (int)player);
return false;
}
return changeReadyStatus((UBYTE)player, bReady);
}
static BOOL changeReadyStatus(UBYTE player, BOOL bReady)
{
unsigned int playerGUI_ID;
for(playerGUI_ID=0;(playerGUI_ID <= game.maxPlayers) &&
(player2dpid[player] != NetPlay.players[playerGUI_ID].dpid);playerGUI_ID++);
bPlayerReadyGUI[playerGUI_ID] = bReady;
sendOptions(player2dpid[player], player); // tell everyone && update requesting player.
return true;
}
static BOOL changeColour(UBYTE player, UBYTE col, UBYTE chosenPlayer)
{
if(chosenPlayer == UBYTE_MAX)
@ -1128,6 +1188,9 @@ static void addTeamChooser(UDWORD player)
// delete that players box
widgDelete(psWScreen,MULTIOP_PLAYER_START+player);
// delete 'ready' button
widgDelete(psWScreen,MULTIOP_READY_START+player);
// add form.
addBlueForm(MULTIOP_PLAYERS,MULTIOP_TEAMCHOOSER_FORM,"",
10,
@ -1263,7 +1326,7 @@ UDWORD addPlayerBox(BOOL players)
sButInit.style = WBUT_PLAIN;
sButInit.x = 10 + MULTIOP_TEAMSWIDTH;
sButInit.y = (UWORD)(( (MULTIOP_PLAYERHEIGHT+5)*i)+4);
sButInit.width = MULTIOP_PLAYERWIDTH - MULTIOP_TEAMSWIDTH;
sButInit.width = MULTIOP_PLAYERWIDTH - MULTIOP_TEAMSWIDTH - MULTIOP_READY_WIDTH;
sButInit.height = MULTIOP_PLAYERHEIGHT;
sButInit.pTip = NULL;//Players[i].name;
sButInit.FontID = font_regular;
@ -1280,6 +1343,29 @@ UDWORD addPlayerBox(BOOL players)
widgAddButton(psWScreen, &sButInit);
}
// add 'ready' button
memset(&sButInit, 0, sizeof(W_BUTINIT));
sButInit.formID = MULTIOP_PLAYERS;
sButInit.id = MULTIOP_READY_START+i;
sButInit.style = WBUT_PLAIN;
sButInit.x = 10 + MULTIOP_PLAYERWIDTH - MULTIOP_READY_WIDTH;
sButInit.y = (UWORD)(( (MULTIOP_PLAYERHEIGHT+5)*i)+4);
sButInit.width = MULTIOP_READY_WIDTH;
sButInit.height = MULTIOP_READY_HEIGHT;
sButInit.FontID = font_regular;
sButInit.pDisplay = displayMultiReady;
sButInit.UserData = i;
if(bPlayerReadyGUI[i])
{
sButInit.pTip = "Ready";
}
else
{
sButInit.pTip = "Click when ready";
}
widgAddButton(psWScreen, &sButInit);
}
else if(game.type == SKIRMISH) // skirmish player
{
@ -1330,16 +1416,6 @@ void kickPlayer(uint32_t player_id)
NETend();
}
static void addOkBut(void)
{
addMultiBut(psWScreen, MULTIOP_OPTIONS,CON_OK,
MULTIOP_OKX,MULTIOP_OKY,
iV_GetImageWidth(FrontImages,IMAGE_BIGOK),
iV_GetImageHeight(FrontImages,IMAGE_BIGOK),
_("Accept Settings"),IMAGE_BIGOK,IMAGE_BIGOK,false);
}
static void addChatBox(void)
{
W_FORMINIT sFormInit;
@ -1616,7 +1692,6 @@ static void processMultiopWidgets(UDWORD id)
{
sendOptions(0,0);
disableMultiButs();
addOkBut();
}
break;
@ -1627,7 +1702,6 @@ static void processMultiopWidgets(UDWORD id)
{
disableMultiButs();
sendOptions(0,0);
addOkBut();
}
break;
@ -1638,7 +1712,6 @@ static void processMultiopWidgets(UDWORD id)
{
sendOptions(0,0);
disableMultiButs();
addOkBut();
}
break;
@ -1762,7 +1835,6 @@ static void processMultiopWidgets(UDWORD id)
addGameOptions(false); // update game options box.
addChatBox();
addOkBut();
disableMultiButs();
@ -1797,42 +1869,6 @@ static void processMultiopWidgets(UDWORD id)
widgSetString(psWScreen, MULTIOP_CHATEDIT, ""); // clear box
break;
case CON_OK:
decideWRF(); // set up swrf & game.map
bMultiPlayer = true;
if(NetPlay.bHost)
{
///////////
//
if(game.type == SKIRMISH)
{
chooseSkirmishColours();
sendOptions(0,0);
}
// end of skirmish col choose
////////
NEThaltJoining(); // stop new players entering.
SendFireUp(); //bcast a fireup message
}
// set the fog correctly..
setRevealStatus(game.fog);
war_SetFog(!game.fog);
changeTitleMode(STARTGAME);
bHosted = false;
if(NetPlay.bHost)
{
sendTextMessage(_("Host is Starting Game"),true);
}
return;
break;
case CON_CANCEL:
stopJoining();
break;
@ -1894,6 +1930,23 @@ static void processMultiopWidgets(UDWORD id)
}
}
// 'ready' button
if((id >= MULTIOP_READY_START) && (id <= MULTIOP_READY_END)) // clicked on a player
{
UBYTE player = (UBYTE)(id-MULTIOP_READY_START);
if(NetPlay.players[player].dpid == player2dpid[selectedPlayer] )
{
SendReadyRequest(selectedPlayer, !bPlayerReadyGUI[player]);
// if hosting try to start the game if everyone is ready
if(NetPlay.bHost && multiplayPlayersReady(false))
{
startMultiplayerGame();
}
}
}
if((id >= MULTIOP_PLAYER_START) && (id <= MULTIOP_PLAYER_END)) // clicked on a player
{
if(NetPlay.players[id-MULTIOP_PLAYER_START].dpid == player2dpid[selectedPlayer] )
@ -1971,6 +2024,38 @@ static void processMultiopWidgets(UDWORD id)
}
/* Start a multiplayer or skirmish game */
void startMultiplayerGame(void)
{
decideWRF(); // set up swrf & game.map
bMultiPlayer = true;
if(NetPlay.bHost)
{
if(game.type == SKIRMISH)
{
chooseSkirmishColours();
sendOptions(0,0);
}
NEThaltJoining(); // stop new players entering.
SendFireUp(); //bcast a fireup message
}
// set the fog correctly..
setRevealStatus(game.fog);
war_SetFog(!game.fog);
changeTitleMode(STARTGAME);
bHosted = false;
if(NetPlay.bHost)
{
sendTextMessage(_("Host is Starting Game"),true);
}
}
// ////////////////////////////////////////////////////////////////////////////
// Net message handling
@ -2014,6 +2099,16 @@ void frontendMultiMessages(void)
recvTeamRequest();
break;
case NET_READY_REQUEST:
recvReadyRequest();
// if hosting try to start the game if everyone is ready
if(NetPlay.bHost && multiplayPlayersReady(false))
{
startMultiplayerGame();
}
break;
case NET_PING: // diagnostic ping msg.
recvPing();
break;
@ -2301,7 +2396,6 @@ BOOL startMultiOptions(BOOL bReenter)
if(bReenter && bHosted)
{
disableMultiButs();
addOkBut();
}
return true;
@ -2433,6 +2527,21 @@ static UDWORD bestPlayer(UDWORD player)
return count;
}
void displayMultiReady(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours)
{
UDWORD x = xOffset+psWidget->x;
UDWORD y = yOffset+psWidget->y;
BOOL Hilight = false;
if( ((W_BUTTON*)psWidget)->state & (WBUTS_HILITE| WCLICK_DOWN | WCLICK_LOCKED | WCLICK_CLICKLOCK))
{
Hilight = true;
}
//bluboxes.
drawBlueBox(x,y,psWidget->width,psWidget->height); // right
}
void displayTeamChooser(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours)
{
UDWORD x = xOffset+psWidget->x;
@ -2674,6 +2783,18 @@ void displayPlayer(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *p
//unknown bugfix
// game.skirmishPlayers[i] =true; // don't clear this one!
game.skDiff[i]=UBYTE_MAX; // don't clear this one!
// draw 'ready' button state
if(bPlayerReadyGUI[i])
{
iV_DrawImage(FrontImages,IMAGE_OK,x+MULTIOP_READY_IMG_OFFSET_X,
y+MULTIOP_READY_IMG_OFFSET_Y);
}
else
{
iV_DrawImage(FrontImages,IMAGE_NO,x+MULTIOP_READY_IMG_OFFSET_X,
y+MULTIOP_READY_IMG_OFFSET_Y);
}
}
else
{
@ -2901,3 +3022,30 @@ void setLockedTeamsMode(void)
sendOptions(0,0);
}
}
/* Returns true if all human players clicked on the 'ready' button */
bool multiplayPlayersReady(bool bNotifyStatus)
{
unsigned int player,playerID;
bool bReady;
bReady = true;
for(player = 0; player < game.maxPlayers; player++)
{
// check if this human player is ready, ignore AIs
if(NetPlay.players[player].dpid && !bPlayerReadyGUI[player])
{
if(bNotifyStatus)
{
for(playerID=0;(playerID <= game.maxPlayers) && (player2dpid[playerID] != NetPlay.players[player].dpid);playerID++);
console("%s is not ready", getPlayerName(playerID));
}
bReady = false;
}
}
return bReady;
}

View File

@ -42,6 +42,7 @@ extern BOOL addMultiBut(W_SCREEN *screen, UDWORD formid, UDWORD id, UDWORD x, UD
extern char sPlayer[128];
extern SDWORD playerTeamGUI[MAX_PLAYERS];
extern SDWORD playerTeam[MAX_PLAYERS];
extern BOOL bPlayerReadyGUI[MAX_PLAYERS];
void kickPlayer (uint32_t dpid);
UDWORD addPlayerBox (BOOL); // players (mid) box
@ -143,6 +144,14 @@ void loadMapPreview(void);
#define MULTIOP_TEAMCHOOSER 102810
#define MULTIOP_TEAMCHOOSER_END 102817
// 'Ready' button
#define MULTIOP_READY_START 102900
#define MULTIOP_READY_WIDTH 41
#define MULTIOP_READY_HEIGHT 36
#define MULTIOP_READY_IMG_OFFSET_X 158
#define MULTIOP_READY_IMG_OFFSET_Y 8
#define MULTIOP_READY_END 102907
#define MULTIOP_PLAYERWIDTH 230
#define MULTIOP_PLAYERHEIGHT 36

View File

@ -288,6 +288,8 @@ BOOL MultiPlayerJoin(UDWORD dpid)
setupNewPlayer(dpid,i); // setup all the guff for that player.
sendOptions(dpid,i);
bPlayerReadyGUI[dpid] = false;
// if skirmish and game full, then kick...
if(game.type == SKIRMISH && NetPlay.playercount > game.maxPlayers )
{

View File

@ -135,6 +135,12 @@ void sendOptions(uint32_t dest, uint32_t play)
NETuint8_t(&ingame.pStructureLimits[i].limit);
}
// Send ready status of all players
for (i = 0; i < MAX_PLAYERS; i++)
{
NETbool(&bPlayerReadyGUI[i]);
}
NETend();
}
@ -248,6 +254,12 @@ void recvOptions()
NETuint8_t(&ingame.pStructureLimits[i].limit);
}
// Receive ready status of all players
for (i = 0; i < MAX_PLAYERS; i++)
{
NETbool(&bPlayerReadyGUI[i]);
}
NETend();
// Post process
@ -335,6 +347,8 @@ BOOL hostCampaign(char *sGame, char *sPlayer)
setMultiStats(NetPlay.dpidPlayer,playerStats,false);
setMultiStats(NetPlay.dpidPlayer,playerStats,true);
bPlayerReadyGUI[0] = false;
if(!NetPlay.bComms)
{
NETplayerInfo();

View File

@ -111,6 +111,9 @@ static BOOL recvBeacon(void);
static BOOL recvDestroyTemplate(void);
static BOOL recvResearch(void);
bool multiplayPlayersReady (bool bNotifyStatus);
void startMultiplayerGame (void);
// ////////////////////////////////////////////////////////////////////////////
// temporarily disable multiplayer mode.
BOOL turnOffMultiMsg(BOOL bDoit)
@ -750,6 +753,15 @@ BOOL recvMessage(void)
case NET_TEAMREQUEST:
recvTeamRequest();
break;
case NET_READY_REQUEST:
recvReadyRequest();
// if hosting try to start the game if everyone is ready
if(NetPlay.bHost && multiplayPlayersReady(false))
{
startMultiplayerGame();
}
break;
case NET_ARTIFACTS:
recvMultiPlayerRandomArtifacts();
break;

View File

@ -214,4 +214,7 @@ extern BOOL msgStackGetDroid(DROID **ppsDroid);
extern BOOL sendBeacon(int32_t locX, int32_t locY, int32_t forPlayer, int32_t sender, const char* pStr);
extern BOOL msgStackFireTop(void);
extern bool multiplayPlayersReady(bool bNotifyStatus);
extern void startMultiplayerGame(void);
#endif // __INCLUDED_SRC_MULTIPLAY_H__

View File

@ -65,5 +65,6 @@ extern BOOL recvMapFileRequested (void);
extern BOOL recvTextMessageAI (void); //AI multiplayer message
extern BOOL recvTeamRequest (void);
extern BOOL recvReadyRequest (void);
#endif // __INCLUDED_SRC_MULTIRECV_H__