2007-01-15 12:09:25 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
2013-01-16 12:34:57 -08:00
Copyright ( C ) 2005 - 2013 Warzone 2100 Project
2007-01-15 12:09:25 -08:00
Warzone 2100 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 of the License , or
( at your option ) any later version .
Warzone 2100 is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY 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 Warzone 2100 ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2007-06-28 10:47:08 -07:00
/*
* MultiInt . c
*
* Alex Lee , 98. Pumpkin Studios , Bath .
2008-03-09 08:45:05 -07:00
* Functions to display and handle the multiplayer interface screens ,
* along with connection and game options .
2007-06-28 10:47:08 -07:00
*/
2011-12-11 15:07:02 -08:00
# include "lib/framework/wzapp.h"
2011-12-11 06:51:31 -08:00
# include "lib/framework/wzconfig.h"
2007-04-11 07:21:45 -07:00
2008-03-16 05:39:08 -07:00
# include <time.h>
2006-06-16 12:10:23 -07:00
2006-09-23 11:38:12 -07:00
# include "lib/framework/frameresource.h"
2008-03-16 05:39:08 -07:00
# include "lib/framework/file.h"
2009-02-10 09:23:09 -08:00
# include "lib/framework/stdio_ext.h"
2007-06-28 10:47:08 -07:00
/* Includes direct access to render library */
2010-12-31 13:37:14 -08:00
# include "lib/ivis_opengl/bitimage.h"
# include "lib/ivis_opengl/pieblitfunc.h"
# include "lib/ivis_opengl/piedef.h"
# include "lib/ivis_opengl/piestate.h"
# include "lib/ivis_opengl/pieclip.h"
# include "lib/ivis_opengl/piemode.h"
# include "lib/ivis_opengl/piepalette.h"
2008-03-16 05:39:08 -07:00
# include "lib/ivis_opengl/screen.h"
# include "lib/gamelib/gtime.h"
# include "lib/netplay/netplay.h"
# include "lib/script/script.h"
2008-03-23 12:08:49 -07:00
# include "lib/widget/editbox.h"
# include "lib/widget/button.h"
2008-03-16 05:39:08 -07:00
# include "lib/widget/widget.h"
2008-03-23 12:08:49 -07:00
# include "lib/widget/widgint.h"
2009-04-19 11:45:28 -07:00
# include "lib/widget/label.h"
2008-03-16 05:39:08 -07:00
2009-08-11 13:36:44 -07:00
# include "challenge.h"
2008-03-16 05:39:08 -07:00
# include "main.h"
# include "objects.h"
# include "display.h"// pal stuff
# include "display3d.h"
2007-06-28 10:47:08 -07:00
# include "objmem.h"
# include "gateway.h"
2008-03-16 05:39:08 -07:00
2007-06-28 10:47:08 -07:00
# include "configuration.h"
# include "intdisplay.h"
# include "design.h"
# include "hci.h"
# include "power.h"
# include "loadsave.h" // for blueboxes.
# include "component.h"
# include "map.h"
# include "console.h" // chat box stuff
# include "frend.h"
# include "advvis.h"
# include "frontend.h"
# include "data.h"
# include "keymap.h"
2007-02-25 04:57:04 -08:00
# include "game.h"
2007-04-01 13:15:46 -07:00
# include "warzoneconfig.h"
2010-01-17 12:12:03 -08:00
# include "modding.h"
2011-01-23 13:30:57 -08:00
# include "qtscript.h"
2012-03-31 06:19:22 -07:00
# include "random.h"
2007-06-28 10:47:08 -07:00
# include "multiplay.h"
# include "multiint.h"
2013-02-24 11:50:37 -08:00
# if defined(WZ_CC_MSVC)
# include "multiint_moc.h" // this is generated on the pre-build event.
# endif
2007-06-28 10:47:08 -07:00
# include "multijoin.h"
# include "multistat.h"
# include "multirecv.h"
# include "multimenu.h"
2009-12-18 16:31:58 -08:00
# include "multilimit.h"
2010-02-09 09:43:53 -08:00
# include "multigifts.h"
2007-06-28 10:47:08 -07:00
2007-03-27 10:53:48 -07:00
# include "warzoneconfig.h"
2006-02-11 01:00:20 -08:00
# include "init.h"
2007-06-28 10:47:08 -07:00
# include "levels.h"
2012-01-30 17:38:15 -08:00
# include "wrappers.h"
2008-08-27 00:25:48 -07:00
2008-04-07 12:07:43 -07:00
# define MAP_PREVIEW_DISPLAY_TIME 2500 // number of milliseconds to show map in preview
2009-08-29 16:33:35 -07:00
// ////////////////////////////////////////////////////////////////////////////
// tertile dependant colors for map preview
// C1 - Arizona type
# define WZCOL_TERC1_CLIFF_LOW pal_Colour(0x68, 0x3C, 0x24)
# define WZCOL_TERC1_CLIFF_HIGH pal_Colour(0xE8, 0x84, 0x5C)
# define WZCOL_TERC1_WATER pal_Colour(0x3F, 0x68, 0x9A)
# define WZCOL_TERC1_ROAD_LOW pal_Colour(0x24, 0x1F, 0x16)
# define WZCOL_TERC1_ROAD_HIGH pal_Colour(0xB2, 0x9A, 0x66)
# define WZCOL_TERC1_GROUND_LOW pal_Colour(0x24, 0x1F, 0x16)
# define WZCOL_TERC1_GROUND_HIGH pal_Colour(0xCC, 0xB2, 0x80)
// C2 - Urban type
# define WZCOL_TERC2_CLIFF_LOW pal_Colour(0x3C, 0x3C, 0x3C)
# define WZCOL_TERC2_CLIFF_HIGH pal_Colour(0x84, 0x84, 0x84)
# define WZCOL_TERC2_WATER WZCOL_TERC1_WATER
# define WZCOL_TERC2_ROAD_LOW pal_Colour(0x00, 0x00, 0x00)
# define WZCOL_TERC2_ROAD_HIGH pal_Colour(0x24, 0x1F, 0x16)
# define WZCOL_TERC2_GROUND_LOW pal_Colour(0x1F, 0x1F, 0x1F)
# define WZCOL_TERC2_GROUND_HIGH pal_Colour(0xB2, 0xB2, 0xB2)
// C3 - Rockies type
# define WZCOL_TERC3_CLIFF_LOW pal_Colour(0x3C, 0x3C, 0x3C)
# define WZCOL_TERC3_CLIFF_HIGH pal_Colour(0xFF, 0xFF, 0xFF)
# define WZCOL_TERC3_WATER WZCOL_TERC1_WATER
# define WZCOL_TERC3_ROAD_LOW pal_Colour(0x24, 0x1F, 0x16)
# define WZCOL_TERC3_ROAD_HIGH pal_Colour(0x3D, 0x21, 0x0A)
# define WZCOL_TERC3_GROUND_LOW pal_Colour(0x00, 0x1C, 0x0E)
# define WZCOL_TERC3_GROUND_HIGH WZCOL_TERC3_CLIFF_HIGH
2011-01-03 06:27:06 -08:00
static const unsigned gnImage [ ] = { IMAGE_GN_0 , IMAGE_GN_1 , IMAGE_GN_2 , IMAGE_GN_3 , IMAGE_GN_4 , IMAGE_GN_5 , IMAGE_GN_6 , IMAGE_GN_7 , IMAGE_GN_8 , IMAGE_GN_9 , IMAGE_GN_10 , IMAGE_GN_11 , IMAGE_GN_12 , IMAGE_GN_13 , IMAGE_GN_14 , IMAGE_GN_15 } ;
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
2006-05-27 09:37:17 -07:00
// vars
2007-09-16 07:05:01 -07:00
extern char MultiCustomMapsPath [ PATH_MAX ] ;
extern char MultiPlayersPath [ PATH_MAX ] ;
2011-03-12 17:32:15 -08:00
extern bool bSendingMap ; // used to indicate we are sending a map
2007-06-28 10:47:08 -07:00
2011-03-12 17:32:15 -08:00
bool bHosted = false ; //we have set up a game
2006-08-12 09:52:37 -07:00
char sPlayer [ 128 ] ; // player name (to be used)
2010-01-04 23:13:16 -08:00
static int colourChooserUp = - 1 ;
2009-06-07 11:10:13 -07:00
static int teamChooserUp = - 1 ;
2011-01-09 07:35:49 -08:00
static int aiChooserUp = - 1 ;
static int difficultyChooserUp = - 1 ;
2011-01-04 09:51:15 -08:00
static int positionChooserUp = - 1 ;
2011-03-12 17:32:15 -08:00
static bool SettingsUp = false ;
2012-01-07 15:52:38 -08:00
static UBYTE InitialProto = 0 ;
2007-06-28 10:47:08 -07:00
static W_SCREEN * psConScreen ;
2006-11-04 15:16:51 -08:00
static SDWORD dwSelectedGame = 0 ; //player[] and games[] indexes
2007-06-28 10:47:08 -07:00
static UDWORD gameNumber ; // index to games icons
2011-03-12 17:32:15 -08:00
static bool safeSearch = false ; // allow auto game finding.
2009-04-19 11:45:28 -07:00
static bool disableLobbyRefresh = false ; // if we allow lobby to be refreshed or not.
2007-06-28 10:47:08 -07:00
static UDWORD hideTime = 0 ;
2009-04-19 11:45:28 -07:00
static bool EnablePasswordPrompt = false ; // if we need the password prompt
LOBBY_ERROR_TYPES LobbyError = ERROR_NOERROR ;
2012-01-10 18:52:01 -08:00
static char tooltipbuffer [ MaxGames ] [ 256 ] = { { ' \0 ' } } ;
2013-02-16 19:18:26 -08:00
static bool toggleFilter = true ; // Used to show all games or only games that are of the same version
2007-06-28 10:47:08 -07:00
/// end of globals.
// ////////////////////////////////////////////////////////////////////////////
// Function protos
// widget functions
2011-03-12 17:32:15 -08:00
static bool addMultiEditBox ( UDWORD formid , UDWORD id , UDWORD x , UDWORD y , char const * tip , char const * tipres , UDWORD icon , UDWORD iconhi , UDWORD iconid ) ;
2007-04-09 15:09:27 -07:00
static void addBlueForm ( UDWORD parent , UDWORD id , const char * txt , UDWORD x , UDWORD y , UDWORD w , UDWORD h ) ;
2008-05-03 10:43:55 -07:00
static void drawReadyButton ( UDWORD player ) ;
2007-06-28 10:47:08 -07:00
// Drawing Functions
2013-02-26 01:45:50 -08:00
static void displayChatEdit ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void intDisplayFeBox ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayRemoteGame ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayPlayer ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayPosition ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayColour ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayTeamChooser ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayAi ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayDifficulty ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
static void displayMultiEditBox ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset ) ;
2013-02-25 10:25:05 -08:00
static Image getFrontHighlightImage ( Image image ) ;
2007-06-28 10:47:08 -07:00
// find games
2006-09-13 02:09:05 -07:00
static void addGames ( void ) ;
2010-01-03 01:17:55 -08:00
static void removeGames ( void ) ;
2007-06-28 10:47:08 -07:00
2010-01-03 01:17:55 -08:00
// password form functions
static void hidePasswordForm ( void ) ;
static void showPasswordForm ( void ) ;
2007-06-28 10:47:08 -07:00
// Game option functions
2011-01-04 09:51:15 -08:00
static void addGameOptions ( ) ;
2006-09-13 02:09:05 -07:00
static void addChatBox ( void ) ;
2012-01-10 18:24:32 -08:00
static void addConsoleBox ( void ) ;
2006-09-13 02:09:05 -07:00
static void disableMultiButs ( void ) ;
static void processMultiopWidgets ( UDWORD ) ;
static void SendFireUp ( void ) ;
2009-04-19 14:42:52 -07:00
2006-09-13 02:09:05 -07:00
static void decideWRF ( void ) ;
2007-06-28 10:47:08 -07:00
2006-09-13 02:09:05 -07:00
static void closeColourChooser ( void ) ;
2006-09-26 11:14:05 -07:00
static void closeTeamChooser ( void ) ;
2011-01-04 09:51:15 -08:00
static void closePositionChooser ( void ) ;
2011-01-09 07:35:49 -08:00
static void closeAiChooser ( void ) ;
static void closeDifficultyChooser ( void ) ;
2011-03-12 17:32:15 -08:00
static bool SendColourRequest ( UBYTE player , UBYTE col ) ;
static bool SendPositionRequest ( UBYTE player , UBYTE chosenPlayer ) ;
static bool safeToUseColour ( UDWORD player , UDWORD col ) ;
static bool changeReadyStatus ( UBYTE player , bool bReady ) ;
2009-02-21 14:09:58 -08:00
static void stopJoining ( void ) ;
2011-01-09 07:35:49 -08:00
static int difficultyIcon ( int difficulty ) ;
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
// map previews..
2011-05-21 12:59:46 -07:00
static const char * difficultyList [ ] = { N_ ( " Easy " ) , N_ ( " Medium " ) , N_ ( " Hard " ) , N_ ( " Insane " ) } ;
2011-01-09 07:35:49 -08:00
static const int difficultyValue [ ] = { 1 , 10 , 15 , 20 } ;
2013-01-05 08:02:08 -08:00
static struct
{
bool scavengers ;
bool alliances ;
bool teams ;
bool power ;
bool difficulty ;
bool ai ;
bool position ;
bool bases ;
} locked ;
2011-01-09 07:35:49 -08:00
struct AIDATA
{
2013-11-17 07:02:07 -08:00
AIDATA ( ) : assigned ( 0 ) { }
2011-01-09 07:35:49 -08:00
char name [ MAX_LEN_AI_NAME ] ;
char slo [ MAX_LEN_AI_NAME ] ;
char vlo [ MAX_LEN_AI_NAME ] ;
2011-01-23 13:30:57 -08:00
char js [ MAX_LEN_AI_NAME ] ;
2011-01-09 07:35:49 -08:00
char tip [ 255 ] ;
int assigned ; ///< How many AIs have we assigned of this type
} ;
static std : : vector < AIDATA > aidata ;
2012-01-14 13:49:44 -08:00
/// Player name overrides
static char nameOverrides [ MAX_PLAYERS ] [ MAX_LEN_AI_NAME ] ;
2013-02-20 00:50:21 -08:00
struct WzMultiButton : public W_BUTTON
{
WzMultiButton ( WIDGET * parent ) : W_BUTTON ( parent ) { }
2013-02-26 01:45:50 -08:00
void display ( int xOffset , int yOffset ) ;
2013-02-20 00:50:21 -08:00
Image imNormal ;
Image imDown ;
unsigned doHighlight ;
unsigned tc ;
} ;
2011-01-09 07:35:49 -08:00
const char * getAIName ( int player )
{
2011-01-15 04:29:23 -08:00
if ( NetPlay . players [ player ] . ai > = 0 )
{
return aidata [ NetPlay . players [ player ] . ai ] . name ;
}
else
{
return " " ;
}
2011-01-09 07:35:49 -08:00
}
int getNextAIAssignment ( const char * name )
{
int ai = matchAIbyName ( name ) ;
int match = aidata [ ai ] . assigned ;
2011-07-17 12:41:06 -07:00
2011-01-09 07:35:49 -08:00
for ( int i = 0 ; i < game . maxPlayers ; i + + )
{
if ( ai = = NetPlay . players [ i ] . ai )
{
if ( match = = 0 )
{
aidata [ ai ] . assigned + + ;
2012-02-08 13:44:16 -08:00
debug ( LOG_SAVE , " wzscript assigned to player %d " , i ) ;
2011-01-09 07:35:49 -08:00
return i ; // found right player
}
match - - ; // find next of this type
}
}
return AI_NOT_FOUND ;
}
2011-01-12 12:15:25 -08:00
void loadMultiScripts ( )
2011-01-09 07:35:49 -08:00
{
2012-01-13 14:00:14 -08:00
bool defaultRules = true ;
2013-01-05 08:02:08 -08:00
char aFileName [ 256 ] ;
char aPathName [ 256 ] ;
const char * ininame = challengeActive ? sRequestResult : aFileName ;
const char * path = challengeActive ? " challenges/ " : aPathName ;
LEVEL_DATASET * psLevel = levFindDataSet ( game . map , & game . hash ) ;
ASSERT_OR_RETURN ( , psLevel , " No level found for %s " , game . map ) ;
sstrcpy ( aFileName , psLevel - > apDataFiles [ psLevel - > game ] ) ;
aFileName [ strlen ( aFileName ) - 4 ] = ' \0 ' ;
sstrcpy ( aPathName , aFileName ) ;
sstrcat ( aFileName , " .ini " ) ;
sstrcat ( aPathName , " / " ) ;
2011-01-09 07:35:49 -08:00
// Reset assigned counter
std : : vector < AIDATA > : : iterator it ;
for ( it = aidata . begin ( ) ; it < aidata . end ( ) ; it + + )
{
( * it ) . assigned = 0 ;
}
2013-01-05 08:02:08 -08:00
// Load map scripts
2013-01-06 15:40:24 -08:00
WzConfig ini ( ininame , WzConfig : : ReadOnly ) ;
2013-01-05 08:02:08 -08:00
if ( PHYSFS_exists ( ininame ) )
2012-01-13 14:00:14 -08:00
{
2013-01-05 08:02:08 -08:00
debug ( LOG_SAVE , " Loading map scripts " ) ;
ini . beginGroup ( " scripts " ) ;
if ( ini . contains ( " extra " ) )
2012-01-13 14:00:14 -08:00
{
2013-01-05 08:02:08 -08:00
loadGlobalScript ( path + ini . value ( " extra " ) . toString ( ) ) ;
2012-01-13 14:00:14 -08:00
}
2013-01-05 08:02:08 -08:00
if ( ini . contains ( " rules " ) )
2012-01-13 14:00:14 -08:00
{
2013-01-05 08:02:08 -08:00
loadGlobalScript ( path + ini . value ( " rules " ) . toString ( ) ) ;
2012-01-13 14:00:14 -08:00
defaultRules = false ;
}
2013-01-05 08:02:08 -08:00
ini . endGroup ( ) ;
2012-01-13 14:00:14 -08:00
}
2011-01-12 12:15:25 -08:00
// Load multiplayer rules
resForceBaseDir ( " messages/ " ) ;
resLoadFile ( " SMSG " , " multiplay.txt " ) ;
2012-01-13 14:00:14 -08:00
if ( defaultRules )
{
2012-02-03 13:04:05 -08:00
debug ( LOG_SAVE , " Loading default rules " ) ;
2012-01-13 14:00:14 -08:00
loadGlobalScript ( " multiplay/skirmish/rules.js " ) ;
}
2011-01-12 12:15:25 -08:00
2011-02-09 09:21:40 -08:00
// Backup data hashes, since AI and scavenger scripts aren't run on all clients.
2011-01-27 07:40:00 -08:00
uint32_t oldHash1 = DataHash [ DATA_SCRIPT ] ;
uint32_t oldHash2 = DataHash [ DATA_SCRIPTVAL ] ;
2011-02-09 09:21:40 -08:00
// Load AI players
2011-01-09 07:35:49 -08:00
resForceBaseDir ( " multiplay/skirmish/ " ) ;
for ( int i = 0 ; i < game . maxPlayers ; i + + )
{
2011-11-20 07:30:51 -08:00
if ( NetPlay . players [ i ] . ai < 0 & & i = = selectedPlayer )
{
NetPlay . players [ i ] . ai = 0 ; // For autogames.
}
2011-01-15 04:29:23 -08:00
// The i == selectedPlayer hack is to enable autogames
2011-01-23 13:30:57 -08:00
if ( bMultiPlayer & & game . type = = SKIRMISH & & ( ! NetPlay . players [ i ] . allocated | | i = = selectedPlayer )
& & NetPlay . players [ i ] . ai > = 0 & & myResponsibility ( i ) )
2011-01-09 07:35:49 -08:00
{
2013-01-05 08:02:08 -08:00
if ( PHYSFS_exists ( ininame ) ) // challenge file may override AI
2012-01-14 06:59:20 -08:00
{
2013-01-05 08:02:08 -08:00
ini . beginGroup ( " player_ " + QString : : number ( i + 1 ) ) ;
if ( ini . contains ( " ai " ) )
2012-01-14 06:59:20 -08:00
{
2013-01-05 08:02:08 -08:00
QString val = ini . value ( " ai " ) . toString ( ) ;
ini . endGroup ( ) ;
2012-01-14 07:11:03 -08:00
if ( val . compare ( " null " ) = = 0 )
{
continue ; // no AI
}
2012-01-14 15:07:33 -08:00
loadPlayerScript ( val , i , NetPlay . players [ i ] . difficulty ) ;
2012-02-08 13:44:16 -08:00
NetPlay . players [ i ] . ai = AI_CUSTOM ;
2012-01-14 06:59:20 -08:00
continue ;
}
2013-01-05 08:02:08 -08:00
ini . endGroup ( ) ;
2012-01-14 06:59:20 -08:00
}
2011-10-23 14:15:29 -07:00
if ( aidata [ NetPlay . players [ i ] . ai ] . slo [ 0 ] ! = ' \0 ' )
{
2012-02-03 13:04:05 -08:00
debug ( LOG_SAVE , " Loading wzscript AI for player %d " , i ) ;
2011-10-23 14:15:29 -07:00
resLoadFile ( " SCRIPT " , aidata [ NetPlay . players [ i ] . ai ] . slo ) ;
resLoadFile ( " SCRIPTVAL " , aidata [ NetPlay . players [ i ] . ai ] . vlo ) ;
}
2011-12-26 14:39:57 -08:00
// autogames are to be implemented differently for qtscript, do not start for human players yet
if ( ! NetPlay . players [ i ] . allocated & & aidata [ NetPlay . players [ i ] . ai ] . js [ 0 ] ! = ' \0 ' )
2011-01-23 13:30:57 -08:00
{
2012-02-03 13:04:05 -08:00
debug ( LOG_SAVE , " Loading javascript AI for player %d " , i ) ;
2011-02-06 09:19:05 -08:00
loadPlayerScript ( QString ( " multiplay/skirmish/ " ) + aidata [ NetPlay . players [ i ] . ai ] . js , i , NetPlay . players [ i ] . difficulty ) ;
2011-01-23 13:30:57 -08:00
}
2011-01-09 07:35:49 -08:00
}
}
2011-01-12 10:35:35 -08:00
// Load scavengers
2011-01-23 13:30:57 -08:00
if ( game . scavengers & & myResponsibility ( scavengerPlayer ( ) ) )
2011-01-12 10:35:35 -08:00
{
2012-02-03 13:04:05 -08:00
debug ( LOG_SAVE , " Loading scavenger AI for player %d " , scavengerPlayer ( ) ) ;
2011-02-06 09:19:05 -08:00
loadPlayerScript ( " multiplay/script/scavfact.js " , scavengerPlayer ( ) , DIFFICULTY_EASY ) ;
2011-01-12 10:35:35 -08:00
}
2011-02-09 09:21:40 -08:00
// Restore data hashes, since AI and scavenger scripts aren't run on all clients.
DataHash [ DATA_SCRIPT ] = oldHash1 ; // Not all players load the same AI scripts.
DataHash [ DATA_SCRIPTVAL ] = oldHash2 ;
2011-01-12 10:35:35 -08:00
// Reset resource path, otherwise things break down the line
2011-01-09 07:35:49 -08:00
resForceBaseDir ( " " ) ;
}
2010-11-28 13:07:58 -08:00
static int guessMapTilesetType ( LEVEL_DATASET * psLevel )
2009-08-29 16:33:35 -07:00
{
2010-11-28 13:07:58 -08:00
unsigned t = 0 , c = 0 ;
if ( psLevel - > psBaseData & & psLevel - > psBaseData - > pName )
2009-08-29 16:33:35 -07:00
{
2010-11-28 13:07:58 -08:00
if ( sscanf ( psLevel - > psBaseData - > pName , " MULTI_CAM_%u " , & c ) ! = 1 )
{
sscanf ( psLevel - > psBaseData - > pName , " MULTI_T%u_C%u " , & t , & c ) ;
}
2009-08-29 16:33:35 -07:00
}
2010-11-28 13:07:58 -08:00
switch ( c )
2009-08-29 16:33:35 -07:00
{
2010-11-28 13:07:58 -08:00
case 1 :
return TILESET_ARIZONA ;
break ;
case 2 :
return TILESET_URBAN ;
break ;
case 3 :
return TILESET_ROCKIES ;
break ;
2009-08-29 16:33:35 -07:00
}
2010-11-28 13:07:58 -08:00
debug ( LOG_MAP , " Could not guess map tileset, using ARIZONA. " ) ;
return TILESET_ARIZONA ;
2009-08-29 16:33:35 -07:00
}
2012-06-18 08:24:06 -07:00
static void loadEmptyMapPreview ( )
{
// No map is available to preview, so improvise.
char * imageData = ( char * ) malloc ( BACKDROP_HACK_WIDTH * BACKDROP_HACK_HEIGHT * 3 ) ;
memset ( imageData , 0 , BACKDROP_HACK_WIDTH * BACKDROP_HACK_HEIGHT * 3 ) ; //dunno about background color
int const ex = 100 , ey = 100 , bx = 5 , by = 8 ;
for ( unsigned n = 0 ; n < 125 ; + + n )
{
int sx = rand ( ) % ( ex - bx ) , sy = rand ( ) % ( ey - by ) ;
2012-06-19 14:17:10 -07:00
char col [ 3 ] = { char ( rand ( ) % 256 ) , char ( rand ( ) % 256 ) , char ( rand ( ) % 256 ) } ;
2012-06-18 08:24:06 -07:00
for ( unsigned y = 0 ; y < by ; + + y )
for ( unsigned x = 0 ; x < bx ; + + x )
if ( ( " \2 \1 \261 \11 \6 " [ x ] > > y & 1 ) = = 1 ) // ?
memcpy ( imageData + 3 * ( sx + x + BACKDROP_HACK_WIDTH * ( sy + y ) ) , col , 3 ) ;
}
// Slight hack to init array with a special value used to determine how many players on map
Vector2i playerpos [ MAX_PLAYERS ] ;
memset ( playerpos , 0x77 , sizeof ( playerpos ) ) ;
2013-02-10 14:27:26 -08:00
screen_enableMapPreview ( ex , ey , playerpos ) ;
2012-06-18 08:24:06 -07:00
2013-02-10 15:14:09 -08:00
screen_Upload ( imageData ) ;
2012-06-18 08:24:06 -07:00
free ( imageData ) ;
}
2011-01-04 09:51:15 -08:00
/// Loads the entire map just to show a picture of it
2009-05-01 00:14:31 -07:00
void loadMapPreview ( bool hideInterface )
2007-06-28 10:47:08 -07:00
{
2010-12-06 17:31:39 -08:00
static char aFileName [ 256 ] ;
2007-06-28 10:47:08 -07:00
UDWORD fileSize ;
2006-08-12 09:52:37 -07:00
char * pFileData = NULL ;
2008-08-01 21:28:58 -07:00
LEVEL_DATASET * psLevel = NULL ;
2009-08-29 16:33:35 -07:00
PIELIGHT plCliffL , plCliffH , plWater , plRoadL , plRoadH , plGroundL , plGroundH ;
2010-05-31 09:24:33 -07:00
UDWORD x , y , height ;
UBYTE col ;
2007-06-28 10:47:08 -07:00
MAPTILE * psTile , * WTile ;
2006-08-12 09:52:37 -07:00
UDWORD oursize ;
2008-08-01 21:28:58 -07:00
Vector2i playerpos [ MAX_PLAYERS ] ; // Will hold player positions
2010-05-31 09:24:33 -07:00
char * ptr = NULL , * imageData = NULL ;
2007-06-28 10:47:08 -07:00
2011-07-03 04:50:27 -07:00
// absurd hack, since there is a problem with updating this crap piece of info, we're setting it to
// true by default for now, like it used to be
game . mapHasScavengers = true ; // this is really the wrong place for it, but this is where it has to be
2011-07-03 04:15:31 -07:00
2007-06-28 10:47:08 -07:00
if ( psMapTiles )
{
mapShutdown ( ) ;
}
2007-04-03 04:12:00 -07:00
// load the terrain types
2012-06-18 08:24:06 -07:00
psLevel = levFindDataSet ( game . map , & game . hash ) ;
if ( psLevel = = NULL )
{
2012-06-25 19:32:40 -07:00
debug ( LOG_INFO , " Could not find level dataset \" %s \" %s. We %s waiting for a download. " , game . map , game . hash . toString ( ) . c_str ( ) , NetPlay . players [ selectedPlayer ] . needFile ? " are " : " aren't " ) ;
2012-06-18 08:24:06 -07:00
loadEmptyMapPreview ( ) ;
return ;
}
if ( psLevel - > realFileName = = NULL )
{
2013-12-07 17:11:38 -08:00
debug ( LOG_WZ , " Loading map preview: \" %s \" builtin t%d " , psLevel - > pName , psLevel - > dataDir ) ;
2012-06-18 08:24:06 -07:00
}
else
{
2013-12-07 17:11:38 -08:00
debug ( LOG_WZ , " Loading map preview: \" %s \" in (%s) \" %s \" %s t%d " , psLevel - > pName , PHYSFS_getRealDir ( psLevel - > realFileName ) , psLevel - > realFileName , psLevel - > realFileHash . toString ( ) . c_str ( ) , psLevel - > dataDir ) ;
2012-06-18 08:24:06 -07:00
}
2012-12-08 05:07:15 -08:00
rebuildSearchPath ( psLevel - > dataDir , false , psLevel - > realFileName ) ;
2013-01-05 08:02:08 -08:00
sstrcpy ( aFileName , psLevel - > apDataFiles [ psLevel - > game ] ) ;
2007-06-28 10:47:08 -07:00
aFileName [ strlen ( aFileName ) - 4 ] = ' \0 ' ;
2008-07-20 15:46:55 -07:00
sstrcat ( aFileName , " /ttypes.ttp " ) ;
2007-06-30 17:28:49 -07:00
pFileData = fileLoadBuffer ;
2010-12-06 17:31:39 -08:00
2007-06-30 17:28:49 -07:00
if ( ! loadFileToBuffer ( aFileName , pFileData , FILE_LOAD_BUFFER_SIZE , & fileSize ) )
2007-04-03 04:12:00 -07:00
{
2012-06-25 19:32:40 -07:00
debug ( LOG_ERROR , " Failed to load terrain types file: [%s] " , aFileName ) ;
2007-04-03 04:12:00 -07:00
return ;
}
if ( pFileData )
{
if ( ! loadTerrainTypeMap ( pFileData , fileSize ) )
{
2011-01-04 09:51:15 -08:00
debug ( LOG_ERROR , " Failed to load terrain types " ) ;
2007-04-03 04:12:00 -07:00
return ;
}
}
2007-06-28 10:47:08 -07:00
2007-04-03 04:12:00 -07:00
// load the map data
ptr = strrchr ( aFileName , ' / ' ) ;
2011-12-11 09:12:21 -08:00
ASSERT_OR_RETURN ( , ptr , " this string was supposed to contain a / " ) ;
2007-04-03 04:12:00 -07:00
strcpy ( ptr , " /game.map " ) ;
2010-11-13 10:48:18 -08:00
if ( ! mapLoad ( aFileName , true ) )
2007-06-28 10:47:08 -07:00
{
2011-01-04 09:51:15 -08:00
debug ( LOG_ERROR , " Failed to load map " ) ;
2007-06-28 10:47:08 -07:00
return ;
}
gwShutDown ( ) ;
2009-08-29 16:33:35 -07:00
// set tileset colors
2010-11-28 13:07:58 -08:00
switch ( guessMapTilesetType ( psLevel ) )
2009-08-29 16:33:35 -07:00
{
case TILESET_ARIZONA :
plCliffL = WZCOL_TERC1_CLIFF_LOW ;
plCliffH = WZCOL_TERC1_CLIFF_HIGH ;
plWater = WZCOL_TERC1_WATER ;
plRoadL = WZCOL_TERC1_ROAD_LOW ;
plRoadH = WZCOL_TERC1_ROAD_HIGH ;
plGroundL = WZCOL_TERC1_GROUND_LOW ;
plGroundH = WZCOL_TERC1_GROUND_HIGH ;
break ;
case TILESET_URBAN :
plCliffL = WZCOL_TERC2_CLIFF_LOW ;
plCliffH = WZCOL_TERC2_CLIFF_HIGH ;
plWater = WZCOL_TERC2_WATER ;
plRoadL = WZCOL_TERC2_ROAD_LOW ;
plRoadH = WZCOL_TERC2_ROAD_HIGH ;
plGroundL = WZCOL_TERC2_GROUND_LOW ;
plGroundH = WZCOL_TERC2_GROUND_HIGH ;
break ;
case TILESET_ROCKIES :
plCliffL = WZCOL_TERC3_CLIFF_LOW ;
plCliffH = WZCOL_TERC3_CLIFF_HIGH ;
plWater = WZCOL_TERC3_WATER ;
plRoadL = WZCOL_TERC3_ROAD_LOW ;
plRoadH = WZCOL_TERC3_ROAD_HIGH ;
plGroundL = WZCOL_TERC3_GROUND_LOW ;
plGroundH = WZCOL_TERC3_GROUND_HIGH ;
break ;
}
2007-02-25 04:57:04 -08:00
oursize = sizeof ( char ) * BACKDROP_HACK_WIDTH * BACKDROP_HACK_HEIGHT ;
2008-08-01 21:28:58 -07:00
imageData = ( char * ) malloc ( oursize * 3 ) ; // used for the texture
if ( ! imageData )
{
2009-10-30 20:57:44 -07:00
debug ( LOG_FATAL , " Out of memory for texture! " ) ;
2008-08-01 21:28:58 -07:00
abort ( ) ; // should be a fatal error ?
return ;
}
2007-02-25 04:57:04 -08:00
ptr = imageData ;
2010-05-31 09:24:33 -07:00
memset ( ptr , 0 , sizeof ( char ) * BACKDROP_HACK_WIDTH * BACKDROP_HACK_HEIGHT * 3 ) ; //dunno about background color
2007-02-25 04:57:04 -08:00
psTile = psMapTiles ;
2007-06-28 10:47:08 -07:00
2010-05-31 09:24:33 -07:00
for ( y = 0 ; y < mapHeight ; y + + )
2007-02-25 04:57:04 -08:00
{
WTile = psTile ;
2010-05-31 09:24:33 -07:00
for ( x = 0 ; x < mapWidth ; x + + )
2007-02-25 04:57:04 -08:00
{
2010-05-31 09:24:33 -07:00
char * const p = imageData + ( 3 * ( y * BACKDROP_HACK_WIDTH + x ) ) ;
2010-11-16 11:02:22 -08:00
height = WTile - > height / ELEVATION_SCALE ;
2007-02-25 04:57:04 -08:00
col = height ;
2007-06-28 10:47:08 -07:00
2010-05-31 09:24:33 -07:00
switch ( terrainType ( WTile ) )
2007-06-28 10:47:08 -07:00
{
2010-05-31 09:24:33 -07:00
case TER_CLIFFFACE :
p [ 0 ] = plCliffL . byte . r + ( plCliffH . byte . r - plCliffL . byte . r ) * col / 256 ;
p [ 1 ] = plCliffL . byte . g + ( plCliffH . byte . g - plCliffL . byte . g ) * col / 256 ;
p [ 2 ] = plCliffL . byte . b + ( plCliffH . byte . b - plCliffL . byte . b ) * col / 256 ;
break ;
case TER_WATER :
p [ 0 ] = plWater . byte . r ;
p [ 1 ] = plWater . byte . g ;
p [ 2 ] = plWater . byte . b ;
break ;
case TER_ROAD :
p [ 0 ] = plRoadL . byte . r + ( plRoadH . byte . r - plRoadL . byte . r ) * col / 256 ;
p [ 1 ] = plRoadL . byte . g + ( plRoadH . byte . g - plRoadL . byte . g ) * col / 256 ;
p [ 2 ] = plRoadL . byte . b + ( plRoadH . byte . b - plRoadL . byte . b ) * col / 256 ;
break ;
default :
p [ 0 ] = plGroundL . byte . r + ( plGroundH . byte . r - plGroundL . byte . r ) * col / 256 ;
p [ 1 ] = plGroundL . byte . g + ( plGroundH . byte . g - plGroundL . byte . g ) * col / 256 ;
p [ 2 ] = plGroundL . byte . b + ( plGroundH . byte . b - plGroundL . byte . b ) * col / 256 ;
break ;
2007-06-28 10:47:08 -07:00
}
2007-02-25 04:57:04 -08:00
WTile + = 1 ;
}
2007-06-28 10:47:08 -07:00
psTile + = mapWidth ;
2007-02-25 04:57:04 -08:00
}
2008-08-01 21:28:58 -07:00
// Slight hack to init array with a special value used to determine how many players on map
memset ( playerpos , 0x77 , sizeof ( playerpos ) ) ;
// color our texture with clancolors @ correct position
2010-05-31 09:24:33 -07:00
plotStructurePreview16 ( imageData , playerpos ) ;
2008-08-01 21:28:58 -07:00
2013-02-10 14:27:26 -08:00
screen_enableMapPreview ( mapWidth , mapHeight , playerpos ) ;
2010-05-31 09:24:33 -07:00
2013-02-10 15:14:09 -08:00
screen_Upload ( imageData ) ;
2008-08-01 21:28:58 -07:00
free ( imageData ) ;
2008-08-03 14:06:39 -07:00
2009-05-01 00:14:31 -07:00
if ( hideInterface )
{
hideTime = gameTime ;
}
2007-06-28 10:47:08 -07:00
mapShutdown ( ) ;
}
2006-02-11 01:00:20 -08:00
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
// helper func
2011-01-09 07:35:49 -08:00
int matchAIbyName ( const char * name )
{
std : : vector < AIDATA > : : iterator it ;
int i = 0 ;
2011-01-15 04:29:23 -08:00
if ( name [ 0 ] = = ' \0 ' )
{
return AI_CLOSED ;
}
2011-01-09 07:35:49 -08:00
for ( it = aidata . begin ( ) ; it < aidata . end ( ) ; it + + , i + + )
{
if ( strncasecmp ( name , ( * it ) . name , MAX_LEN_AI_NAME ) = = 0 )
{
return i ;
}
}
return AI_NOT_FOUND ;
}
void readAIs ( )
{
char basepath [ PATH_MAX ] ;
const char * sSearchPath = " multiplay/skirmish/ " ;
char * * i , * * files ;
aidata . clear ( ) ;
strcpy ( basepath , sSearchPath ) ;
files = PHYSFS_enumerateFiles ( basepath ) ;
for ( i = files ; * i ! = NULL ; + + i )
{
char path [ PATH_MAX ] ;
// See if this filename contains the extension we're looking for
if ( ! strstr ( * i , " .ai " ) )
{
continue ;
}
sstrcpy ( path , basepath ) ;
sstrcat ( path , * i ) ;
2013-01-06 15:40:24 -08:00
WzConfig aiconf ( path , WzConfig : : ReadOnly ) ;
2011-01-09 07:35:49 -08:00
AIDATA ai ;
2011-04-01 11:31:15 -07:00
aiconf . beginGroup ( " AI " ) ;
2013-08-23 14:25:29 -07:00
sstrcpy ( ai . name , aiconf . value ( " name " , " error " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
sstrcpy ( ai . slo , aiconf . value ( " slo " , " " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
sstrcpy ( ai . vlo , aiconf . value ( " vlo " , " " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
sstrcpy ( ai . js , aiconf . value ( " js " , " " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
sstrcpy ( ai . tip , aiconf . value ( " tip " , " Click to choose this AI " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
2011-01-09 07:35:49 -08:00
if ( strcmp ( ai . name , " Nexus " ) = = 0 )
{
std : : vector < AIDATA > : : iterator it ;
it = aidata . begin ( ) ;
aidata . insert ( it , ai ) ;
}
else
{
aidata . push_back ( ai ) ;
}
}
PHYSFS_freeList ( files ) ;
}
2007-06-28 10:47:08 -07:00
//sets sWRFILE form game.map
static void decideWRF ( void )
{
// try and load it from the maps directory first,
2008-05-25 06:46:49 -07:00
sstrcpy ( aLevelName , MultiCustomMapsPath ) ;
sstrcat ( aLevelName , game . map ) ;
sstrcat ( aLevelName , " .wrf " ) ;
2007-10-27 07:35:35 -07:00
debug ( LOG_WZ , " decideWRF: %s " , aLevelName ) ;
2007-06-28 10:47:08 -07:00
//if the file exists in the downloaded maps dir then use that one instead.
// FIXME: Try to incorporate this into physfs setup somehow for sane paths
2007-10-27 07:35:35 -07:00
if ( ! PHYSFS_exists ( aLevelName ) )
2007-06-28 10:47:08 -07:00
{
2008-05-25 06:46:49 -07:00
sstrcpy ( aLevelName , game . map ) ; // doesn't exist, must be a predefined one.
2007-06-28 10:47:08 -07:00
}
}
// ////////////////////////////////////////////////////////////////////////////
// Connection Options Screen.
2011-03-12 17:32:15 -08:00
static bool OptionsInet ( void ) //internet options
2006-05-27 09:37:17 -07:00
{
2013-02-15 23:44:47 -08:00
psConScreen = new W_SCREEN ;
2007-06-28 10:47:08 -07:00
2010-12-22 06:02:14 -08:00
W_FORMINIT sFormInit ; //Connection Settings
2007-06-28 10:47:08 -07:00
sFormInit . formID = 0 ;
sFormInit . id = CON_SETTINGS ;
sFormInit . style = WFORM_PLAIN ;
sFormInit . x = CON_SETTINGSX ;
sFormInit . y = CON_SETTINGSY ;
sFormInit . width = CON_SETTINGSWIDTH ;
sFormInit . height = CON_SETTINGSHEIGHT ;
sFormInit . pDisplay = intDisplayFeBox ;
widgAddForm ( psConScreen , & sFormInit ) ;
2012-01-07 15:52:38 -08:00
addMultiBut ( psConScreen , CON_SETTINGS , CON_OK , CON_OKX , CON_OKY , MULTIOP_OKW , MULTIOP_OKH ,
2008-03-24 09:51:17 -07:00
_ ( " Accept Settings " ) , IMAGE_OK , IMAGE_OK , true ) ;
2010-01-10 00:26:14 -08:00
addMultiBut ( psConScreen , CON_SETTINGS , CON_IP_CANCEL , CON_OKX + MULTIOP_OKW + 10 , CON_OKY , MULTIOP_OKW , MULTIOP_OKH ,
_ ( " Cancel " ) , IMAGE_NO , IMAGE_NO , true ) ;
2007-06-28 10:47:08 -07:00
2006-05-27 09:37:17 -07:00
//label.
2010-12-22 06:02:14 -08:00
W_LABINIT sLabInit ;
2007-06-28 10:47:08 -07:00
sLabInit . formID = CON_SETTINGS ;
sLabInit . id = CON_SETTINGS_LABEL ;
sLabInit . style = WLAB_ALIGNCENTRE ;
sLabInit . x = 0 ;
sLabInit . y = 10 ;
sLabInit . width = CON_SETTINGSWIDTH ;
sLabInit . height = 20 ;
2007-04-01 13:15:46 -07:00
sLabInit . pText = _ ( " IP Address or Machine Name " ) ;
2007-06-28 10:47:08 -07:00
widgAddLabel ( psConScreen , & sLabInit ) ;
2010-12-22 06:02:14 -08:00
W_EDBINIT sEdInit ; // address
2007-06-28 10:47:08 -07:00
sEdInit . formID = CON_SETTINGS ;
sEdInit . id = CON_IP ;
sEdInit . x = CON_IPX ;
sEdInit . y = CON_IPY ;
sEdInit . width = CON_NAMEBOXWIDTH ;
sEdInit . height = CON_NAMEBOXHEIGHT ;
2007-04-01 13:15:46 -07:00
sEdInit . pText = " " ; //_("IP Address or Machine Name");
2007-06-28 10:47:08 -07:00
sEdInit . pBoxDisplay = intDisplayEditBox ;
if ( ! widgAddEditBox ( psConScreen , & sEdInit ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2010-01-03 01:17:55 -08:00
// auto click in the text box
2010-12-22 06:02:14 -08:00
W_CONTEXT sContext ;
2010-01-03 01:17:55 -08:00
sContext . xOffset = 0 ;
sContext . yOffset = 0 ;
sContext . mx = 0 ;
sContext . my = 0 ;
2010-12-20 12:37:49 -08:00
widgGetFromID ( psConScreen , CON_IP ) - > clicked ( & sContext ) ;
2011-07-17 12:41:06 -07:00
2008-03-24 09:51:17 -07:00
SettingsUp = true ;
return true ;
2007-06-28 10:47:08 -07:00
}
2012-01-07 15:52:38 -08:00
// ////////////////////////////////////////////////////////////////////////////
// Draw the connections screen.
bool startConnectionScreen ( void )
{
addBackdrop ( ) ; //background
addTopForm ( ) ; // logo
addBottomForm ( ) ;
SettingsUp = false ;
InitialProto = 0 ;
safeSearch = false ;
// don't pretend we are running a network game. Really do it!
NetPlay . bComms = true ; // use network = true
addSideText ( FRONTEND_SIDETEXT , FRONTEND_SIDEX , FRONTEND_SIDEY , _ ( " CONNECTION " ) ) ;
addMultiBut ( psWScreen , FRONTEND_BOTFORM , CON_CANCEL , 10 , 10 , MULTIOP_OKW , MULTIOP_OKH ,
_ ( " Return To Previous Screen " ) , IMAGE_RETURN , IMAGE_RETURN_HI , IMAGE_RETURN_HI ) ; // goback buttpn levels
addTextButton ( CON_TYPESID_START + 0 , FRONTEND_POS2X , FRONTEND_POS2Y , _ ( " Lobby " ) , WBUT_TXTCENTRE ) ;
addTextButton ( CON_TYPESID_START + 1 , FRONTEND_POS3X , FRONTEND_POS3Y , _ ( " IP " ) , WBUT_TXTCENTRE ) ;
return true ;
}
void runConnectionScreen ( void )
{
static char addr [ 128 ] ;
2013-01-27 00:02:31 -08:00
W_SCREEN * curScreen = SettingsUp ? psConScreen : psWScreen ;
WidgetTriggers const & triggers = widgRunScreen ( curScreen ) ;
unsigned id = triggers . empty ( ) ? 0 : triggers . front ( ) . widget - > id ; // Just use first click here, since the next click could be on another menu.
2012-01-07 15:52:38 -08:00
switch ( id )
{
case CON_CANCEL : //cancel
changeTitleMode ( MULTI ) ;
bMultiPlayer = false ;
bMultiMessages = false ;
break ;
case CON_TYPESID_START + 0 : // Lobby button
2012-02-19 14:49:49 -08:00
if ( LobbyError ! = ERROR_INVALID )
2012-01-07 15:52:38 -08:00
{
setLobbyError ( ERROR_NOERROR ) ;
}
changeTitleMode ( GAMEFIND ) ;
break ;
case CON_TYPESID_START + 1 : // IP button
OptionsInet ( ) ;
break ;
case CON_OK :
sstrcpy ( addr , widgGetString ( psConScreen , CON_IP ) ) ;
if ( addr [ 0 ] = = ' \0 ' )
{
sstrcpy ( addr , " 127.0.0.1 " ) ; // Default to localhost.
}
if ( SettingsUp = = true )
{
2013-02-15 23:44:47 -08:00
delete psConScreen ;
psConScreen = NULL ;
2012-01-07 15:52:38 -08:00
SettingsUp = false ;
}
joinGame ( addr , 0 ) ;
break ;
case CON_IP_CANCEL :
if ( SettingsUp = = true )
{
2013-02-15 23:44:47 -08:00
delete psConScreen ;
psConScreen = NULL ;
2012-01-07 15:52:38 -08:00
SettingsUp = false ;
}
break ;
}
widgDisplayScreen ( psWScreen ) ; // show the widgets currently running
if ( SettingsUp = = true )
{
widgDisplayScreen ( psConScreen ) ; // show the widgets currently running
}
if ( CancelPressed ( ) )
{
changeTitleMode ( MULTI ) ;
}
}
2009-04-19 11:45:28 -07:00
// ////////////////////////////////////////////////////////////////////////
// Lobby error reading
LOBBY_ERROR_TYPES getLobbyError ( void )
{
return LobbyError ;
}
void setLobbyError ( LOBBY_ERROR_TYPES error_type )
{
LobbyError = error_type ;
2010-01-03 02:40:52 -08:00
if ( LobbyError < = ERROR_FULL )
2009-04-19 11:45:28 -07:00
{
disableLobbyRefresh = false ;
}
else
{
disableLobbyRefresh = true ;
}
}
2007-06-28 10:47:08 -07:00
2011-04-25 11:37:20 -07:00
/**
* Try connecting to the given host , show
* the multiplayer screen or a error .
*/
bool joinGame ( const char * host , uint32_t port )
{
PLAYERSTATS playerStats ;
if ( ingame . localJoiningInProgress )
{
return false ;
}
2011-07-17 12:41:06 -07:00
2011-04-25 11:37:20 -07:00
if ( ! NETjoinGame ( host , port , ( char * ) sPlayer ) ) // join
{
2012-03-25 21:19:37 -07:00
switch ( getLobbyError ( ) )
2011-04-25 11:37:20 -07:00
{
2012-03-25 21:19:37 -07:00
case ERROR_HOSTDROPPED :
setLobbyError ( ERROR_NOERROR ) ;
break ;
case ERROR_WRONGPASSWORD :
2013-01-27 00:02:31 -08:00
{
2012-03-25 21:19:37 -07:00
// Change to GAMEFIND, screen with a password dialog.
changeTitleMode ( GAMEFIND ) ;
showPasswordForm ( ) ;
2013-01-27 00:02:31 -08:00
WidgetTriggers const & triggers = widgRunScreen ( psWScreen ) ;
unsigned id = triggers . empty ( ) ? 0 : triggers . front ( ) . widget - > id ; // Just use first click here, since the next click could be on another menu.
if ( id ! = CON_PASSWORD ) // Run the current set of widgets
2012-03-25 21:19:37 -07:00
{
return false ;
}
NETsetGamePassword ( widgGetString ( psWScreen , CON_PASSWORD ) ) ;
break ;
2013-01-27 00:02:31 -08:00
}
2012-03-25 21:19:37 -07:00
default :
break ;
2011-04-25 11:37:20 -07:00
}
// Hide a (maybe shown) password form.
hidePasswordForm ( ) ;
// Change to GAMEFIND, screen.
2012-01-07 15:52:38 -08:00
changeTitleMode ( GAMEFIND ) ;
2011-04-25 11:37:20 -07:00
// Shows the lobby error.
addGames ( ) ;
2012-01-10 18:24:32 -08:00
addConsoleBox ( ) ;
2011-04-25 11:37:20 -07:00
return false ;
}
ingame . localJoiningInProgress = true ;
loadMultiStats ( sPlayer , & playerStats ) ;
setMultiStats ( selectedPlayer , playerStats , false ) ;
setMultiStats ( selectedPlayer , playerStats , true ) ;
changeTitleMode ( MULTIOPTION ) ;
2012-02-14 13:18:35 -08:00
if ( war_getMPcolour ( ) > = 0 )
{
SendColourRequest ( selectedPlayer , war_getMPcolour ( ) ) ;
}
2011-04-25 11:37:20 -07:00
return true ;
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
// Game Chooser Screen.
2012-01-07 15:52:38 -08:00
2006-09-13 03:54:35 -07:00
static void addGames ( void )
2007-06-28 10:47:08 -07:00
{
2013-02-16 19:18:26 -08:00
int i , gcount = 0 , added = 0 ;
2009-12-30 13:23:33 -08:00
static const char * wrongVersionTip = " Your version of Warzone is incompatible with this game. " ;
2010-01-17 12:12:03 -08:00
static const char * badModTip = " Your loaded mods are incompatible with this game. (Check mods/autoload/?) " ;
2006-05-27 09:37:17 -07:00
2012-01-07 15:52:38 -08:00
//count games to see if need two columns.
2013-02-15 19:32:37 -08:00
for ( i = 0 ; i < MaxGames ; i + + )
2012-01-07 15:52:38 -08:00
{
2013-02-15 19:32:37 -08:00
if ( NetPlay . games [ i ] . desc . dwSize ! = 0 )
2012-01-07 15:52:38 -08:00
{
gcount + + ;
}
}
2012-01-10 18:24:32 -08:00
2010-12-22 06:02:14 -08:00
W_BUTINIT sButInit ;
2007-06-28 10:47:08 -07:00
sButInit . formID = FRONTEND_BOTFORM ;
sButInit . width = GAMES_GAMEWIDTH ;
sButInit . height = GAMES_GAMEHEIGHT ;
2006-05-27 09:37:17 -07:00
sButInit . pDisplay = displayRemoteGame ;
2007-06-28 10:47:08 -07:00
2009-04-19 11:45:28 -07:00
// we want the old games deleted, and only list games when we should
2009-07-13 13:09:57 -07:00
if ( getLobbyError ( ) | | ! gcount )
2009-04-19 11:45:28 -07:00
{
for ( i = 0 ; i < MaxGames ; i + + )
{
widgDelete ( psWScreen , GAMES_GAMESTART + i ) ; // remove old widget
}
gcount = 0 ;
}
2008-10-03 20:07:29 -07:00
// in case they refresh, and a game becomes available.
2012-01-10 18:24:32 -08:00
widgDelete ( psWScreen , FRONTEND_NOGAMESAVAILABLE ) ;
2010-01-03 01:17:55 -08:00
2008-08-17 11:18:31 -07:00
// only have to do this if we have any games available.
2009-04-19 11:45:28 -07:00
if ( ! getLobbyError ( ) & & gcount )
2007-06-28 10:47:08 -07:00
{
2012-01-07 15:52:38 -08:00
for ( i = 0 ; i < MaxGames ; i + + ) // draw games
2007-06-28 10:47:08 -07:00
{
2008-08-17 11:18:31 -07:00
widgDelete ( psWScreen , GAMES_GAMESTART + i ) ; // remove old icon.
2006-05-27 09:37:17 -07:00
2013-02-16 19:18:26 -08:00
if ( NetPlay . games [ i ] . desc . dwSize ! = 0 )
{ // either display all games, or games that are the client's specific version
if ( toggleFilter )
{
if ( ( NetPlay . games [ i ] . game_version_major ! = NETGetMajorVersion ( ) ) | | ( NetPlay . games [ i ] . game_version_minor ! = NETGetMinorVersion ( ) ) )
continue ;
}
added + + ;
2012-01-07 15:52:38 -08:00
sButInit . id = GAMES_GAMESTART + i ;
2012-01-10 18:24:32 -08:00
sButInit . x = 20 ;
sButInit . y = ( UWORD ) ( 45 + ( ( 5 + GAMES_GAMEHEIGHT ) * i ) ) ;
2006-05-27 09:37:17 -07:00
2012-01-07 15:52:38 -08:00
// display the correct tooltip message.
2012-01-10 18:24:32 -08:00
if ( ! NETisCorrectVersion ( NetPlay . games [ i ] . game_version_major , NetPlay . games [ i ] . game_version_minor ) )
2012-01-07 15:52:38 -08:00
{
sButInit . pTip = wrongVersionTip ;
}
else if ( strcmp ( NetPlay . games [ i ] . modlist , getModList ( ) ) ! = 0 )
{
sButInit . pTip = badModTip ;
}
else
{
2012-01-29 04:48:01 -08:00
std : : string flags ;
if ( NetPlay . games [ i ] . privateGame )
2012-01-10 18:24:32 -08:00
{
2012-01-29 04:48:01 -08:00
flags + = " " ; flags + = _ ( " [Password required] " ) ;
}
if ( NetPlay . games [ i ] . limits & NO_TANKS )
{
flags + = " " ; flags + = _ ( " [No Tanks] " ) ;
}
if ( NetPlay . games [ i ] . limits & NO_BORGS )
{
flags + = " " ; flags + = _ ( " [No Cyborgs] " ) ;
}
if ( NetPlay . games [ i ] . limits & NO_VTOLS )
{
flags + = " " ; flags + = _ ( " [No VTOLs] " ) ;
}
if ( flags . empty ( ) )
{
ssprintf ( tooltipbuffer [ i ] , _ ( " Hosted by %s " ) , NetPlay . games [ i ] . hostname ) ;
2012-01-10 18:24:32 -08:00
}
else
{
2012-01-29 04:48:01 -08:00
ssprintf ( tooltipbuffer [ i ] , _ ( " Hosted by %s —%s " ) , NetPlay . games [ i ] . hostname , flags . c_str ( ) ) ;
2012-01-10 18:24:32 -08:00
}
sButInit . pTip = tooltipbuffer [ i ] ;
2012-01-07 15:52:38 -08:00
}
sButInit . UserData = i ;
2011-04-25 12:07:08 -07:00
2012-01-07 15:52:38 -08:00
widgAddButton ( psWScreen , & sButInit ) ;
}
2007-06-28 10:47:08 -07:00
}
2013-11-19 17:31:22 -08:00
if ( ! added )
2013-02-16 19:18:26 -08:00
{
sButInit = W_BUTINIT ( ) ;
sButInit . formID = FRONTEND_BOTFORM ;
sButInit . id = FRONTEND_NOGAMESAVAILABLE ;
sButInit . x = 70 ;
sButInit . y = 378 ;
sButInit . style = WBUT_TXTCENTRE ;
sButInit . width = FRONTEND_BUTWIDTH ;
sButInit . UserData = 0 ; // store disable state
sButInit . height = FRONTEND_BUTHEIGHT ;
sButInit . pDisplay = displayTextOption ;
sButInit . FontID = font_large ;
sButInit . pText = _ ( " Can't find any games for your version. " ) ;
widgAddButton ( psWScreen , & sButInit ) ;
}
2007-06-28 10:47:08 -07:00
}
2008-08-17 11:18:31 -07:00
else
{
2012-01-07 15:52:38 -08:00
// display lobby message based on results.
// This is a 'button', not text so it can be hilighted/centered.
2009-04-10 11:26:55 -07:00
const char * txt ;
2009-04-10 21:43:56 -07:00
W_BUTINIT sButInit ;
2009-04-19 11:45:28 -07:00
switch ( getLobbyError ( ) )
2009-04-10 11:26:55 -07:00
{
2009-04-19 11:45:28 -07:00
case ERROR_NOERROR :
2009-04-10 11:26:55 -07:00
txt = _ ( " No games are available " ) ;
break ;
2009-04-19 11:45:28 -07:00
case ERROR_FULL :
txt = _ ( " Game is full " ) ;
break ;
case ERROR_KICKED :
2012-02-19 14:49:49 -08:00
case ERROR_INVALID :
2009-04-19 11:45:28 -07:00
txt = _ ( " You were kicked! " ) ;
2009-04-10 11:26:55 -07:00
break ;
2009-05-02 13:49:18 -07:00
case ERROR_WRONGVERSION :
2009-05-26 09:21:04 -07:00
txt = _ ( " Wrong Game Version! " ) ;
2009-04-19 11:45:28 -07:00
break ;
2011-07-17 12:41:06 -07:00
case ERROR_WRONGDATA :
2010-01-17 12:12:03 -08:00
txt = _ ( " You have an incompatible mod. " ) ;
2009-10-04 19:49:58 -07:00
break ;
2009-12-18 16:23:37 -08:00
// AFAIK, the only way this can really happy is if the Host's file is named wrong, or a client side error.
2011-07-17 12:41:06 -07:00
case ERROR_UNKNOWNFILEISSUE :
2009-12-18 16:23:37 -08:00
txt = _ ( " Host couldn't send file? " ) ;
debug ( LOG_POPUP , " Warzone couldn't complete a file request. \n \n Possibly, Host's file is incorrect. Check your logs for more details. " ) ;
break ;
2009-04-19 11:45:28 -07:00
case ERROR_WRONGPASSWORD :
txt = _ ( " Incorrect Password! " ) ;
break ;
2009-10-04 19:49:58 -07:00
case ERROR_HOSTDROPPED :
txt = _ ( " Host has dropped connection! " ) ;
break ;
2009-04-19 11:45:28 -07:00
case ERROR_CONNECTION :
2009-04-10 11:45:09 -07:00
default :
2009-04-19 11:45:28 -07:00
txt = _ ( " Connection Error " ) ;
2009-04-10 11:45:09 -07:00
break ;
2009-04-10 11:26:55 -07:00
}
2008-08-17 11:18:31 -07:00
// delete old widget if necessary
2012-01-07 15:52:38 -08:00
widgDelete ( psWScreen , FRONTEND_NOGAMESAVAILABLE ) ;
2008-08-17 11:18:31 -07:00
2010-12-22 06:02:14 -08:00
sButInit = W_BUTINIT ( ) ;
2008-08-17 11:18:31 -07:00
sButInit . formID = FRONTEND_BOTFORM ;
2012-01-07 15:52:38 -08:00
sButInit . id = FRONTEND_NOGAMESAVAILABLE ;
sButInit . x = 70 ;
sButInit . y = 50 ;
2010-12-22 06:02:14 -08:00
sButInit . style = WBUT_TXTCENTRE ;
2008-08-17 11:18:31 -07:00
sButInit . width = FRONTEND_BUTWIDTH ;
sButInit . UserData = 0 ; // store disable state
sButInit . height = FRONTEND_BUTHEIGHT ;
sButInit . pDisplay = displayTextOption ;
sButInit . FontID = font_large ;
sButInit . pText = txt ;
widgAddButton ( psWScreen , & sButInit ) ;
}
2010-01-03 01:17:55 -08:00
}
2006-05-27 09:37:17 -07:00
2010-01-03 01:17:55 -08:00
static void removeGames ( void )
{
2012-01-07 15:52:38 -08:00
int i ;
for ( i = 0 ; i < MaxGames ; i + + )
2010-01-03 01:17:55 -08:00
{
widgDelete ( psWScreen , GAMES_GAMESTART + i ) ; // remove old widget
}
2012-01-07 15:52:38 -08:00
widgDelete ( psWScreen , FRONTEND_NOGAMESAVAILABLE ) ;
2007-06-28 10:47:08 -07:00
}
void runGameFind ( void )
{
static UDWORD lastupdate = 0 ;
2012-01-10 18:24:32 -08:00
static char game_password [ StringSize ] ;
2006-05-27 09:37:17 -07:00
2012-01-07 15:52:38 -08:00
if ( lastupdate > gameTime ) lastupdate = 0 ;
if ( gameTime - lastupdate > 6000 & & ! EnablePasswordPrompt )
2007-06-28 10:47:08 -07:00
{
lastupdate = gameTime ;
2012-01-07 15:52:38 -08:00
if ( safeSearch )
2007-06-28 10:47:08 -07:00
{
2012-03-25 21:19:37 -07:00
if ( ! NETfindGame ( ) ) // find games synchronously
{
pie_LoadBackDrop ( SCREEN_RANDOMBDROP ) ;
}
2007-06-28 10:47:08 -07:00
}
addGames ( ) ; //redraw list
2012-01-10 18:24:32 -08:00
addConsoleBox ( ) ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2013-01-27 00:02:31 -08:00
WidgetTriggers const & triggers = widgRunScreen ( psWScreen ) ;
unsigned id = triggers . empty ( ) ? 0 : triggers . front ( ) . widget - > id ; // Just use first click here, since the next click could be on another menu.
2012-01-07 15:52:38 -08:00
if ( id = = CON_CANCEL ) // ok
2007-06-28 10:47:08 -07:00
{
2012-01-07 15:52:38 -08:00
changeTitleMode ( PROTOCOL ) ;
2007-06-28 10:47:08 -07:00
}
2012-01-07 15:52:38 -08:00
2013-02-16 19:18:26 -08:00
if ( id = = MULTIOP_REFRESH | | id = = MULTIOP_FILTER_TOGGLE )
2009-04-19 11:45:28 -07:00
{
2013-02-16 19:18:26 -08:00
if ( id = = MULTIOP_FILTER_TOGGLE )
{
toggleFilter = ! toggleFilter ;
2013-10-30 19:45:39 -07:00
toggleFilter ? widgSetButtonState ( psWScreen , MULTIOP_FILTER_TOGGLE , WBUT_CLICKLOCK ) : widgSetButtonState ( psWScreen , MULTIOP_FILTER_TOGGLE , 0 ) ;
}
else
{
widgSetButtonState ( psWScreen , MULTIOP_FILTER_TOGGLE , 0 ) ;
2013-02-16 19:18:26 -08:00
}
2012-01-07 15:52:38 -08:00
ingame . localOptionsReceived = true ;
2012-03-25 21:19:37 -07:00
if ( ! NETfindGame ( ) ) // find games synchronously
{
pie_LoadBackDrop ( SCREEN_RANDOMBDROP ) ;
}
2012-01-10 18:24:32 -08:00
addGames ( ) ; //redraw list.
addConsoleBox ( ) ;
2009-04-19 11:45:28 -07:00
}
2012-01-07 15:52:38 -08:00
if ( id = = CON_PASSWORD )
2007-06-28 10:47:08 -07:00
{
2012-01-07 15:52:38 -08:00
sstrcpy ( game_password , widgGetString ( psWScreen , CON_PASSWORD ) ) ;
NETsetGamePassword ( game_password ) ;
}
2011-04-27 06:17:55 -07:00
2012-01-07 15:52:38 -08:00
// below is when they hit a game box to connect to--ideally this would be where
// we would want a modal password entry box.
2012-01-10 18:24:32 -08:00
if ( id > = GAMES_GAMESTART & & id < = GAMES_GAMEEND )
2012-01-07 15:52:38 -08:00
{
2012-01-10 18:24:32 -08:00
gameNumber = id - GAMES_GAMESTART ;
2011-04-27 06:17:55 -07:00
2012-01-10 18:24:32 -08:00
if ( NetPlay . games [ gameNumber ] . privateGame )
2012-01-07 15:52:38 -08:00
{
2012-01-10 18:24:32 -08:00
showPasswordForm ( ) ;
}
else
{
ingame . localOptionsReceived = false ; // note, we are awaiting options
sstrcpy ( game . name , NetPlay . games [ gameNumber ] . name ) ; // store name
joinGame ( NetPlay . games [ gameNumber ] . desc . host , 0 ) ;
2012-01-07 15:52:38 -08:00
}
2010-01-03 01:17:55 -08:00
}
2012-01-07 15:52:38 -08:00
else if ( id = = CON_PASSWORDYES )
{
2012-01-10 18:24:32 -08:00
ingame . localOptionsReceived = false ; // note, we are awaiting options
2012-01-07 15:52:38 -08:00
sstrcpy ( game . name , NetPlay . games [ gameNumber ] . name ) ; // store name
joinGame ( NetPlay . games [ gameNumber ] . desc . host , 0 ) ;
}
else if ( id = = CON_PASSWORDNO )
{
hidePasswordForm ( ) ;
}
2007-06-28 10:47:08 -07:00
widgDisplayScreen ( psWScreen ) ; // show the widgets currently running
2012-01-07 15:52:38 -08:00
if ( safeSearch )
2007-06-28 10:47:08 -07:00
{
2012-01-07 15:52:38 -08:00
iV_SetFont ( font_large ) ;
iV_DrawText ( _ ( " Searching " ) , D_W + 260 , D_H + 460 ) ;
2007-06-28 10:47:08 -07:00
}
2012-01-07 15:52:38 -08:00
2010-06-20 17:39:03 -07:00
if ( CancelPressed ( ) )
{
2012-01-07 15:52:38 -08:00
changeTitleMode ( PROTOCOL ) ;
2010-06-20 17:39:03 -07:00
}
2012-01-10 18:24:32 -08:00
// console box handling
iV_SetFont ( font_small ) ;
if ( widgGetFromID ( psWScreen , MULTIOP_CONSOLEBOX ) )
{
while ( getNumberConsoleMessages ( ) > getConsoleLineInfo ( ) )
{
removeTopConsoleMessage ( ) ;
}
updateConsoleMessages ( ) ;
}
displayConsoleMessages ( ) ;
2007-06-28 10:47:08 -07:00
}
2009-04-19 11:45:28 -07:00
// This is what starts the lobby screen
2007-06-28 10:47:08 -07:00
void startGameFind ( void )
{
2009-04-19 11:45:28 -07:00
addBackdrop ( ) ; //background image
2013-02-27 23:29:08 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
2012-01-07 15:52:38 -08:00
2009-04-19 11:45:28 -07:00
// draws the background of the games listed
2013-02-27 23:29:08 -08:00
IntFormAnimated * botForm = new IntFormAnimated ( parent ) ;
botForm - > id = FRONTEND_BOTFORM ;
botForm - > setGeometry ( MULTIOP_OPTIONSX , MULTIOP_OPTIONSY , MULTIOP_CHATBOXW , 415 ) ; // FIXME: Add box at bottom for server messages
2007-06-28 10:47:08 -07:00
2010-01-03 01:17:55 -08:00
addSideText ( FRONTEND_SIDETEXT , MULTIOP_OPTIONSX - 3 , MULTIOP_OPTIONSY , _ ( " GAMES " ) ) ;
2007-06-28 10:47:08 -07:00
// cancel
2007-04-13 05:28:50 -07:00
addMultiBut ( psWScreen , FRONTEND_BOTFORM , CON_CANCEL , 10 , 5 , MULTIOP_OKW , MULTIOP_OKH , _ ( " Return To Previous Screen " ) ,
2008-04-18 10:05:40 -07:00
IMAGE_RETURN , IMAGE_RETURN_HI , IMAGE_RETURN_HI ) ;
2007-06-28 10:47:08 -07:00
2010-01-03 01:17:55 -08:00
//refresh
2013-10-30 19:45:39 -07:00
addMultiBut ( psWScreen , FRONTEND_BOTFORM , MULTIOP_REFRESH , MULTIOP_CHATBOXW - MULTIOP_OKW - 5 , 5 , MULTIOP_OKW , MULTIOP_OKH ,
_ ( " Refresh Games List " ) , IMAGE_RELOAD_HI , IMAGE_RELOAD , IMAGE_RELOAD ) ;
2013-02-16 19:18:26 -08:00
//filter toggle
2013-10-30 19:45:39 -07:00
addMultiBut ( psWScreen , FRONTEND_BOTFORM , MULTIOP_FILTER_TOGGLE , MULTIOP_CHATBOXW - MULTIOP_OKW - 45 , 5 , MULTIOP_OKW , MULTIOP_OKH ,
_ ( " Filter Games List " ) , IMAGE_FILTER , IMAGE_FILTER_ON , IMAGE_FILTER_ON ) ;
2010-01-03 01:17:55 -08:00
if ( safeSearch | | disableLobbyRefresh )
2007-06-28 10:47:08 -07:00
{
2010-01-03 01:17:55 -08:00
widgHide ( psWScreen , MULTIOP_REFRESH ) ;
2013-10-31 19:43:00 -07:00
widgHide ( psWScreen , MULTIOP_FILTER_TOGGLE ) ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2012-03-25 21:19:37 -07:00
if ( ! NETfindGame ( ) )
{
pie_LoadBackDrop ( SCREEN_RANDOMBDROP ) ;
}
2012-01-07 15:52:38 -08:00
addGames ( ) ; // now add games.
2012-01-10 18:24:32 -08:00
addConsoleBox ( ) ;
displayConsoleMessages ( ) ;
2009-04-19 11:45:28 -07:00
2010-01-03 01:17:55 -08:00
// Password stuff. Hidden by default.
2009-04-19 11:45:28 -07:00
2010-01-03 01:17:55 -08:00
// draws the background of the password box
2013-02-27 23:29:08 -08:00
IntFormAnimated * passwordForm = new IntFormAnimated ( parent ) ;
2013-02-25 10:25:05 -08:00
passwordForm - > id = FRONTEND_PASSWORDFORM ;
passwordForm - > setGeometry ( FRONTEND_BOTFORMX , 160 , FRONTEND_TOPFORMW , FRONTEND_TOPFORMH - 40 ) ;
2012-01-07 15:52:38 -08:00
2013-02-25 10:25:05 -08:00
// password label.
W_LABEL * enterPasswordLabel = new W_LABEL ( passwordForm ) ;
enterPasswordLabel - > setTextAlignment ( WLAB_ALIGNCENTRE ) ;
enterPasswordLabel - > setGeometry ( 130 , 0 , 280 , 40 ) ;
enterPasswordLabel - > setFont ( font_large , WZCOL_FORM_TEXT ) ;
enterPasswordLabel - > setString ( _ ( " Enter Password: " ) ) ;
2010-01-03 01:17:55 -08:00
2013-02-25 10:25:05 -08:00
// and finally draw the password entry box
W_EDITBOX * passwordBox = new W_EDITBOX ( passwordForm ) ;
passwordBox - > id = CON_PASSWORD ;
passwordBox - > setGeometry ( 130 , 40 , 280 , 20 ) ;
passwordBox - > setBoxColours ( WZCOL_MENU_BORDER , WZCOL_MENU_BORDER , WZCOL_MENU_BACKGROUND ) ;
W_BUTTON * buttonYes = new W_BUTTON ( passwordForm ) ;
buttonYes - > id = CON_PASSWORDYES ;
buttonYes - > setImages ( Image ( FrontImages , IMAGE_OK ) , Image ( FrontImages , IMAGE_OK ) , getFrontHighlightImage ( Image ( FrontImages , IMAGE_OK ) ) ) ;
buttonYes - > move ( 180 , 65 ) ;
buttonYes - > setTip ( _ ( " OK " ) ) ;
W_BUTTON * buttonNo = new W_BUTTON ( passwordForm ) ;
buttonNo - > id = CON_PASSWORDNO ;
buttonNo - > setImages ( Image ( FrontImages , IMAGE_NO ) , Image ( FrontImages , IMAGE_NO ) , getFrontHighlightImage ( Image ( FrontImages , IMAGE_NO ) ) ) ;
buttonNo - > move ( 230 , 65 ) ;
buttonNo - > setTip ( _ ( " Cancel " ) ) ;
passwordForm - > hide ( ) ;
2010-01-03 01:17:55 -08:00
EnablePasswordPrompt = false ;
}
static void hidePasswordForm ( void )
{
EnablePasswordPrompt = false ;
2012-02-03 15:21:03 -08:00
if ( widgGetFromID ( psWScreen , FRONTEND_PASSWORDFORM ) ) widgHide ( psWScreen , FRONTEND_PASSWORDFORM ) ;
2010-01-03 01:17:55 -08:00
widgReveal ( psWScreen , FRONTEND_SIDETEXT ) ;
widgReveal ( psWScreen , FRONTEND_BOTFORM ) ;
widgReveal ( psWScreen , CON_CANCEL ) ;
if ( ! safeSearch & & ( ! disableLobbyRefresh ) )
{
2012-03-25 21:19:37 -07:00
if ( widgGetFromID ( psWScreen , MULTIOP_REFRESH ) ) widgReveal ( psWScreen , MULTIOP_REFRESH ) ;
2013-10-31 19:43:00 -07:00
if ( widgGetFromID ( psWScreen , MULTIOP_FILTER_TOGGLE ) ) widgReveal ( psWScreen , MULTIOP_FILTER_TOGGLE ) ;
2009-04-19 11:45:28 -07:00
}
2010-01-03 01:17:55 -08:00
addGames ( ) ;
2012-01-10 18:24:32 -08:00
addConsoleBox ( ) ;
2010-01-03 01:17:55 -08:00
}
2011-01-04 09:51:15 -08:00
2010-01-03 01:17:55 -08:00
static void showPasswordForm ( void )
{
W_CONTEXT sContext ;
EnablePasswordPrompt = true ;
widgHide ( psWScreen , FRONTEND_SIDETEXT ) ;
widgHide ( psWScreen , FRONTEND_BOTFORM ) ;
widgHide ( psWScreen , CON_CANCEL ) ;
widgHide ( psWScreen , MULTIOP_REFRESH ) ;
2013-10-31 19:43:00 -07:00
widgHide ( psWScreen , MULTIOP_FILTER_TOGGLE ) ;
2010-01-03 01:17:55 -08:00
removeGames ( ) ;
widgReveal ( psWScreen , FRONTEND_PASSWORDFORM ) ;
// auto click in the password box
sContext . xOffset = 0 ;
sContext . yOffset = 0 ;
sContext . mx = 0 ;
sContext . my = 0 ;
2010-12-20 12:37:49 -08:00
widgGetFromID ( psWScreen , CON_PASSWORD ) - > clicked ( & sContext ) ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////////
// Game Options Screen.
// ////////////////////////////////////////////////////////////////////////////
2013-03-14 09:57:43 -07:00
MultibuttonWidget : : MultibuttonWidget ( WIDGET * parent , int value )
2013-03-14 03:01:51 -07:00
: W_FORM ( parent )
, label ( nullptr )
, mapper ( new QSignalMapper ( this ) )
, currentValue_ ( value )
, disabled ( false )
, gap_ ( 3 )
2013-03-14 09:57:43 -07:00
, lockCurrent ( false )
2013-03-14 03:01:51 -07:00
{
connect ( mapper , SIGNAL ( mapped ( int ) ) , this , SLOT ( choose ( int ) ) ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : display ( int xOffset , int yOffset )
2013-03-14 03:01:51 -07:00
{
iV_ShadowBox ( xOffset + x ( ) , yOffset + y ( ) , xOffset + x ( ) + width ( ) - 1 , yOffset + y ( ) + height ( ) - 1 , 0 , WZCOL_MENU_BORDER , WZCOL_MENU_BORDER , WZCOL_MENU_BACKGROUND ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : geometryChanged ( )
2013-03-14 03:01:51 -07:00
{
int s = width ( ) - gap_ ;
for ( std : : vector < std : : pair < W_BUTTON * , int > > : : const_reverse_iterator i = buttons . rbegin ( ) ; i ! = buttons . rend ( ) ; + + i )
{
i - > first - > move ( s - i - > first - > width ( ) , ( height ( ) - i - > first - > height ( ) ) / 2 ) ;
s - = i - > first - > width ( ) + gap_ ;
}
if ( label ! = nullptr )
{
label - > setGeometry ( gap_ , 0 , s - gap_ , height ( ) ) ;
}
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : setLabel ( char const * text )
2013-03-14 03:01:51 -07:00
{
delete label ;
label = new W_LABEL ( this ) ;
label - > setString ( text ) ;
geometryChanged ( ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : addButton ( int value , Image image , Image imageDown , char const * tip )
2013-03-14 03:01:51 -07:00
{
W_BUTTON * button = new W_BUTTON ( this ) ;
button - > setImages ( image , imageDown , getFrontHighlightImage ( image ) ) ;
button - > setTip ( tip ) ;
2013-03-14 09:57:43 -07:00
button - > setState ( value = = currentValue_ & & lockCurrent ? WBUT_LOCK : disabled ? WBUT_DISABLE : 0 ) ;
2013-03-14 03:01:51 -07:00
buttons . push_back ( std : : make_pair ( button , value ) ) ;
mapper - > setMapping ( button , value ) ;
connect ( button , SIGNAL ( clicked ( ) ) , mapper , SLOT ( map ( ) ) ) ;
geometryChanged ( ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : enable ( bool enabled )
2013-03-14 03:01:51 -07:00
{
if ( ! enabled = = disabled )
{
return ;
}
disabled = ! enabled ;
stateChanged ( ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : setGap ( int gap )
2013-03-14 03:01:51 -07:00
{
if ( gap = = gap_ )
{
return ;
}
gap_ = gap ;
geometryChanged ( ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : choose ( int value )
2013-03-14 03:01:51 -07:00
{
2013-03-14 09:57:43 -07:00
if ( value = = currentValue_ & & lockCurrent )
2013-03-14 03:01:51 -07:00
{
return ;
}
currentValue_ = value ;
stateChanged ( ) ;
emit chosen ( currentValue_ ) ;
screenPointer - > setReturn ( this ) ;
}
2013-03-14 09:57:43 -07:00
void MultibuttonWidget : : stateChanged ( )
2013-03-14 03:01:51 -07:00
{
for ( std : : vector < std : : pair < W_BUTTON * , int > > : : const_iterator i = buttons . begin ( ) ; i ! = buttons . end ( ) ; + + i )
{
2013-03-14 09:57:43 -07:00
i - > first - > setState ( i - > second = = currentValue_ & & lockCurrent ? WBUT_LOCK : disabled ? WBUT_DISABLE : 0 ) ;
2013-03-14 03:01:51 -07:00
}
}
2013-03-14 09:57:43 -07:00
MultichoiceWidget : : MultichoiceWidget ( WIDGET * parent , int value )
: MultibuttonWidget ( parent , value )
{
lockCurrent = true ;
}
2007-04-09 15:09:27 -07:00
static void addBlueForm ( UDWORD parent , UDWORD id , const char * txt , UDWORD x , UDWORD y , UDWORD w , UDWORD h )
2007-06-28 10:47:08 -07:00
{
2010-12-22 06:02:14 -08:00
W_FORMINIT sFormInit ; // draw options box.
2007-06-28 10:47:08 -07:00
sFormInit . formID = parent ;
sFormInit . id = id ;
sFormInit . x = ( UWORD ) x ;
sFormInit . y = ( UWORD ) y ;
sFormInit . style = WFORM_PLAIN ;
sFormInit . width = ( UWORD ) w ; //190;
sFormInit . height = ( UWORD ) h ; //27;
sFormInit . pDisplay = intDisplayFeBox ;
widgAddForm ( psWScreen , & sFormInit ) ;
if ( strlen ( txt ) > 0 )
{
2010-12-22 06:02:14 -08:00
W_LABINIT sLabInit ;
2007-06-28 10:47:08 -07:00
sLabInit . formID = id ;
sLabInit . id = id + 1 ;
sLabInit . x = 3 ;
sLabInit . y = 4 ;
sLabInit . width = 80 ;
sLabInit . height = 20 ;
sLabInit . pText = txt ;
widgAddLabel ( psWScreen , & sLabInit ) ;
}
return ;
}
2011-02-25 12:30:13 -08:00
struct LimitIcon
2010-09-06 14:06:21 -07:00
{
char const * stat ;
char const * desc ;
int icon ;
2011-02-25 12:30:13 -08:00
} ;
2010-09-06 14:06:21 -07:00
static const LimitIcon limitIcons [ ] =
{
2010-09-19 14:32:10 -07:00
{ " A0LightFactory " , N_ ( " Tanks disabled!! " ) , IMAGE_NO_TANK } ,
{ " A0CyborgFactory " , N_ ( " Cyborgs disabled. " ) , IMAGE_NO_CYBORG } ,
2012-08-05 14:03:24 -07:00
{ " A0VTolFactory1 " , N_ ( " VTOLs disabled. " ) , IMAGE_NO_VTOL } ,
{ " A0Sat-linkCentre " , N_ ( " Satellite Uplink disabled. " ) , IMAGE_NO_UPLINK } ,
{ " A0LasSatCommand " , N_ ( " Laser Satellite disabled. " ) , IMAGE_NO_LASSAT } ,
2010-09-06 14:06:21 -07:00
} ;
void updateLimitFlags ( )
{
unsigned i ;
unsigned flags = 0 ;
if ( ! ingame . bHostSetup )
{
return ; // The host works out the flags.
}
for ( i = 0 ; i < ARRAY_SIZE ( limitIcons ) ; + + i )
{
int stat = getStructStatFromName ( limitIcons [ i ] . stat ) ;
bool disabled = asStructLimits [ 0 ] ! = NULL & & stat > = 0 & & asStructLimits [ 0 ] [ stat ] . limit = = 0 ;
flags | = disabled < < i ;
}
ingame . flags = flags ;
}
2009-10-09 17:38:00 -07:00
// need to check for side effects.
2011-01-04 09:51:15 -08:00
static void addGameOptions ( )
2007-06-28 10:47:08 -07:00
{
widgDelete ( psWScreen , MULTIOP_OPTIONS ) ; // clear options list
widgDelete ( psWScreen , FRONTEND_SIDETEXT3 ) ; // del text..
2006-05-27 09:37:17 -07:00
2007-10-01 12:45:49 -07:00
iV_SetFont ( font_regular ) ;
2007-06-28 10:47:08 -07:00
2013-02-27 23:29:08 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
// draw options box.
IntFormAnimated * optionsForm = new IntFormAnimated ( parent , false ) ;
optionsForm - > id = MULTIOP_OPTIONS ;
optionsForm - > setGeometry ( MULTIOP_OPTIONSX , MULTIOP_OPTIONSY , MULTIOP_OPTIONSW , MULTIOP_OPTIONSH ) ;
2007-06-28 10:47:08 -07:00
2007-04-01 13:15:46 -07:00
addSideText ( FRONTEND_SIDETEXT3 , MULTIOP_OPTIONSX - 3 , MULTIOP_OPTIONSY , _ ( " OPTIONS " ) ) ;
2006-05-27 09:37:17 -07:00
2010-01-02 18:37:15 -08:00
// game name box
if ( ! NetPlay . bComms )
{
2013-01-05 08:02:08 -08:00
addMultiEditBox ( MULTIOP_OPTIONS , MULTIOP_GNAME , MCOL0 , MROW2 , _ ( " Game Name " ) ,
challengeActive ? game . name : _ ( " One-Player Skirmish " ) , IMAGE_EDIT_GAME ,
2012-01-14 06:59:20 -08:00
IMAGE_EDIT_GAME_HI , MULTIOP_GNAME_ICON ) ;
2010-01-02 18:37:15 -08:00
// disable for one-player skirmish
widgSetButtonState ( psWScreen , MULTIOP_GNAME , WEDBS_DISABLE ) ;
}
else
{
addMultiEditBox ( MULTIOP_OPTIONS , MULTIOP_GNAME , MCOL0 , MROW2 , _ ( " Select Game Name " ) , game . name , IMAGE_EDIT_GAME , IMAGE_EDIT_GAME_HI , MULTIOP_GNAME_ICON ) ;
}
2012-09-20 09:06:10 -07:00
widgSetButtonState ( psWScreen , MULTIOP_GNAME_ICON , WBUT_DISABLE ) ;
2013-11-20 19:09:40 -08:00
2010-01-02 18:37:15 -08:00
// map chooser
2013-11-20 19:09:40 -08:00
addBlueForm ( MULTIOP_OPTIONS , MULTIOP_MAP , game . map , MCOL0 , MROW3 , MULTIOP_BLUEFORMW , 29 ) ;
addMultiBut ( psWScreen , MULTIOP_MAP , MULTIOP_MAP_ICON , MCOL4 , 2 , 20 , MULTIOP_BUTH , _ ( " Select Map " ) , IMAGE_EDIT_MAP , IMAGE_EDIT_MAP_HI , true ) ;
addMultiBut ( psWScreen , MULTIOP_MAP , MULTIOP_MAP_MOD , MCOL3 + 11 , 10 , 12 , 12 , _ ( " Map-Mod! " ) , IMAGE_LAMP_RED , IMAGE_LAMP_AMBER , false ) ;
if ( ! game . isMapMod )
{
widgHide ( psWScreen , MULTIOP_MAP_MOD ) ;
}
2010-01-02 18:37:15 -08:00
// disable for challenges
2009-08-11 13:36:44 -07:00
if ( challengeActive )
{
widgSetButtonState ( psWScreen , MULTIOP_MAP_ICON , WBUT_DISABLE ) ;
}
2009-04-19 11:45:28 -07:00
// password box
2012-09-03 01:25:05 -07:00
if ( ingame . bHostSetup & & NetPlay . bComms )
2009-04-23 11:59:58 -07:00
{
2012-03-23 18:24:40 -07:00
addMultiEditBox ( MULTIOP_OPTIONS , MULTIOP_PASSWORD_EDIT , MCOL0 , MROW4 , _ ( " Click to set Password " ) , NetPlay . gamePassword , IMAGE_UNLOCK_BLUE , IMAGE_LOCK_BLUE , MULTIOP_PASSWORD_BUT ) ;
2012-09-03 01:25:05 -07:00
if ( NetPlay . GamePassworded )
{
widgSetButtonState ( psWScreen , MULTIOP_PASSWORD_BUT , WBUT_CLICKLOCK ) ;
widgSetButtonState ( psWScreen , MULTIOP_PASSWORD_EDIT , WEDBS_DISABLE ) ;
}
2012-03-23 18:24:40 -07:00
}
2011-07-17 12:41:06 -07:00
2012-01-07 15:52:38 -08:00
//just display the game options.
2008-04-18 12:45:10 -07:00
addMultiEditBox ( MULTIOP_OPTIONS , MULTIOP_PNAME , MCOL0 , MROW1 , _ ( " Select Player Name " ) , ( char * ) sPlayer , IMAGE_EDIT_PLAYER , IMAGE_EDIT_PLAYER_HI , MULTIOP_PNAME_ICON ) ;
2007-06-28 10:47:08 -07:00
2013-03-14 09:57:43 -07:00
ListWidget * optionsList = new ListWidget ( optionsForm ) ;
optionsList - > setChildSize ( MULTIOP_BLUEFORMW , 29 ) ;
optionsList - > setChildSpacing ( 2 , 2 ) ;
optionsList - > setGeometry ( MCOL0 , MROW5 , MULTIOP_BLUEFORMW , optionsForm - > height ( ) - MROW5 ) ;
2007-06-28 10:47:08 -07:00
2013-03-14 09:57:43 -07:00
MultichoiceWidget * scavengerChoice = new MultichoiceWidget ( optionsList , game . scavengers ) ;
scavengerChoice - > id = MULTIOP_GAMETYPE ;
scavengerChoice - > setLabel ( _ ( " Scavengers " ) ) ;
if ( game . mapHasScavengers )
{
scavengerChoice - > addButton ( true , Image ( FrontImages , IMAGE_SCAVENGERS_ON ) , Image ( FrontImages , IMAGE_SCAVENGERS_ON_HI ) , _ ( " Scavengers " ) ) ;
}
scavengerChoice - > addButton ( false , Image ( FrontImages , IMAGE_SCAVENGERS_OFF ) , Image ( FrontImages , IMAGE_SCAVENGERS_OFF_HI ) , _ ( " No Scavengers " ) ) ;
scavengerChoice - > enable ( ! locked . scavengers ) ;
optionsList - > addWidgetToLayout ( scavengerChoice ) ;
2006-09-26 11:14:05 -07:00
2013-03-14 09:57:43 -07:00
MultichoiceWidget * allianceChoice = new MultichoiceWidget ( optionsList , game . alliance ) ;
allianceChoice - > id = MULTIOP_ALLIANCES ;
allianceChoice - > setLabel ( _ ( " Alliances " ) ) ;
allianceChoice - > addButton ( NO_ALLIANCES , Image ( FrontImages , IMAGE_NOALLI ) , Image ( FrontImages , IMAGE_NOALLI_HI ) , _ ( " No Alliances " ) ) ;
allianceChoice - > addButton ( ALLIANCES , Image ( FrontImages , IMAGE_ALLI ) , Image ( FrontImages , IMAGE_ALLI_HI ) , _ ( " Allow Alliances " ) ) ;
2013-04-29 12:20:34 -07:00
allianceChoice - > addButton ( ALLIANCES_UNSHARED , Image ( FrontImages , IMAGE_ALLI_UNSHARED ) , Image ( FrontImages , IMAGE_ALLI_UNSHARED_HI ) , _ ( " Locked Teams, No Shared Research " ) ) ;
2013-03-14 09:57:43 -07:00
allianceChoice - > addButton ( ALLIANCES_TEAMS , Image ( FrontImages , IMAGE_ALLI_TEAMS ) , Image ( FrontImages , IMAGE_ALLI_TEAMS_HI ) , _ ( " Locked Teams " ) ) ;
allianceChoice - > enable ( ! locked . alliances ) ;
optionsList - > addWidgetToLayout ( allianceChoice ) ;
2006-05-27 09:37:17 -07:00
2013-03-14 09:57:43 -07:00
MultichoiceWidget * powerChoice = new MultichoiceWidget ( optionsList , game . power ) ;
2013-03-14 03:01:51 -07:00
powerChoice - > id = MULTIOP_POWER ;
powerChoice - > setLabel ( _ ( " Power " ) ) ;
powerChoice - > addButton ( LEV_LOW , Image ( FrontImages , IMAGE_POWLO ) , Image ( FrontImages , IMAGE_POWLO_HI ) , _ ( " Low Power Levels " ) ) ;
powerChoice - > addButton ( LEV_MED , Image ( FrontImages , IMAGE_POWMED ) , Image ( FrontImages , IMAGE_POWMED_HI ) , _ ( " Medium Power Levels " ) ) ;
powerChoice - > addButton ( LEV_HI , Image ( FrontImages , IMAGE_POWHI ) , Image ( FrontImages , IMAGE_POWHI_HI ) , _ ( " High Power Levels " ) ) ;
powerChoice - > enable ( ! locked . power ) ;
2013-03-14 09:57:43 -07:00
optionsList - > addWidgetToLayout ( powerChoice ) ;
MultichoiceWidget * baseTypeChoice = new MultichoiceWidget ( optionsList , game . base ) ;
baseTypeChoice - > id = MULTIOP_BASETYPE ;
baseTypeChoice - > setLabel ( _ ( " Base " ) ) ;
baseTypeChoice - > addButton ( CAMP_CLEAN , Image ( FrontImages , IMAGE_NOBASE ) , Image ( FrontImages , IMAGE_NOBASE_HI ) , _ ( " Start with No Bases " ) ) ;
baseTypeChoice - > addButton ( CAMP_BASE , Image ( FrontImages , IMAGE_SBASE ) , Image ( FrontImages , IMAGE_SBASE_HI ) , _ ( " Start with Bases " ) ) ;
baseTypeChoice - > addButton ( CAMP_WALLS , Image ( FrontImages , IMAGE_LBASE ) , Image ( FrontImages , IMAGE_LBASE_HI ) , _ ( " Start with Advanced Bases " ) ) ;
baseTypeChoice - > enable ( ! locked . bases ) ;
optionsList - > addWidgetToLayout ( baseTypeChoice ) ;
MultibuttonWidget * mapPreviewButton = new MultibuttonWidget ( optionsList ) ;
mapPreviewButton - > id = MULTIOP_MAP_PREVIEW ;
mapPreviewButton - > setLabel ( _ ( " Map Preview " ) ) ;
mapPreviewButton - > addButton ( 0 , Image ( FrontImages , IMAGE_FOG_OFF ) , Image ( FrontImages , IMAGE_FOG_OFF_HI ) , _ ( " Click to see Map " ) ) ;
optionsList - > addWidgetToLayout ( mapPreviewButton ) ;
2007-06-28 10:47:08 -07:00
2013-03-14 09:57:43 -07:00
if ( ingame . bHostSetup )
2009-08-11 13:36:44 -07:00
{
2013-03-14 09:57:43 -07:00
MultibuttonWidget * structLimitsButton = new MultibuttonWidget ( optionsList ) ;
structLimitsButton - > id = MULTIOP_STRUCTLIMITS ;
structLimitsButton - > setLabel ( challengeActive ? _ ( " Show Structure Limits " ) : _ ( " Set Structure Limits " ) ) ;
structLimitsButton - > addButton ( 0 , Image ( FrontImages , IMAGE_SLIM ) , Image ( FrontImages , IMAGE_SLIM_HI ) , challengeActive ? _ ( " Show Structure Limits " ) : _ ( " Set Structure Limits " ) ) ;
optionsList - > addWidgetToLayout ( structLimitsButton ) ;
2009-08-11 13:36:44 -07:00
}
2007-06-28 10:47:08 -07:00
2013-03-14 09:57:43 -07:00
if ( ingame . bHostSetup & & ! bHosted & & ! challengeActive )
2007-06-28 10:47:08 -07:00
{
2013-03-14 09:57:43 -07:00
MultibuttonWidget * hostButton = new MultibuttonWidget ( optionsList ) ;
hostButton - > id = MULTIOP_HOST ;
hostButton - > setLabel ( _ ( " Start Hosting Game " ) ) ;
hostButton - > addButton ( 0 , Image ( FrontImages , IMAGE_HOST ) , Image ( FrontImages , IMAGE_HOST_HI ) , _ ( " Start Hosting Game " ) ) ;
optionsList - > addWidgetToLayout ( hostButton ) ;
2007-06-28 10:47:08 -07:00
}
// cancel
addMultiBut ( psWScreen , MULTIOP_OPTIONS , CON_CANCEL ,
MULTIOP_CANCELX , MULTIOP_CANCELY ,
iV_GetImageWidth ( FrontImages , IMAGE_RETURN ) ,
iV_GetImageHeight ( FrontImages , IMAGE_RETURN ) ,
2008-04-18 10:05:40 -07:00
_ ( " Return To Previous Screen " ) , IMAGE_RETURN , IMAGE_RETURN_HI , IMAGE_RETURN_HI ) ;
2007-06-28 10:47:08 -07:00
2010-09-06 14:06:21 -07:00
// Add any relevant factory disabled icons.
updateLimitFlags ( ) ;
2013-01-05 08:02:08 -08:00
2010-09-19 14:32:10 -07:00
int y = 2 ;
bool skip = false ;
2013-01-05 08:02:08 -08:00
for ( int i = 0 ; i < ARRAY_SIZE ( limitIcons ) ; + + i )
2010-09-06 14:06:21 -07:00
{
if ( ( ingame . flags & 1 < < i ) ! = 0 )
{
2010-09-19 14:32:10 -07:00
if ( ! skip )
{ // only add this once.
2012-08-05 14:03:24 -07:00
addBlueForm ( MULTIOP_OPTIONS , MULTIOP_NO_SOMETHING , " " , MULTIOP_HOSTX , MULTIOP_NO_SOMETHINGY , 41 , 152 ) ;
2010-09-19 14:32:10 -07:00
}
addMultiBut ( psWScreen , MULTIOP_NO_SOMETHING , MULTIOP_NO_SOMETHINGY + i , MULTIOP_NO_SOMETHINGX , y ,
2010-09-06 14:06:21 -07:00
35 , 28 , _ ( limitIcons [ i ] . desc ) ,
limitIcons [ i ] . icon , limitIcons [ i ] . icon , limitIcons [ i ] . icon ) ;
2010-09-19 14:32:10 -07:00
y + = 28 + 3 ;
skip = true ;
2010-09-06 14:06:21 -07:00
}
}
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////////
// Colour functions
2012-01-10 04:05:06 -08:00
static bool safeToUseColour ( unsigned player , unsigned otherPlayer )
2006-05-27 09:37:17 -07:00
{
2012-01-10 04:05:06 -08:00
// Player wants to take the colour from otherPlayer. May not take from a human otherPlayer, unless we're the host.
return player = = otherPlayer | | NetPlay . isHost | | ! isHumanPlayer ( otherPlayer ) ;
2007-06-28 10:47:08 -07:00
}
2011-01-04 09:51:15 -08:00
static void initChooser ( int player )
2007-06-28 10:47:08 -07:00
{
// delete that players box,
2011-01-04 09:51:15 -08:00
widgDelete ( psWScreen , MULTIOP_PLAYER_START + player ) ;
2007-06-28 10:47:08 -07:00
2010-01-04 23:13:16 -08:00
// delete team chooser button
2011-01-04 09:51:15 -08:00
widgDelete ( psWScreen , MULTIOP_TEAMS_START + player ) ;
2006-09-26 11:14:05 -07:00
2010-01-04 23:13:16 -08:00
// delete 'ready' button
2011-01-04 09:51:15 -08:00
widgDelete ( psWScreen , MULTIOP_READY_FORM_ID + player ) ;
// delete 'colour' button
widgDelete ( psWScreen , MULTIOP_COLOUR_START + player ) ;
2008-04-09 13:05:09 -07:00
2011-01-04 09:51:15 -08:00
// remove any choosers already up
2010-01-04 23:13:16 -08:00
closeColourChooser ( ) ;
2011-01-04 09:51:15 -08:00
closeTeamChooser ( ) ;
}
2011-01-09 07:35:49 -08:00
static void addDifficultyChooser ( int player )
{
closeColourChooser ( ) ;
closeTeamChooser ( ) ;
widgDelete ( psWScreen , MULTIOP_AI_FORM ) ;
widgDelete ( psWScreen , MULTIOP_PLAYERS ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ;
difficultyChooserUp = player ;
2013-02-27 23:29:08 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
IntFormAnimated * aiForm = new IntFormAnimated ( parent , false ) ;
aiForm - > id = MULTIOP_AI_FORM ;
aiForm - > setGeometry ( MULTIOP_PLAYERSX , MULTIOP_PLAYERSY , MULTIOP_PLAYERSW , MULTIOP_PLAYERSH ) ;
2011-01-09 07:35:49 -08:00
addSideText ( FRONTEND_SIDETEXT2 , MULTIOP_PLAYERSX - 3 , MULTIOP_PLAYERSY , _ ( " DIFFICULTY " ) ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
W_BUTINIT sButInit ;
sButInit . formID = MULTIOP_AI_FORM ;
sButInit . id = MULTIOP_DIFFICULTY_CHOOSE_START + i ;
sButInit . x = 7 ;
sButInit . y = ( MULTIOP_PLAYERHEIGHT + 5 ) * i + 4 ;
sButInit . width = MULTIOP_PLAYERWIDTH + 1 ;
sButInit . height = MULTIOP_PLAYERHEIGHT ;
switch ( i )
{
2012-12-12 06:38:13 -08:00
case 0 : sButInit . pTip = _ ( " Starts disadvantaged " ) ; break ;
2011-01-09 07:35:49 -08:00
case 1 : sButInit . pTip = _ ( " Plays nice " ) ; break ;
case 2 : sButInit . pTip = _ ( " No holds barred " ) ; break ;
2011-12-17 05:03:52 -08:00
case 3 : sButInit . pTip = _ ( " Starts with advantages " ) ; break ;
2011-01-09 07:35:49 -08:00
}
sButInit . pDisplay = displayDifficulty ;
sButInit . UserData = i ;
widgAddButton ( psWScreen , & sButInit ) ;
}
}
static void addAiChooser ( int player )
{
closeColourChooser ( ) ;
closeTeamChooser ( ) ;
widgDelete ( psWScreen , MULTIOP_AI_FORM ) ;
widgDelete ( psWScreen , MULTIOP_PLAYERS ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ;
aiChooserUp = player ;
2013-02-27 23:29:08 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
IntFormAnimated * aiForm = new IntFormAnimated ( parent , false ) ;
aiForm - > id = MULTIOP_AI_FORM ;
aiForm - > setGeometry ( MULTIOP_PLAYERSX , MULTIOP_PLAYERSY , MULTIOP_PLAYERSW , MULTIOP_PLAYERSH ) ;
2011-01-09 07:35:49 -08:00
addSideText ( FRONTEND_SIDETEXT2 , MULTIOP_PLAYERSX - 3 , MULTIOP_PLAYERSY , _ ( " CHOOSE AI " ) ) ;
2011-01-15 04:29:23 -08:00
W_BUTINIT sButInit ;
sButInit . formID = MULTIOP_AI_FORM ;
sButInit . x = 7 ;
sButInit . width = MULTIOP_PLAYERWIDTH + 1 ;
2012-12-04 16:12:50 -08:00
// Try to fit as many as possible, just got to make sure text fits in the 'box'.
// NOTE: Correct way would be to get the actual font size, render the text, and see what fits.
if ( aidata . size ( ) > 8 )
{
sButInit . height = MULTIOP_PLAYERHEIGHT - 7 ;
}
else
{
sButInit . height = MULTIOP_PLAYERHEIGHT ;
}
2011-01-15 04:29:23 -08:00
sButInit . pDisplay = displayAi ;
2012-12-04 16:12:50 -08:00
// only need this button in (true) mp games
int mpbutton = NetPlay . bComms ? 1 : 0 ;
// cap AI's that are shown, since it looks a bit ugly. *FIXME*
int capAIs = aidata . size ( ) ;
2013-10-28 19:17:13 -07:00
if ( aidata . size ( ) > 9 )
2012-12-04 16:12:50 -08:00
{
2013-10-28 19:17:13 -07:00
debug ( LOG_INFO , " You have too many AI's loaded for the GUI to handle. Only the first 10 will be shown. " ) ;
addConsoleMessage ( " You have too many AI's loaded for the GUI to handle. Only the first 10 will be shown. " , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
2012-12-04 16:12:50 -08:00
capAIs = 10 ;
}
// button height * how many AI + possible buttons (openclosed)
int gap = MULTIOP_PLAYERSH - ( ( sButInit . height ) * ( capAIs + 1 + mpbutton ) ) ;
int gapDiv = capAIs - 1 ;
gap = std : : min ( gap , 5 * gapDiv ) ;
2011-01-15 04:29:23 -08:00
// Open button
2012-12-04 16:12:50 -08:00
if ( mpbutton )
2011-01-15 04:29:23 -08:00
{
sButInit . id = MULTIOP_AI_OPEN ;
sButInit . pTip = _ ( " Allow human players to join in this slot " ) ;
2011-03-15 10:15:24 -07:00
sButInit . UserData = ( UDWORD ) AI_OPEN ;
2012-12-04 16:12:50 -08:00
sButInit . y = 3 ; //Top most position
2011-01-15 04:29:23 -08:00
widgAddButton ( psWScreen , & sButInit ) ;
}
// Closed button
sButInit . pTip = _ ( " Leave this slot unused " ) ;
sButInit . id = MULTIOP_AI_CLOSED ;
2011-03-15 10:15:24 -07:00
sButInit . UserData = ( UDWORD ) AI_CLOSED ;
2012-12-04 16:12:50 -08:00
if ( mpbutton )
{
sButInit . y = sButInit . height ;
}
else
{
sButInit . y = 0 ; //since we don't have the lone mpbutton, we can start at position 0
}
2011-01-15 04:29:23 -08:00
widgAddButton ( psWScreen , & sButInit ) ;
2011-01-09 07:35:49 -08:00
2012-12-04 16:12:50 -08:00
for ( int i = 0 ; i < capAIs ; i + + )
2011-01-09 07:35:49 -08:00
{
2012-12-04 16:12:50 -08:00
sButInit . y = ( sButInit . height * gapDiv + gap ) * ( i + 1 + mpbutton ) / gapDiv ; // +1 for 'closed', and possible +1 more for 'open' for MP games)
2011-01-09 07:35:49 -08:00
sButInit . pTip = aidata [ i ] . tip ;
2011-01-15 04:29:23 -08:00
sButInit . id = MULTIOP_AI_START + i ;
2011-01-09 07:35:49 -08:00
sButInit . UserData = i ;
widgAddButton ( psWScreen , & sButInit ) ;
}
}
2008-04-09 13:05:09 -07:00
2011-01-09 07:35:49 -08:00
static void closeAiChooser ( )
{
widgDelete ( psWScreen , MULTIOP_AI_FORM ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ;
aiChooserUp = - 1 ;
}
static void closeDifficultyChooser ( )
{
widgDelete ( psWScreen , MULTIOP_AI_FORM ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ;
difficultyChooserUp = - 1 ;
}
2011-01-04 09:51:15 -08:00
static void closePositionChooser ( )
{
positionChooserUp = - 1 ;
}
2011-01-03 05:48:41 -08:00
static int playerBoxHeight ( int player )
{
2012-02-17 20:28:38 -08:00
int gap = MULTIOP_PLAYERSH - MULTIOP_TEAMSHEIGHT * game . maxPlayers ;
2011-01-03 05:48:41 -08:00
int gapDiv = game . maxPlayers - 1 ;
gap = std : : min ( gap , 5 * gapDiv ) ;
STATIC_ASSERT ( MULTIOP_TEAMSHEIGHT = = MULTIOP_PLAYERHEIGHT ) ; // Why are these different defines?
2012-02-17 20:28:38 -08:00
return ( MULTIOP_TEAMSHEIGHT * gapDiv + gap ) * NetPlay . players [ player ] . position / gapDiv ;
2011-01-03 05:48:41 -08:00
}
2011-01-04 09:51:15 -08:00
static void addPositionChooser ( int player )
{
2010-01-04 23:13:16 -08:00
closeColourChooser ( ) ;
2011-01-04 09:51:15 -08:00
closeTeamChooser ( ) ;
closePositionChooser ( ) ;
2011-01-09 07:35:49 -08:00
closeAiChooser ( ) ;
closeDifficultyChooser ( ) ;
2011-01-04 09:51:15 -08:00
positionChooserUp = player ;
addPlayerBox ( true ) ;
}
static void addColourChooser ( UDWORD player )
{
UDWORD i ;
initChooser ( player ) ;
2010-01-04 23:13:16 -08:00
2007-06-28 10:47:08 -07:00
// add form.
addBlueForm ( MULTIOP_PLAYERS , MULTIOP_COLCHOOSER_FORM , " " ,
2012-02-17 20:28:38 -08:00
8 ,
2011-01-03 05:48:41 -08:00
playerBoxHeight ( player ) ,
2006-09-26 11:14:05 -07:00
MULTIOP_ROW_WIDTH , MULTIOP_PLAYERHEIGHT ) ;
2007-06-28 10:47:08 -07:00
// add the flags
2011-03-17 12:44:34 -07:00
int flagW = iV_GetImageWidth ( FrontImages , IMAGE_PLAYERN ) ;
int flagH = iV_GetImageHeight ( FrontImages , IMAGE_PLAYERN ) ;
2012-02-17 20:28:38 -08:00
int space = MULTIOP_ROW_WIDTH - 0 - flagW * MAX_PLAYERS_IN_GUI ;
2011-01-03 05:48:41 -08:00
int spaceDiv = MAX_PLAYERS_IN_GUI ;
space = std : : min ( space , 5 * spaceDiv ) ;
for ( i = 0 ; i < MAX_PLAYERS_IN_GUI ; i + + )
2007-06-28 10:47:08 -07:00
{
2011-06-11 15:33:01 -07:00
addMultiBut ( psWScreen , MULTIOP_COLCHOOSER_FORM , MULTIOP_COLCHOOSER + getPlayerColour ( i ) ,
2011-01-03 05:48:41 -08:00
i * ( flagW * spaceDiv + space ) / spaceDiv + 7 , 4 , // x, y
flagW , flagH , // w, h
2011-06-11 15:33:01 -07:00
getPlayerColourName ( i ) , IMAGE_PLAYERN , IMAGE_PLAYERN_HI , IMAGE_PLAYERN_HI , getPlayerColour ( i ) ) ;
2007-06-28 10:47:08 -07:00
if ( ! safeToUseColour ( selectedPlayer , i ) )
{
2011-06-11 15:33:01 -07:00
widgSetButtonState ( psWScreen , MULTIOP_COLCHOOSER + getPlayerColour ( i ) , WBUT_DISABLE ) ;
2007-06-28 10:47:08 -07:00
}
}
2010-01-04 23:13:16 -08:00
colourChooserUp = player ;
2007-06-28 10:47:08 -07:00
}
2006-09-13 02:09:05 -07:00
static void closeColourChooser ( void )
2007-06-28 10:47:08 -07:00
{
2010-01-04 23:13:16 -08:00
colourChooserUp = - 1 ;
2007-06-28 10:47:08 -07:00
widgDelete ( psWScreen , MULTIOP_COLCHOOSER_FORM ) ;
}
2008-01-27 06:25:30 -08:00
static void changeTeam ( UBYTE player , UBYTE team )
2006-09-26 11:14:05 -07:00
{
2009-06-07 11:10:13 -07:00
NetPlay . players [ player ] . team = team ;
2008-01-27 06:25:30 -08:00
debug ( LOG_WZ , " set %d as new team for player %d " , team , player ) ;
2009-06-07 11:10:13 -07:00
NETBroadcastPlayerInfo ( player ) ;
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
2008-01-27 06:25:30 -08:00
}
2006-09-26 11:14:05 -07:00
2011-03-12 17:32:15 -08:00
static bool SendTeamRequest ( UBYTE player , UBYTE chosenTeam )
2008-01-27 06:25:30 -08:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost ) // do or request the change.
2006-09-26 11:14:05 -07:00
{
2008-01-27 06:25:30 -08:00
changeTeam ( player , chosenTeam ) ; // do the change, remember only the host can do this to avoid confusion.
2006-09-26 11:14:05 -07:00
}
else
{
2010-02-09 09:43:53 -08:00
NETbeginEncode ( NETnetQueue ( NET_HOST_ONLY ) , NET_TEAMREQUEST ) ;
2008-01-27 06:25:30 -08:00
NETuint8_t ( & player ) ;
NETuint8_t ( & chosenTeam ) ;
NETend ( ) ;
2006-09-26 11:14:05 -07:00
}
2008-03-24 09:51:17 -07:00
return true ;
2006-09-26 11:14:05 -07:00
}
2011-03-12 17:32:15 -08:00
bool recvTeamRequest ( NETQUEUE queue )
2006-09-26 11:14:05 -07:00
{
2008-01-27 06:25:30 -08:00
UBYTE player , team ;
2006-09-26 11:14:05 -07:00
2010-11-25 03:58:28 -08:00
if ( ! NetPlay . isHost | | ! bHosted ) // Only host should act, and only if the game hasn't started yet.
2006-09-26 11:14:05 -07:00
{
2012-02-19 14:49:49 -08:00
ASSERT ( false , " Host only routine detected for client! " ) ;
2008-03-24 09:51:17 -07:00
return true ;
2006-09-26 11:14:05 -07:00
}
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_TEAMREQUEST ) ;
2008-01-27 06:25:30 -08:00
NETuint8_t ( & player ) ;
NETuint8_t ( & team ) ;
NETend ( ) ;
2006-09-26 11:14:05 -07:00
2013-10-21 12:41:55 -07:00
if ( player > = MAX_PLAYERS | | team > = MAX_PLAYERS )
2008-01-27 06:25:30 -08:00
{
2012-02-19 14:49:49 -08:00
debug ( LOG_NET , " NET_TEAMREQUEST invalid, player %d team, %d " , ( int ) player , ( int ) team ) ;
2008-03-16 05:39:08 -07:00
debug ( LOG_ERROR , " Invalid NET_TEAMREQUEST from player %d: Tried to change player %d (team %d) " ,
2010-02-09 09:43:53 -08:00
queue . index , ( int ) player , ( int ) team ) ;
2008-03-24 09:51:17 -07:00
return false ;
2008-01-27 06:25:30 -08:00
}
2006-09-26 11:14:05 -07:00
2012-02-19 14:49:49 -08:00
if ( whosResponsible ( player ) ! = queue . index )
{
HandleBadParam ( " NET_TEAMREQUEST given incorrect params. " , player , queue . index ) ;
return false ;
}
2009-12-03 21:50:40 -08:00
if ( NetPlay . players [ player ] . team ! = team )
{
resetReadyStatus ( false ) ;
}
2012-02-19 14:49:49 -08:00
debug ( LOG_NET , " %s is now part of team: %d " , NetPlay . players [ player ] . name , ( int ) team ) ;
2009-12-03 21:50:40 -08:00
changeTeam ( player , team ) ; // we do this regardless, in case of sync issues
2006-09-26 11:14:05 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2006-09-26 11:14:05 -07:00
}
2011-03-12 17:32:15 -08:00
static bool SendReadyRequest ( UBYTE player , bool bReady )
2008-04-09 13:05:09 -07:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost ) // do or request the change.
2008-04-09 13:05:09 -07:00
{
return changeReadyStatus ( player , bReady ) ;
}
else
{
2012-02-19 14:49:49 -08:00
NETbeginEncode ( NETnetQueue ( NET_HOST_ONLY ) , NET_READY_REQUEST ) ;
2008-04-09 13:05:09 -07:00
NETuint8_t ( & player ) ;
NETbool ( & bReady ) ;
NETend ( ) ;
}
return true ;
}
2011-03-12 17:32:15 -08:00
bool recvReadyRequest ( NETQUEUE queue )
2008-04-09 13:05:09 -07:00
{
UBYTE player ;
2011-03-12 17:32:15 -08:00
bool bReady ;
2008-04-09 13:05:09 -07:00
2010-11-25 03:58:28 -08:00
if ( ! NetPlay . isHost | | ! bHosted ) // Only host should act, and only if the game hasn't started yet.
2008-04-09 13:05:09 -07:00
{
2012-02-19 14:49:49 -08:00
ASSERT ( false , " Host only routine detected for client! " ) ;
2008-04-09 13:05:09 -07:00
return true ;
}
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_READY_REQUEST ) ;
2008-04-09 13:05:09 -07:00
NETuint8_t ( & player ) ;
NETbool ( & bReady ) ;
NETend ( ) ;
2013-10-21 12:41:55 -07:00
if ( player > = MAX_PLAYERS )
2008-04-09 13:05:09 -07:00
{
debug ( LOG_ERROR , " Invalid NET_READY_REQUEST from player %d: player id = %d " ,
2010-02-09 09:43:53 -08:00
queue . index , ( int ) player ) ;
2008-04-09 13:05:09 -07:00
return false ;
}
2012-02-19 14:49:49 -08:00
if ( whosResponsible ( player ) ! = queue . index )
{
HandleBadParam ( " NET_READY_REQUEST given incorrect params. " , player , queue . index ) ;
return false ;
}
2009-12-18 16:23:37 -08:00
// do not allow players to select 'ready' if we are sending a map too them!
// TODO: make a new icon to show this state?
if ( NetPlay . players [ player ] . wzFile . isSending )
{
return false ;
}
2008-04-09 13:05:09 -07:00
return changeReadyStatus ( ( UBYTE ) player , bReady ) ;
}
2011-03-12 17:32:15 -08:00
static bool changeReadyStatus ( UBYTE player , bool bReady )
2008-04-09 13:05:09 -07:00
{
2009-06-07 11:10:13 -07:00
drawReadyButton ( player ) ;
NetPlay . players [ player ] . ready = bReady ;
NETBroadcastPlayerInfo ( player ) ;
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
2008-04-09 13:05:09 -07:00
return true ;
}
2011-03-12 17:32:15 -08:00
static bool changePosition ( UBYTE player , UBYTE position )
2007-06-28 10:47:08 -07:00
{
2009-06-07 11:10:13 -07:00
int i ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2007-06-28 10:47:08 -07:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ i ] . position = = position )
2007-06-28 10:47:08 -07:00
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Swapping positions between players %d(%d) and %d(%d) " ,
player , NetPlay . players [ player ] . position , i , NetPlay . players [ i ] . position ) ;
NetPlay . players [ i ] . position = NetPlay . players [ player ] . position ;
NetPlay . players [ player ] . position = position ;
2010-07-23 05:50:36 -07:00
NETBroadcastTwoPlayerInfo ( player , i ) ;
2010-01-04 23:13:16 -08:00
netPlayersUpdated = true ;
2009-06-07 11:10:13 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
}
debug ( LOG_ERROR , " Failed to swap positions for player %d, position %d " , ( int ) player , ( int ) position ) ;
2010-01-04 23:13:16 -08:00
if ( player < game . maxPlayers & & position < game . maxPlayers )
{
2012-10-01 10:54:27 -07:00
debug ( LOG_NET , " corrupted positions: player (%u) new position (%u) old position (%d) " , player , position , NetPlay . players [ player ] . position ) ;
2010-01-04 23:13:16 -08:00
// Positions were corrupted. Attempt to fix.
NetPlay . players [ player ] . position = position ;
NETBroadcastPlayerInfo ( player ) ;
netPlayersUpdated = true ;
return true ;
}
2009-06-07 11:10:13 -07:00
return false ;
}
2006-05-27 09:37:17 -07:00
2012-02-14 13:18:35 -08:00
bool changeColour ( unsigned player , int col , bool isHost )
2009-06-07 11:10:13 -07:00
{
2012-02-14 13:18:35 -08:00
if ( col < 0 | | col > = MAX_PLAYERS_IN_GUI )
{
return true ;
}
2007-06-28 10:47:08 -07:00
2012-02-14 13:18:35 -08:00
if ( getPlayerColour ( player ) = = col )
{
return true ; // Nothing to do.
}
for ( unsigned i = 0 ; i < MAX_PLAYERS ; + + i )
2009-06-07 11:10:13 -07:00
{
2009-11-26 10:33:03 -08:00
if ( getPlayerColour ( i ) = = col )
2007-06-28 10:47:08 -07:00
{
2012-02-14 13:18:35 -08:00
if ( ! isHost & & NetPlay . players [ i ] . allocated )
{
return true ; // May not swap.
}
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Swapping colours between players %d(%d) and %d(%d) " ,
player , getPlayerColour ( player ) , i , getPlayerColour ( i ) ) ;
setPlayerColour ( i , getPlayerColour ( player ) ) ;
2009-11-26 10:33:03 -08:00
NetPlay . players [ i ] . colour = getPlayerColour ( player ) ;
2009-06-07 11:10:13 -07:00
setPlayerColour ( player , col ) ;
2009-11-26 10:33:03 -08:00
NetPlay . players [ player ] . colour = col ;
2010-07-23 05:50:36 -07:00
NETBroadcastTwoPlayerInfo ( player , i ) ;
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
2009-06-07 11:10:13 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
}
2009-09-30 17:39:34 -07:00
debug ( LOG_ERROR , " Failed to swap colours for player %d, colour %d " , ( int ) player , ( int ) col ) ;
2010-01-04 23:13:16 -08:00
if ( player < game . maxPlayers & & col < MAX_PLAYERS )
{
// Colours were corrupted. Attempt to fix.
2012-10-01 10:54:27 -07:00
debug ( LOG_NET , " corrupted colours: player (%u) new colour (%u) old colour (%d) " , player , col , NetPlay . players [ player ] . colour ) ;
2010-01-04 23:13:16 -08:00
setPlayerColour ( player , col ) ;
NetPlay . players [ player ] . colour = col ;
NETBroadcastPlayerInfo ( player ) ;
netPlayersUpdated = true ;
return true ;
}
2009-06-07 11:10:13 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2011-03-12 17:32:15 -08:00
static bool SendColourRequest ( UBYTE player , UBYTE col )
2008-01-27 07:04:55 -08:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost ) // do or request the change
2008-01-27 07:04:55 -08:00
{
2012-02-14 13:18:35 -08:00
return changeColour ( player , col , true ) ;
2008-01-27 07:04:55 -08:00
}
else
{
2009-06-07 11:10:13 -07:00
// clients tell the host which color they want
2010-02-09 09:43:53 -08:00
NETbeginEncode ( NETnetQueue ( NET_HOST_ONLY ) , NET_COLOURREQUEST ) ;
2008-01-27 07:04:55 -08:00
NETuint8_t ( & player ) ;
NETuint8_t ( & col ) ;
2009-06-07 11:10:13 -07:00
NETend ( ) ;
}
return true ;
}
2011-03-12 17:32:15 -08:00
static bool SendPositionRequest ( UBYTE player , UBYTE position )
2009-06-07 11:10:13 -07:00
{
if ( NetPlay . isHost ) // do or request the change
{
return changePosition ( player , position ) ;
}
else
{
2009-11-26 10:33:03 -08:00
debug ( LOG_NET , " Requesting the host to change our position. From %d to %d " , player , position ) ;
2009-06-07 11:10:13 -07:00
// clients tell the host which position they want
2010-02-09 09:43:53 -08:00
NETbeginEncode ( NETnetQueue ( NET_HOST_ONLY ) , NET_POSITIONREQUEST ) ;
2009-06-07 11:10:13 -07:00
NETuint8_t ( & player ) ;
NETuint8_t ( & position ) ;
2008-01-27 07:04:55 -08:00
NETend ( ) ;
}
2008-03-24 09:51:17 -07:00
return true ;
2008-01-27 07:04:55 -08:00
}
2011-03-12 17:32:15 -08:00
bool recvColourRequest ( NETQUEUE queue )
2008-01-27 07:04:55 -08:00
{
2009-06-07 11:10:13 -07:00
UBYTE player , col ;
2008-01-27 07:04:55 -08:00
2010-11-25 03:58:28 -08:00
if ( ! NetPlay . isHost | | ! bHosted ) // Only host should act, and only if the game hasn't started yet.
2008-01-27 07:04:55 -08:00
{
2012-02-19 14:49:49 -08:00
ASSERT ( false , " Host only routine detected for client! " ) ;
2008-03-24 09:51:17 -07:00
return true ;
2008-01-27 07:04:55 -08:00
}
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_COLOURREQUEST ) ;
2008-01-27 07:04:55 -08:00
NETuint8_t ( & player ) ;
NETuint8_t ( & col ) ;
NETend ( ) ;
2013-10-21 12:41:55 -07:00
if ( player > = MAX_PLAYERS )
2009-06-07 11:10:13 -07:00
{
debug ( LOG_ERROR , " Invalid NET_COLOURREQUEST from player %d: Tried to change player %d to colour %d " ,
2010-02-09 09:43:53 -08:00
queue . index , ( int ) player , ( int ) col ) ;
2009-06-07 11:10:13 -07:00
return false ;
}
2012-02-19 14:49:49 -08:00
if ( whosResponsible ( player ) ! = queue . index )
{
HandleBadParam ( " NET_COLOURREQUEST given incorrect params. " , player , queue . index ) ;
return false ;
}
2009-06-07 11:10:13 -07:00
resetReadyStatus ( false ) ;
2012-02-14 13:18:35 -08:00
return changeColour ( player , col , false ) ;
2009-06-07 11:10:13 -07:00
}
2011-03-12 17:32:15 -08:00
bool recvPositionRequest ( NETQUEUE queue )
2009-06-07 11:10:13 -07:00
{
UBYTE player , position ;
2010-11-25 03:58:28 -08:00
if ( ! NetPlay . isHost | | ! bHosted ) // Only host should act, and only if the game hasn't started yet.
2009-06-07 11:10:13 -07:00
{
2012-02-19 14:49:49 -08:00
ASSERT ( false , " Host only routine detected for client! " ) ;
2009-06-07 11:10:13 -07:00
return true ;
}
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_POSITIONREQUEST ) ;
2009-06-07 11:10:13 -07:00
NETuint8_t ( & player ) ;
NETuint8_t ( & position ) ;
NETend ( ) ;
2009-11-26 10:33:03 -08:00
debug ( LOG_NET , " Host received position request from player %d to %d " , player , position ) ;
2012-02-19 14:49:49 -08:00
2013-10-21 12:41:55 -07:00
if ( player > = MAX_PLAYERS | | position > = MAX_PLAYERS )
2008-01-27 07:09:41 -08:00
{
2009-11-26 10:33:03 -08:00
debug ( LOG_ERROR , " Invalid NET_POSITIONREQUEST from player %d: Tried to change player %d to %d " ,
2010-02-09 09:43:53 -08:00
queue . index , ( int ) player , ( int ) position ) ;
2008-03-24 09:51:17 -07:00
return false ;
2008-01-27 07:09:41 -08:00
}
2012-02-19 14:49:49 -08:00
if ( whosResponsible ( player ) ! = queue . index )
{
HandleBadParam ( " NET_POSITIONREQUEST given incorrect params. " , player , queue . index ) ;
return false ;
}
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2009-06-07 11:10:13 -07:00
return changePosition ( player , position ) ;
2008-01-27 07:04:55 -08:00
}
2012-02-05 04:13:04 -08:00
// If so, return that team; if not, return -1; if there are no players, return team MAX_PLAYERS.
2012-01-21 05:11:53 -08:00
int allPlayersOnSameTeam ( int except )
{
2012-02-05 04:13:04 -08:00
int minTeam = MAX_PLAYERS , maxTeam = 0 ;
for ( int i = 0 ; i < game . maxPlayers ; + + i )
2012-01-21 05:11:53 -08:00
{
2012-02-05 04:13:04 -08:00
if ( i ! = except & & ( NetPlay . players [ i ] . allocated | | NetPlay . players [ i ] . ai > = 0 ) )
2012-01-21 05:11:53 -08:00
{
2012-02-05 04:13:04 -08:00
minTeam = std : : min ( minTeam , NetPlay . players [ i ] . team ) ;
maxTeam = std : : max ( maxTeam , NetPlay . players [ i ] . team ) ;
2012-01-21 05:11:53 -08:00
}
}
2012-02-05 04:13:04 -08:00
if ( minTeam = = MAX_PLAYERS | | minTeam = = maxTeam )
{
return minTeam ; // Players all on same team.
}
return - 1 ; // Players not all on same team.
2012-01-21 05:11:53 -08:00
}
2006-09-27 14:17:28 -07:00
/*
* Opens a menu for a player to choose a team
* ' player ' is a player id of the player who will get a new team assigned
*/
2006-09-26 11:14:05 -07:00
static void addTeamChooser ( UDWORD player )
{
UDWORD i ;
2012-01-21 05:11:53 -08:00
int disallow = allPlayersOnSameTeam ( player ) ;
2006-09-26 11:14:05 -07:00
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Opened team chooser for %d, current team: %d " , player , NetPlay . players [ player ] . team ) ;
2006-09-26 11:14:05 -07:00
2011-01-04 09:51:15 -08:00
initChooser ( player ) ;
2008-04-09 13:05:09 -07:00
2006-09-26 11:14:05 -07:00
// add form.
2012-02-17 20:28:38 -08:00
addBlueForm ( MULTIOP_PLAYERS , MULTIOP_TEAMCHOOSER_FORM , " " , 8 , playerBoxHeight ( player ) , MULTIOP_ROW_WIDTH , MULTIOP_TEAMSHEIGHT ) ;
2006-09-26 11:14:05 -07:00
2011-01-03 05:48:41 -08:00
int teamW = iV_GetImageWidth ( FrontImages , IMAGE_TEAM0 ) ;
int teamH = iV_GetImageHeight ( FrontImages , IMAGE_TEAM0 ) ;
2012-02-17 20:28:38 -08:00
int space = MULTIOP_ROW_WIDTH - 4 - teamW * ( game . maxPlayers + 1 ) ;
2011-01-03 05:48:41 -08:00
int spaceDiv = game . maxPlayers ;
space = std : : min ( space , 3 * spaceDiv ) ;
2008-10-18 11:27:32 -07:00
// add the teams, skipping the one we CAN'T be on (if applicable)
2008-10-13 20:40:48 -07:00
for ( i = 0 ; i < game . maxPlayers ; i + + )
2006-09-26 11:14:05 -07:00
{
2008-10-18 11:27:32 -07:00
if ( i ! = disallow )
{
2011-01-03 05:48:41 -08:00
addMultiBut ( psWScreen , MULTIOP_TEAMCHOOSER_FORM , MULTIOP_TEAMCHOOSER + i , i * ( teamW * spaceDiv + space ) / spaceDiv + 3 , 6 , teamW , teamH , _ ( " Team " ) , IMAGE_TEAM0 + i , IMAGE_TEAM0_HI + i , IMAGE_TEAM0_HI + i ) ;
2008-10-18 11:27:32 -07:00
}
// may want to add some kind of 'can't do' icon instead of being blank?
2006-09-26 11:14:05 -07:00
}
2011-01-04 09:51:15 -08:00
// add a kick button
if ( player ! = selectedPlayer & & NetPlay . bComms & & NetPlay . isHost & & NetPlay . players [ player ] . allocated )
{
2011-02-27 01:26:26 -08:00
const int imgwidth = iV_GetImageWidth ( FrontImages , IMAGE_NOJOIN ) ;
const int imgheight = iV_GetImageHeight ( FrontImages , IMAGE_NOJOIN ) ;
addMultiBut ( psWScreen , MULTIOP_TEAMCHOOSER_FORM , MULTIOP_TEAMCHOOSER_KICK , MULTIOP_ROW_WIDTH - imgwidth - 4 , 8 , imgwidth , imgheight ,
( " Kick player " ) , IMAGE_NOJOIN , IMAGE_NOJOIN , IMAGE_NOJOIN ) ;
2011-01-04 09:51:15 -08:00
}
2009-06-07 11:10:13 -07:00
teamChooserUp = player ;
2006-09-26 11:14:05 -07:00
}
2006-09-27 14:17:28 -07:00
/*
* Closes Team Chooser dialog box , if there was any open
*/
2006-09-26 11:14:05 -07:00
static void closeTeamChooser ( void )
{
2009-06-07 11:10:13 -07:00
teamChooserUp = - 1 ;
2006-09-26 11:14:05 -07:00
widgDelete ( psWScreen , MULTIOP_TEAMCHOOSER_FORM ) ; //only once!
}
2008-05-03 10:43:55 -07:00
static void drawReadyButton ( UDWORD player )
{
2012-01-21 05:11:53 -08:00
int disallow = allPlayersOnSameTeam ( - 1 ) ;
2008-05-03 10:43:55 -07:00
// delete 'ready' botton form
widgDelete ( psWScreen , MULTIOP_READY_FORM_ID + player ) ;
// add form to hold 'ready' botton
addBlueForm ( MULTIOP_PLAYERS , MULTIOP_READY_FORM_ID + player , " " ,
2012-02-17 20:28:38 -08:00
7 + MULTIOP_PLAYERWIDTH - MULTIOP_READY_WIDTH ,
2011-01-03 05:48:41 -08:00
playerBoxHeight ( player ) ,
2008-05-03 10:43:55 -07:00
MULTIOP_READY_WIDTH , MULTIOP_READY_HEIGHT ) ;
2009-12-20 14:44:40 -08:00
2013-03-02 00:51:32 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , MULTIOP_READY_FORM_ID + player ) ;
2011-01-09 07:35:49 -08:00
if ( ! NetPlay . players [ player ] . allocated & & NetPlay . players [ player ] . ai > = 0 )
{
int icon = difficultyIcon ( NetPlay . players [ player ] . difficulty ) ;
addMultiBut ( psWScreen , MULTIOP_READY_FORM_ID + player , MULTIOP_DIFFICULTY_INIT_START + player , 6 , 4 , MULTIOP_READY_WIDTH , MULTIOP_READY_HEIGHT ,
2013-01-05 08:02:08 -08:00
locked . difficulty ? _ ( " Difficulty locked " ) : ( NetPlay . isHost ? _ ( " Click to change difficulty " ) : NULL ) , icon , icon , icon ) ;
2011-01-09 07:35:49 -08:00
return ;
}
else if ( ! NetPlay . players [ player ] . allocated )
{
return ; // closed or open
}
2012-01-21 05:11:53 -08:00
if ( disallow ! = - 1 )
{
return ;
}
2012-02-05 03:32:46 -08:00
bool isMe = player = = selectedPlayer ;
bool isReady = NetPlay . players [ player ] . ready ;
char const * const toolTips [ 2 ] [ 2 ] = { { _ ( " Waiting for player " ) , _ ( " Player is ready " ) } , { _ ( " Click when ready " ) , _ ( " Waiting for other players " ) } } ;
unsigned images [ 2 ] [ 2 ] = { { IMAGE_CHECK_OFF , IMAGE_CHECK_ON } , { IMAGE_CHECK_OFF_HI , IMAGE_CHECK_ON_HI } } ;
2009-12-20 14:44:40 -08:00
2012-02-05 03:32:46 -08:00
// draw 'ready' button
2012-02-17 20:28:38 -08:00
addMultiBut ( psWScreen , MULTIOP_READY_FORM_ID + player , MULTIOP_READY_START + player , 3 , 10 , MULTIOP_READY_WIDTH , MULTIOP_READY_HEIGHT ,
2012-02-05 03:32:46 -08:00
toolTips [ isMe ] [ isReady ] , images [ 0 ] [ isReady ] , images [ 0 ] [ isReady ] , images [ isMe ] [ isReady ] ) ;
2013-03-02 00:51:32 -08:00
W_LABEL * label = new W_LABEL ( parent ) ;
label - > id = MULTIOP_READY_START + MAX_PLAYERS + player ;
label - > setGeometry ( 0 , 0 , MULTIOP_READY_WIDTH , 17 ) ;
label - > setTextAlignment ( WLAB_ALIGNBOTTOM ) ;
label - > setFont ( font_small , WZCOL_TEXT_BRIGHT ) ;
label - > setString ( _ ( " READY? " ) ) ;
2009-06-07 11:10:13 -07:00
}
static bool canChooseTeamFor ( int i )
{
2010-01-10 02:52:23 -08:00
return ( i = = selectedPlayer | | NetPlay . isHost ) ;
2008-05-03 10:43:55 -07:00
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
// box for players.
2011-03-12 17:32:15 -08:00
void addPlayerBox ( bool players )
2007-06-28 10:47:08 -07:00
{
// if background isn't there, then return since were not ready to draw the box yet!
if ( widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) = = NULL )
{
2011-01-04 09:51:15 -08:00
return ;
2007-06-28 10:47:08 -07:00
}
widgDelete ( psWScreen , MULTIOP_PLAYERS ) ; // del player window
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ; // del text too,
2011-01-09 07:35:49 -08:00
if ( aiChooserUp > = 0 )
{
addAiChooser ( aiChooserUp ) ;
return ;
}
else if ( difficultyChooserUp > = 0 )
{
addDifficultyChooser ( difficultyChooserUp ) ;
return ;
}
2013-02-27 23:29:08 -08:00
// draw player window
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
IntFormAnimated * playersForm = new IntFormAnimated ( parent , false ) ;
playersForm - > id = MULTIOP_PLAYERS ;
playersForm - > setGeometry ( MULTIOP_PLAYERSX , MULTIOP_PLAYERSY , MULTIOP_PLAYERSW , MULTIOP_PLAYERSH ) ;
2007-06-28 10:47:08 -07:00
2007-04-01 13:15:46 -07:00
addSideText ( FRONTEND_SIDETEXT2 , MULTIOP_PLAYERSX - 3 , MULTIOP_PLAYERSY , _ ( " PLAYERS " ) ) ;
2007-06-28 10:47:08 -07:00
if ( players )
{
2011-01-10 15:18:18 -08:00
int team = - 1 ;
2010-01-23 20:48:56 -08:00
bool allOnSameTeam = true ;
2009-11-29 11:41:17 -08:00
2011-01-04 09:51:15 -08:00
for ( int i = 0 ; i < game . maxPlayers ; i + + )
2010-01-23 20:48:56 -08:00
{
if ( game . skDiff [ i ] | | isHumanPlayer ( i ) )
{
2013-04-29 12:20:34 -07:00
int myTeam = alliancesSetTeamsBeforeGame ( game . alliance ) ? NetPlay . players [ i ] . team : i ;
2010-01-23 20:48:56 -08:00
if ( team = = - 1 )
{
2011-01-10 15:18:18 -08:00
team = myTeam ;
2010-01-23 20:48:56 -08:00
}
2011-01-10 15:18:18 -08:00
else if ( myTeam ! = team )
2010-01-23 20:48:56 -08:00
{
allOnSameTeam = false ;
2011-01-10 15:18:18 -08:00
break ; // We just need to know if we have enough to start a game
2010-01-23 20:48:56 -08:00
}
}
}
2011-01-04 09:51:15 -08:00
for ( int i = 0 ; i < game . maxPlayers ; i + + )
2006-05-27 09:37:17 -07:00
{
2011-01-13 07:58:28 -08:00
if ( positionChooserUp > = 0 & & positionChooserUp ! = i & & ( NetPlay . isHost | | ! isHumanPlayer ( i ) ) )
2011-01-04 09:51:15 -08:00
{
W_BUTINIT sButInit ;
sButInit . formID = MULTIOP_PLAYERS ;
sButInit . id = MULTIOP_PLAYER_START + i ;
sButInit . x = 7 ;
2011-01-03 05:48:41 -08:00
sButInit . y = playerBoxHeight ( i ) ;
2011-01-04 09:51:15 -08:00
sButInit . width = MULTIOP_PLAYERWIDTH + 1 ;
sButInit . height = MULTIOP_PLAYERHEIGHT ;
sButInit . pTip = _ ( " Click to change to this slot " ) ;
sButInit . pDisplay = displayPosition ;
sButInit . UserData = i ;
widgAddButton ( psWScreen , & sButInit ) ;
continue ;
}
else if ( i = = colourChooserUp )
{
addColourChooser ( i ) ;
continue ;
}
else if ( i = = teamChooserUp )
{
addTeamChooser ( i ) ;
continue ;
}
else if ( ingame . localOptionsReceived )
2006-09-26 11:14:05 -07:00
{
//add team chooser
2010-12-22 06:02:14 -08:00
W_BUTINIT sButInit ;
2006-09-26 11:14:05 -07:00
sButInit . formID = MULTIOP_PLAYERS ;
sButInit . id = MULTIOP_TEAMS_START + i ;
2009-11-28 23:24:22 -08:00
sButInit . x = 7 ;
2011-01-03 05:48:41 -08:00
sButInit . y = playerBoxHeight ( i ) ;
2006-09-26 11:14:05 -07:00
sButInit . width = MULTIOP_TEAMSWIDTH ;
sButInit . height = MULTIOP_TEAMSHEIGHT ;
2013-01-05 08:02:08 -08:00
if ( canChooseTeamFor ( i ) & & ! locked . teams )
2009-06-07 11:10:13 -07:00
{
2010-08-25 07:37:44 -07:00
sButInit . pTip = _ ( " Choose Team " ) ;
2009-06-07 11:10:13 -07:00
}
2013-01-05 08:02:08 -08:00
else if ( locked . teams )
{
sButInit . pTip = _ ( " Teams locked " ) ;
}
2009-06-07 11:10:13 -07:00
sButInit . pDisplay = displayTeamChooser ;
2007-11-09 13:01:23 -08:00
sButInit . UserData = i ;
2006-09-26 11:14:05 -07:00
2010-01-04 23:13:16 -08:00
if ( teamChooserUp = = i & & colourChooserUp < 0 )
2006-09-26 11:14:05 -07:00
{
addTeamChooser ( i ) ;
}
2013-04-29 12:20:34 -07:00
else if ( alliancesSetTeamsBeforeGame ( game . alliance ) )
2006-09-26 11:14:05 -07:00
{
2009-11-28 23:24:22 -08:00
// only if not disabled and in locked teams mode
2006-09-26 11:14:05 -07:00
widgAddButton ( psWScreen , & sButInit ) ;
}
}
2011-01-04 09:51:15 -08:00
// draw player colour
W_BUTINIT sColInit ;
sColInit . formID = MULTIOP_PLAYERS ;
sColInit . id = MULTIOP_COLOUR_START + i ;
sColInit . x = 7 + MULTIOP_TEAMSWIDTH ;
2011-01-03 05:48:41 -08:00
sColInit . y = playerBoxHeight ( i ) ;
2011-01-04 09:51:15 -08:00
sColInit . width = MULTIOP_COLOUR_WIDTH ;
sColInit . height = MULTIOP_PLAYERHEIGHT ;
2011-01-18 05:34:23 -08:00
if ( selectedPlayer = = i | | NetPlay . isHost )
2007-06-28 10:47:08 -07:00
{
2011-01-04 09:51:15 -08:00
sColInit . pTip = _ ( " Click to change player colour " ) ;
}
sColInit . pDisplay = displayColour ;
sColInit . UserData = i ;
widgAddButton ( psWScreen , & sColInit ) ;
2011-01-09 07:35:49 -08:00
if ( ingame . localOptionsReceived )
2007-06-28 10:47:08 -07:00
{
2011-01-10 10:40:29 -08:00
if ( ! allOnSameTeam )
2009-11-29 11:41:17 -08:00
{
drawReadyButton ( i ) ;
}
2008-05-03 10:43:55 -07:00
2009-06-07 11:10:13 -07:00
// draw player info box
2010-12-22 06:02:14 -08:00
W_BUTINIT sButInit ;
2007-06-28 10:47:08 -07:00
sButInit . formID = MULTIOP_PLAYERS ;
sButInit . id = MULTIOP_PLAYER_START + i ;
2011-01-04 09:51:15 -08:00
sButInit . x = 7 + MULTIOP_TEAMSWIDTH + MULTIOP_COLOUR_WIDTH ;
2011-01-03 05:48:41 -08:00
sButInit . y = playerBoxHeight ( i ) ;
2011-01-04 09:51:15 -08:00
sButInit . width = MULTIOP_PLAYERWIDTH - MULTIOP_TEAMSWIDTH - MULTIOP_READY_WIDTH - MULTIOP_COLOUR_WIDTH ;
2007-06-28 10:47:08 -07:00
sButInit . height = MULTIOP_PLAYERHEIGHT ;
2013-01-05 08:02:08 -08:00
if ( ( selectedPlayer = = i | | NetPlay . isHost ) & & NetPlay . players [ i ] . allocated & & ! locked . position )
2009-06-07 11:10:13 -07:00
{
2011-01-04 09:51:15 -08:00
sButInit . pTip = _ ( " Click to change player position " ) ;
2009-06-07 11:10:13 -07:00
}
2013-01-05 08:02:08 -08:00
else if ( ! NetPlay . players [ i ] . allocated & & NetPlay . isHost & & ! locked . ai )
2009-06-07 11:10:13 -07:00
{
2012-01-14 06:59:20 -08:00
sButInit . pTip = _ ( " Click to change AI " ) ;
2009-06-07 11:10:13 -07:00
}
2013-06-03 12:11:06 -07:00
if ( NetPlay . players [ i ] . allocated & & ! getMultiStats ( i ) . identity . empty ( ) )
{
if ( ! sButInit . pTip . isEmpty ( ) )
{
sButInit . pTip + = " \n " ;
}
EcKey : : Key bytes = getMultiStats ( i ) . identity . toBytes ( EcKey : : Public ) ;
sButInit . pTip + = _ ( " Player ID: " ) ;
2013-06-16 03:28:16 -07:00
if ( ! bytes . empty ( ) )
{
sButInit . pTip + = sha256Sum ( & bytes [ 0 ] , bytes . size ( ) ) . toString ( ) . substr ( 0 , 20 ) . c_str ( ) ;
}
else
{
sButInit . pTip + = _ ( " (none) " ) ;
}
2013-06-03 12:11:06 -07:00
}
2009-06-07 11:10:13 -07:00
sButInit . pDisplay = displayPlayer ;
2007-11-09 13:01:23 -08:00
sButInit . UserData = i ;
2011-01-04 09:51:15 -08:00
widgAddButton ( psWScreen , & sButInit ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
2006-09-27 14:17:28 -07:00
/*
* Notify all players of host launching the game
*/
2006-09-13 03:54:35 -07:00
static void SendFireUp ( void )
2007-06-28 10:47:08 -07:00
{
2012-03-31 06:19:22 -07:00
uint32_t randomSeed = rand ( ) ; // Pick a random random seed for the synchronised random number generator.
2010-02-09 09:43:53 -08:00
NETbeginEncode ( NETbroadcastQueue ( ) , NET_FIREUP ) ;
2012-03-31 06:19:22 -07:00
NETuint32_t ( & randomSeed ) ;
2008-01-27 06:25:30 -08:00
NETend ( ) ;
2012-12-09 13:37:55 -08:00
printSearchPath ( ) ;
2012-03-31 06:19:22 -07:00
gameSRand ( randomSeed ) ; // Set the seed for the synchronised random number generator. The clients will use the same seed.
2007-06-28 10:47:08 -07:00
}
2009-04-10 21:41:14 -07:00
// host kicks a player from a game.
2009-04-19 11:45:28 -07:00
void kickPlayer ( uint32_t player_id , const char * reason , LOBBY_ERROR_TYPES type )
2007-06-28 10:47:08 -07:00
{
// send a kick msg
2010-02-09 09:43:53 -08:00
NETbeginEncode ( NETbroadcastQueue ( ) , NET_KICK ) ;
2008-01-09 15:30:42 -08:00
NETuint32_t ( & player_id ) ;
2009-04-10 21:41:14 -07:00
NETstring ( ( char * ) reason , MAX_KICK_REASON ) ;
2009-04-19 11:45:28 -07:00
NETenum ( & type ) ;
2008-01-09 15:30:42 -08:00
NETend ( ) ;
2011-01-04 09:51:15 -08:00
NETflush ( ) ;
2013-10-31 19:29:41 -07:00
wzDelay ( 300 ) ;
2010-01-09 05:39:09 -08:00
debug ( LOG_NET , " Kicking player %u (%s). " ,
( unsigned int ) player_id , getPlayerName ( player_id ) ) ;
NETplayerKicked ( player_id ) ;
2007-06-28 10:47:08 -07:00
}
2006-09-13 02:09:05 -07:00
static void addChatBox ( void )
2007-06-28 10:47:08 -07:00
{
if ( widgGetFromID ( psWScreen , FRONTEND_TOPFORM ) )
{
widgDelete ( psWScreen , FRONTEND_TOPFORM ) ;
}
if ( widgGetFromID ( psWScreen , MULTIOP_CHATBOX ) )
{
return ;
}
2013-02-27 23:29:08 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
2007-06-28 10:47:08 -07:00
2013-02-27 23:29:08 -08:00
IntFormAnimated * chatBox = new IntFormAnimated ( parent ) ;
chatBox - > id = MULTIOP_CHATBOX ;
chatBox - > setGeometry ( MULTIOP_CHATBOXX , MULTIOP_CHATBOXY , MULTIOP_CHATBOXW , MULTIOP_CHATBOXH ) ;
2007-06-28 10:47:08 -07:00
2007-04-01 13:15:46 -07:00
addSideText ( FRONTEND_SIDETEXT4 , MULTIOP_CHATBOXX - 3 , MULTIOP_CHATBOXY , _ ( " CHAT " ) ) ;
2007-06-28 10:47:08 -07:00
flushConsoleMessages ( ) ; // add the chatbox.
initConsoleMessages ( ) ;
2008-03-24 09:51:17 -07:00
enableConsoleDisplay ( true ) ;
setConsoleBackdropStatus ( false ) ;
2010-07-14 09:32:53 -07:00
setConsoleSizePos ( MULTIOP_CHATBOXX + 4 + D_W , MULTIOP_CHATBOXY + 14 + D_H , MULTIOP_CHATBOXW - 4 ) ;
2008-03-24 09:51:17 -07:00
setConsolePermanence ( true , true ) ;
2007-06-28 10:47:08 -07:00
setConsoleLineInfo ( 5 ) ; // use x lines on chat window
2010-12-22 06:02:14 -08:00
W_EDBINIT sEdInit ; // add the edit box
2007-06-28 10:47:08 -07:00
sEdInit . formID = MULTIOP_CHATBOX ;
2006-05-27 09:37:17 -07:00
sEdInit . id = MULTIOP_CHATEDIT ;
2007-06-28 10:47:08 -07:00
sEdInit . x = MULTIOP_CHATEDITX ;
sEdInit . y = MULTIOP_CHATEDITY ;
sEdInit . width = MULTIOP_CHATEDITW ;
sEdInit . height = MULTIOP_CHATEDITH ;
sEdInit . pUserData = NULL ;
sEdInit . pBoxDisplay = displayChatEdit ;
2006-05-27 09:37:17 -07:00
widgAddEditBox ( psWScreen , & sEdInit ) ;
2007-06-28 10:47:08 -07:00
2010-01-17 12:12:03 -08:00
if ( * getModList ( ) )
{
2013-02-24 01:06:51 -08:00
std : : string modListMessage = _ ( " Mod: " ) ;
modListMessage + = getModList ( ) ;
addConsoleMessage ( modListMessage . c_str ( ) , DEFAULT_JUSTIFY , SYSTEM_MESSAGE ) ;
2010-01-17 12:12:03 -08:00
if ( NetPlay . bComms )
{
addConsoleMessage ( _ ( " All players need to have the same mods to join your game. " ) , DEFAULT_JUSTIFY , SYSTEM_MESSAGE ) ;
}
}
2007-06-28 10:47:08 -07:00
return ;
}
2012-01-10 18:24:32 -08:00
static void addConsoleBox ( void )
{
if ( widgGetFromID ( psWScreen , FRONTEND_TOPFORM ) )
{
widgDelete ( psWScreen , FRONTEND_TOPFORM ) ;
}
if ( widgGetFromID ( psWScreen , MULTIOP_CONSOLEBOX ) )
{
return ;
}
2013-02-27 23:29:08 -08:00
WIDGET * parent = widgGetFromID ( psWScreen , FRONTEND_BACKDROP ) ;
2012-01-10 18:24:32 -08:00
2013-02-27 23:29:08 -08:00
IntFormAnimated * consoleBox = new IntFormAnimated ( parent ) ;
consoleBox - > id = MULTIOP_CONSOLEBOX ;
consoleBox - > setGeometry ( MULTIOP_CONSOLEBOXX , MULTIOP_CONSOLEBOXY , MULTIOP_CONSOLEBOXW , MULTIOP_CONSOLEBOXH ) ;
2012-01-10 18:24:32 -08:00
flushConsoleMessages ( ) ; // add the chatbox.
initConsoleMessages ( ) ;
enableConsoleDisplay ( true ) ;
setConsoleBackdropStatus ( false ) ;
setConsoleSizePos ( MULTIOP_CONSOLEBOXX + 4 + D_W , MULTIOP_CONSOLEBOXY + 14 + D_H , MULTIOP_CONSOLEBOXW - 4 ) ;
setConsolePermanence ( true , true ) ;
2012-01-26 19:09:09 -08:00
setConsoleLineInfo ( 3 ) ; // use x lines on chat window
2012-01-10 18:24:32 -08:00
addConsoleMessage ( _ ( " Connecting to the lobby server... " ) , DEFAULT_JUSTIFY , SYSTEM_MESSAGE ) ;
displayConsoleMessages ( ) ;
return ;
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
static void disableMultiButs ( void )
2006-05-27 09:37:17 -07:00
{
2007-06-28 10:47:08 -07:00
// edit box icons.
2009-04-19 11:45:28 -07:00
widgSetButtonState ( psWScreen , MULTIOP_GNAME_ICON , WBUT_DISABLE ) ;
widgSetButtonState ( psWScreen , MULTIOP_MAP_ICON , WBUT_DISABLE ) ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
// edit boxes
widgSetButtonState ( psWScreen , MULTIOP_GNAME , WEDBS_DISABLE ) ;
2009-06-07 11:10:13 -07:00
if ( ! NetPlay . isHost )
2007-06-28 10:47:08 -07:00
{
2013-03-14 09:57:43 -07:00
( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_GAMETYPE ) ) - > disable ( ) ; // Scavengers.
( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_BASETYPE ) ) - > disable ( ) ; // camapign subtype.
2013-03-14 03:01:51 -07:00
( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_POWER ) ) - > disable ( ) ; // pow levels
2013-03-14 09:57:43 -07:00
( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_ALLIANCES ) ) - > disable ( ) ;
2007-06-28 10:47:08 -07:00
}
}
////////////////////////////////////////////////////////////////////////////
2006-09-20 08:18:37 -07:00
static void stopJoining ( void )
2007-06-28 10:47:08 -07:00
{
2006-05-27 09:37:17 -07:00
dwSelectedGame = 0 ;
2010-01-10 04:14:59 -08:00
reloadMPConfig ( ) ; // reload own settings
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " player %u (Host is %s) stopping. " , selectedPlayer , NetPlay . isHost ? " true " : " false " ) ;
2007-06-28 10:47:08 -07:00
if ( bHosted ) // cancel a hosted game.
{
2009-11-28 12:40:53 -08:00
// annouce we are leaving...
debug ( LOG_NET , " Host is quitting game... " ) ;
2010-02-09 09:43:53 -08:00
NETbeginEncode ( NETbroadcastQueue ( ) , NET_HOST_DROPPED ) ;
2009-11-28 12:40:53 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
sendLeavingMsg ( ) ; // say goodbye
NETclose ( ) ; // quit running game.
2008-03-24 09:51:17 -07:00
bHosted = false ; // stop host mode.
2007-06-28 10:47:08 -07:00
widgDelete ( psWScreen , FRONTEND_BACKDROP ) ; // refresh options screen.
2011-01-15 04:29:23 -08:00
startMultiOptions ( false ) ;
2008-03-24 09:51:17 -07:00
ingame . localJoiningInProgress = false ;
2007-06-28 10:47:08 -07:00
return ;
}
else if ( ingame . localJoiningInProgress ) // cancel a joined game.
{
2009-11-28 12:40:53 -08:00
debug ( LOG_NET , " Canceling game... " ) ;
2007-06-28 10:47:08 -07:00
sendLeavingMsg ( ) ; // say goodbye
NETclose ( ) ; // quit running game.
2006-05-27 09:37:17 -07:00
2010-02-20 21:32:36 -08:00
// if we were in a midle of transfering a file, then close the file handle
if ( NetPlay . pMapFileHandle )
{
debug ( LOG_NET , " closing aborted file " ) ; // no need to delete it, we do size check on (map) file
PHYSFS_close ( NetPlay . pMapFileHandle ) ;
NetPlay . pMapFileHandle = NULL ;
}
2008-03-24 09:51:17 -07:00
ingame . localJoiningInProgress = false ; // reset local flags
ingame . localOptionsReceived = false ;
2009-06-07 11:10:13 -07:00
if ( ! ingame . bHostSetup & & NetPlay . isHost ) // joining and host was transfered.
2006-05-27 09:37:17 -07:00
{
2009-06-07 11:10:13 -07:00
NetPlay . isHost = false ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2012-01-30 19:04:37 -08:00
changeTitleMode ( MULTI ) ;
2010-09-01 12:05:22 -07:00
selectedPlayer = 0 ;
realSelectedPlayer = 0 ;
2007-06-28 10:47:08 -07:00
return ;
}
2009-11-28 12:40:53 -08:00
debug ( LOG_NET , " We have stopped joining. " ) ;
2010-06-20 17:39:03 -07:00
changeTitleMode ( lastTitleMode ) ;
2007-09-10 06:48:44 -07:00
selectedPlayer = 0 ;
2010-09-01 12:05:22 -07:00
realSelectedPlayer = 0 ;
2007-06-28 10:47:08 -07:00
2007-04-17 11:24:31 -07:00
if ( ingame . bHostSetup )
{
2006-12-31 10:19:19 -08:00
pie_LoadBackDrop ( SCREEN_RANDOMBDROP ) ;
2007-06-28 10:47:08 -07:00
}
}
2013-01-05 08:02:08 -08:00
static void loadMapSettings1 ( )
{
char aFileName [ 256 ] ;
const char * ininame = challengeActive ? sRequestResult : aFileName ;
LEVEL_DATASET * psLevel = levFindDataSet ( game . map , & game . hash ) ;
ASSERT_OR_RETURN ( , psLevel , " No level found for %s " , game . map ) ;
sstrcpy ( aFileName , psLevel - > apDataFiles [ psLevel - > game ] ) ;
aFileName [ strlen ( aFileName ) - 4 ] = ' \0 ' ;
sstrcat ( aFileName , " .ini " ) ;
2013-01-06 15:40:24 -08:00
WzConfig ini ( ininame , WzConfig : : ReadOnly ) ;
2013-01-05 08:02:08 -08:00
if ( ! PHYSFS_exists ( ininame ) )
{
return ;
}
ini . beginGroup ( " locked " ) ; // GUI lockdown
locked . power = ini . value ( " power " , challengeActive ) . toBool ( ) ;
locked . alliances = ini . value ( " alliances " , challengeActive ) . toBool ( ) ;
locked . teams = ini . value ( " teams " , challengeActive ) . toBool ( ) ;
locked . difficulty = ini . value ( " difficulty " , challengeActive ) . toBool ( ) ;
locked . ai = ini . value ( " ai " , challengeActive ) . toBool ( ) ;
locked . scavengers = ini . value ( " scavengers " , challengeActive ) . toBool ( ) ;
locked . position = ini . value ( " position " , challengeActive ) . toBool ( ) ;
locked . bases = ini . value ( " bases " , challengeActive ) . toBool ( ) ;
ini . endGroup ( ) ;
ini . beginGroup ( " defaults " ) ;
game . scavengers = ini . value ( " scavengers " , game . scavengers ) . toBool ( ) ;
game . base = ini . value ( " bases " , game . base ) . toInt ( ) ;
game . alliance = ini . value ( " alliances " , game . alliance ) . toInt ( ) ;
2013-05-05 04:34:59 -07:00
if ( ini . contains ( " powerLevel " ) )
2013-01-05 08:02:08 -08:00
{
2013-05-05 04:34:59 -07:00
game . power = ini . value ( " powerLevel " , game . power ) . toInt ( ) ;
2013-01-05 08:02:08 -08:00
}
ini . endGroup ( ) ;
}
static void loadMapSettings2 ( )
{
char aFileName [ 256 ] ;
const char * ininame = challengeActive ? sRequestResult : aFileName ;
LEVEL_DATASET * psLevel = levFindDataSet ( game . map , & game . hash ) ;
ASSERT_OR_RETURN ( , psLevel , " No level found for %s " , game . map ) ;
sstrcpy ( aFileName , psLevel - > apDataFiles [ psLevel - > game ] ) ;
aFileName [ strlen ( aFileName ) - 4 ] = ' \0 ' ;
sstrcat ( aFileName , " .ini " ) ;
2013-01-06 15:40:24 -08:00
WzConfig ini ( ininame , WzConfig : : ReadOnly ) ;
2013-01-05 08:02:08 -08:00
if ( ! PHYSFS_exists ( ininame ) )
{
return ;
}
int offbyone = 0 ; // for compatibility with 3.1 and earlier challenges
ini . beginGroup ( " challenge " ) ; // backwards compatibility mode
if ( challengeActive & & ini . value ( " version " , 1 ) . toInt ( ) < = 1 )
{
offbyone = 1 ; // old version, counts from 1
}
ini . endGroup ( ) ;
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
ini . beginGroup ( " player_ " + QString : : number ( i + offbyone ) ) ;
if ( ini . contains ( " team " ) )
{
NetPlay . players [ i ] . team = ini . value ( " team " ) . toInt ( ) - offbyone ;
}
else if ( challengeActive ) // team is a required key for challenges
{
NetPlay . players [ i ] . ai = AI_CLOSED ;
}
if ( ini . contains ( " name " ) )
{
sstrcpy ( nameOverrides [ i ] , ini . value ( " name " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
}
if ( ini . contains ( " position " ) )
{
changePosition ( i , ini . value ( " position " , NetPlay . players [ i ] . position ) . toInt ( ) ) ;
}
if ( ini . contains ( " difficulty " ) )
{
QString value = ini . value ( " difficulty " , " Medium " ) . toString ( ) ;
for ( int j = 0 ; j < ARRAY_SIZE ( difficultyList ) ; j + + )
{
if ( strcasecmp ( difficultyList [ j ] , value . toUtf8 ( ) . constData ( ) ) = = 0 )
{
game . skDiff [ i ] = difficultyValue [ j ] ;
NetPlay . players [ i ] . difficulty = j ;
}
}
}
ini . endGroup ( ) ;
}
}
2006-09-27 14:17:28 -07:00
/*
* Process click events on the multiplayer / skirmish options screen
* ' id ' is id of the button that was pressed
*/
2007-06-28 10:47:08 -07:00
static void processMultiopWidgets ( UDWORD id )
{
PLAYERSTATS playerStats ;
// host, who is setting up the game
2006-05-27 09:37:17 -07:00
if ( ( ingame . bHostSetup & & ! bHosted ) )
2007-06-28 10:47:08 -07:00
{
switch ( id ) // Options buttons
{
case MULTIOP_GNAME : // we get this when nec.
2008-07-20 15:46:55 -07:00
sstrcpy ( game . name , widgGetString ( psWScreen , MULTIOP_GNAME ) ) ;
2007-06-28 10:47:08 -07:00
break ;
2006-05-27 09:37:17 -07:00
2013-05-26 00:34:57 -07:00
case MULTIOP_GNAME_ICON :
2007-06-28 10:47:08 -07:00
break ;
2013-05-26 00:34:57 -07:00
case MULTIOP_MAP :
widgDelete ( psWScreen , MULTIOP_PLAYERS ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ; // del text too,
debug ( LOG_WZ , " processMultiopWidgets[MULTIOP_MAP_ICON]: %s.wrf " , MultiCustomMapsPath ) ;
addMultiRequest ( MultiCustomMapsPath , " .wrf " , MULTIOP_MAP , current_tech , 0 , widgGetString ( psWScreen , MULTIOP_MAP ) ) ;
2013-11-20 19:09:40 -08:00
widgSetString ( psWScreen , MULTIOP_MAP + 1 , game . map ) ; //What a horrible hack! FIX ME! (See addBlueForm())
widgReveal ( psWScreen , MULTIOP_MAP_MOD ) ;
2007-06-28 10:47:08 -07:00
break ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
case MULTIOP_MAP_ICON :
widgDelete ( psWScreen , MULTIOP_PLAYERS ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ; // del text too,
2007-06-26 06:43:35 -07:00
debug ( LOG_WZ , " processMultiopWidgets[MULTIOP_MAP_ICON]: %s.wrf " , MultiCustomMapsPath ) ;
2009-05-12 13:37:22 -07:00
addMultiRequest ( MultiCustomMapsPath , " .wrf " , MULTIOP_MAP , current_tech , current_numplayers ) ;
2007-06-28 10:47:08 -07:00
break ;
2006-05-27 09:37:17 -07:00
2013-03-14 09:57:43 -07:00
case MULTIOP_MAP_PREVIEW :
2009-05-01 00:14:31 -07:00
loadMapPreview ( true ) ;
2008-04-07 12:07:43 -07:00
break ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
}
2007-06-28 10:47:08 -07:00
// host who is setting up or has hosted
2009-06-07 11:10:13 -07:00
if ( ingame . bHostSetup ) // || NetPlay.isHost) // FIXME Was: if(ingame.bHostSetup);{} ??? Note the ; !
2006-05-27 09:37:17 -07:00
{
2007-06-28 10:47:08 -07:00
switch ( id )
{
2013-03-14 09:57:43 -07:00
case MULTIOP_GAMETYPE :
game . scavengers = ( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_GAMETYPE ) ) - > currentValue ( ) ;
2009-06-09 11:00:18 -07:00
resetReadyStatus ( false ) ;
if ( bHosted )
{
sendOptions ( ) ;
}
break ;
2013-03-14 09:57:43 -07:00
case MULTIOP_BASETYPE :
game . base = ( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_BASETYPE ) ) - > currentValue ( ) ;
2011-01-04 09:51:15 -08:00
addGameOptions ( ) ;
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2007-06-28 10:47:08 -07:00
if ( bHosted )
{
2009-06-07 11:10:13 -07:00
sendOptions ( ) ;
2007-06-28 10:47:08 -07:00
disableMultiButs ( ) ;
}
break ;
2006-05-27 09:37:17 -07:00
2013-03-14 09:57:43 -07:00
case MULTIOP_ALLIANCES :
game . alliance = ( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_ALLIANCES ) ) - > currentValue ( ) ;
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
2008-04-10 12:19:04 -07:00
2006-09-21 13:42:48 -07:00
if ( bHosted )
{
2009-06-07 11:10:13 -07:00
sendOptions ( ) ;
2006-09-21 13:42:48 -07:00
}
break ;
2013-03-14 03:01:51 -07:00
case MULTIOP_POWER : // set power level
game . power = ( ( MultichoiceWidget * ) widgGetFromID ( psWScreen , MULTIOP_POWER ) ) - > currentValue ( ) ;
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2007-06-28 10:47:08 -07:00
if ( bHosted )
{
2009-06-07 11:10:13 -07:00
sendOptions ( ) ;
2007-06-28 10:47:08 -07:00
}
break ;
2012-09-03 01:25:05 -07:00
case MULTIOP_PASSWORD_EDIT :
{
unsigned result = widgGetButtonState ( psWScreen , MULTIOP_PASSWORD_BUT ) ;
if ( result ! = 0 )
{
break ;
}
}
// Continue, do not break, since we just set a password.
case MULTIOP_PASSWORD_BUT :
{
char buf [ 255 ] ;
bool willSet = widgGetButtonState ( psWScreen , MULTIOP_PASSWORD_BUT ) = = 0 ;
debug ( LOG_NET , " Password button hit, %d " , ( int ) willSet ) ;
widgSetButtonState ( psWScreen , MULTIOP_PASSWORD_BUT , willSet ? WBUT_CLICKLOCK : 0 ) ;
widgSetButtonState ( psWScreen , MULTIOP_PASSWORD_EDIT , willSet ? WEDBS_DISABLE : 0 ) ;
if ( willSet )
{
char game_password [ 64 ] ;
sstrcpy ( game_password , widgGetString ( psWScreen , MULTIOP_PASSWORD_EDIT ) ) ;
NETsetGamePassword ( game_password ) ;
// say password is now required to join games?
ssprintf ( buf , _ ( " *** password [%s] is now required! *** " ) , NetPlay . gamePassword ) ;
addConsoleMessage ( buf , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
}
else
{
NETresetGamePassword ( ) ;
ssprintf ( buf , _ ( " *** password is NOT required! *** " ) ) ;
addConsoleMessage ( buf , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
}
NETGameLocked ( willSet ) ;
2007-06-28 10:47:08 -07:00
}
break ;
}
}
// these work all the time.
switch ( id )
{
2013-11-20 19:09:40 -08:00
case MULTIOP_MAP_MOD :
2013-11-20 17:42:09 -08:00
char buf [ 256 ] ;
ssprintf ( buf , _ ( " This is a map-mod, it can change your playing experience! " ) ) ;
addConsoleMessage ( buf , DEFAULT_JUSTIFY , SYSTEM_MESSAGE ) ;
break ;
2013-11-20 19:09:40 -08:00
2013-03-14 09:57:43 -07:00
case MULTIOP_STRUCTLIMITS :
2007-06-28 10:47:08 -07:00
changeTitleMode ( MULTILIMIT ) ;
break ;
2006-05-27 09:37:17 -07:00
case MULTIOP_PNAME :
2008-07-20 15:46:55 -07:00
sstrcpy ( sPlayer , widgGetString ( psWScreen , MULTIOP_PNAME ) ) ;
2007-06-28 10:47:08 -07:00
// chop to 15 chars..
2006-08-12 09:52:37 -07:00
while ( strlen ( sPlayer ) > 15 ) // clip name.
2007-06-28 10:47:08 -07:00
{
sPlayer [ strlen ( sPlayer ) - 1 ] = ' \0 ' ;
}
// update string.
widgSetString ( psWScreen , MULTIOP_PNAME , sPlayer ) ;
2006-11-03 13:35:50 -08:00
removeWildcards ( ( char * ) sPlayer ) ;
2007-06-28 10:47:08 -07:00
2010-08-13 04:44:17 -07:00
printConsoleNameChange ( NetPlay . players [ selectedPlayer ] . name , sPlayer ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
NETchangePlayerName ( selectedPlayer , ( char * ) sPlayer ) ; // update if joined.
2006-11-03 13:35:50 -08:00
loadMultiStats ( ( char * ) sPlayer , & playerStats ) ;
2009-06-07 11:10:13 -07:00
setMultiStats ( selectedPlayer , playerStats , false ) ;
setMultiStats ( selectedPlayer , playerStats , true ) ;
2010-12-07 17:19:15 -08:00
netPlayersUpdated = true ;
2007-06-28 10:47:08 -07:00
break ;
2006-05-27 09:37:17 -07:00
case MULTIOP_PNAME_ICON :
2007-06-28 10:47:08 -07:00
widgDelete ( psWScreen , MULTIOP_PLAYERS ) ;
widgDelete ( psWScreen , FRONTEND_SIDETEXT2 ) ; // del text too,
2007-06-26 06:43:35 -07:00
addMultiRequest ( MultiPlayersPath , " .sta " , MULTIOP_PNAME , 0 , 0 ) ;
2007-06-28 10:47:08 -07:00
break ;
2013-03-14 09:57:43 -07:00
case MULTIOP_HOST :
2010-02-16 20:12:17 -08:00
debug ( LOG_NET , " MULTIOP_HOST enabled " ) ;
2008-07-20 15:46:55 -07:00
sstrcpy ( game . name , widgGetString ( psWScreen , MULTIOP_GNAME ) ) ; // game name
sstrcpy ( sPlayer , widgGetString ( psWScreen , MULTIOP_PNAME ) ) ; // pname
2006-05-27 09:37:17 -07:00
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2009-10-04 19:49:58 -07:00
resetDataHash ( ) ;
2006-11-03 13:35:50 -08:00
removeWildcards ( ( char * ) sPlayer ) ;
2006-05-27 09:37:17 -07:00
2009-06-07 11:10:13 -07:00
if ( ! hostCampaign ( ( char * ) game . name , ( char * ) sPlayer ) )
{
addConsoleMessage ( _ ( " Sorry! Failed to host the game. " ) , DEFAULT_JUSTIFY , SYSTEM_MESSAGE ) ;
break ;
}
2008-03-24 09:51:17 -07:00
bHosted = true ;
2013-01-05 08:02:08 -08:00
loadMapSettings2 ( ) ;
2007-07-21 08:52:33 -07:00
2013-10-31 19:43:00 -07:00
widgDelete ( psWScreen , MULTIOP_REFRESH ) ;
widgDelete ( psWScreen , MULTIOP_HOST ) ;
widgDelete ( psWScreen , MULTIOP_FILTER_TOGGLE ) ;
2006-05-27 09:37:17 -07:00
2008-03-24 09:51:17 -07:00
ingame . localOptionsReceived = true ;
2007-06-28 10:47:08 -07:00
2011-01-04 09:51:15 -08:00
addGameOptions ( ) ; // update game options box.
2007-06-28 10:47:08 -07:00
addChatBox ( ) ;
disableMultiButs ( ) ;
2006-09-26 22:38:51 -07:00
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ; //to make sure host can't skip player selection menu (sets game.skdiff to UBYTE_MAX for humans)
2007-06-28 10:47:08 -07:00
break ;
case MULTIOP_CHATEDIT :
// don't send empty lines to other players in the lobby
if ( ! strcmp ( widgGetString ( psWScreen , MULTIOP_CHATEDIT ) , " " ) )
break ;
2008-03-24 09:51:17 -07:00
sendTextMessage ( widgGetString ( psWScreen , MULTIOP_CHATEDIT ) , true ) ; //send
2007-06-28 10:47:08 -07:00
widgSetString ( psWScreen , MULTIOP_CHATEDIT , " " ) ; // clear box
break ;
case CON_CANCEL :
2012-01-16 18:25:59 -08:00
pie_LoadBackDrop ( SCREEN_RANDOMBDROP ) ;
2009-08-11 13:36:44 -07:00
if ( ! challengeActive )
{
NETGameLocked ( false ) ; // reset status on a cancel
stopJoining ( ) ;
}
else
{
2009-09-05 03:57:59 -07:00
NETclose ( ) ;
bHosted = false ;
ingame . localJoiningInProgress = false ;
2011-12-17 14:02:50 -08:00
changeTitleMode ( SINGLE ) ;
addChallenges ( ) ;
2009-08-11 13:36:44 -07:00
}
2007-06-28 10:47:08 -07:00
break ;
2013-03-14 09:57:43 -07:00
case MULTIOP_MAP_PREVIEW :
2009-05-01 00:14:31 -07:00
loadMapPreview ( true ) ;
2008-04-07 12:07:43 -07:00
break ;
2011-01-15 04:29:23 -08:00
case MULTIOP_AI_CLOSED :
NetPlay . players [ aiChooserUp ] . ai = AI_CLOSED ;
break ;
case MULTIOP_AI_OPEN :
NetPlay . players [ aiChooserUp ] . ai = AI_OPEN ;
break ;
2007-06-28 10:47:08 -07:00
default :
break ;
2006-05-27 09:37:17 -07:00
}
2011-01-15 04:29:23 -08:00
if ( id = = MULTIOP_AI_CLOSED | | id = = MULTIOP_AI_OPEN ) // common code
{
game . skDiff [ aiChooserUp ] = 0 ; // disable AI for this slot
NETBroadcastPlayerInfo ( aiChooserUp ) ;
closeAiChooser ( ) ;
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
}
2012-12-09 13:32:10 -08:00
if ( id > = MULTIOP_DIFFICULTY_CHOOSE_START & & id < = MULTIOP_DIFFICULTY_CHOOSE_END & & difficultyChooserUp ! = - 1 )
2011-01-09 07:35:49 -08:00
{
int idx = id - MULTIOP_DIFFICULTY_CHOOSE_START ;
NetPlay . players [ difficultyChooserUp ] . difficulty = idx ;
game . skDiff [ difficultyChooserUp ] = difficultyValue [ idx ] ;
2011-01-12 13:44:14 -08:00
NETBroadcastPlayerInfo ( difficultyChooserUp ) ;
2011-01-09 07:35:49 -08:00
closeDifficultyChooser ( ) ;
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
}
2012-12-09 13:32:10 -08:00
if ( id > = MULTIOP_AI_START & & id < = MULTIOP_AI_END & & aiChooserUp ! = - 1 )
2011-01-09 07:35:49 -08:00
{
int idx = id - MULTIOP_AI_START ;
NetPlay . players [ aiChooserUp ] . ai = idx ;
2012-03-17 01:30:02 -07:00
sstrcpy ( NetPlay . players [ aiChooserUp ] . name , getAIName ( aiChooserUp ) ) ;
2011-01-15 04:29:23 -08:00
game . skDiff [ aiChooserUp ] = difficultyValue [ NetPlay . players [ aiChooserUp ] . difficulty ] ; // set difficulty, in case re-enabled
2011-01-12 13:44:14 -08:00
NETBroadcastPlayerInfo ( aiChooserUp ) ;
2011-01-09 07:35:49 -08:00
closeAiChooser ( ) ;
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
}
2011-01-03 05:48:41 -08:00
STATIC_ASSERT ( MULTIOP_TEAMS_START + MAX_PLAYERS - 1 < = MULTIOP_TEAMS_END ) ;
2013-01-05 08:02:08 -08:00
if ( id > = MULTIOP_TEAMS_START & & id < = MULTIOP_TEAMS_START + MAX_PLAYERS - 1 & & ! locked . teams ) // Clicked on a team chooser
2006-09-26 11:14:05 -07:00
{
2009-06-07 11:10:13 -07:00
int clickedMenuID = id - MULTIOP_TEAMS_START ;
2006-09-26 11:14:05 -07:00
//make sure team chooser is not up before adding new one for another player
2011-01-04 09:51:15 -08:00
if ( teamChooserUp < 0 & & colourChooserUp < 0 & & canChooseTeamFor ( clickedMenuID ) & & positionChooserUp < 0 )
2006-09-26 11:14:05 -07:00
{
2009-06-07 11:10:13 -07:00
addTeamChooser ( clickedMenuID ) ;
2006-09-26 11:14:05 -07:00
}
}
//clicked on a team
2011-01-03 05:48:41 -08:00
STATIC_ASSERT ( MULTIOP_TEAMCHOOSER + MAX_PLAYERS - 1 < = MULTIOP_TEAMCHOOSER_END ) ;
if ( id > = MULTIOP_TEAMCHOOSER & & id < = MULTIOP_TEAMCHOOSER + MAX_PLAYERS - 1 )
2006-09-26 11:14:05 -07:00
{
2009-06-07 11:10:13 -07:00
ASSERT ( teamChooserUp > = 0 , " teamChooserUp < 0 " ) ;
2008-10-14 14:03:23 -07:00
ASSERT ( id > = MULTIOP_TEAMCHOOSER
& & ( id - MULTIOP_TEAMCHOOSER ) < MAX_PLAYERS , " processMultiopWidgets: wrong id - MULTIOP_TEAMCHOOSER value (%d) " , id - MULTIOP_TEAMCHOOSER ) ;
2006-09-26 11:14:05 -07:00
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ; // will reset only locally if not a host
2009-06-07 11:10:13 -07:00
SendTeamRequest ( teamChooserUp , ( UBYTE ) id - MULTIOP_TEAMCHOOSER ) ;
2006-09-26 11:14:05 -07:00
2009-06-07 11:10:13 -07:00
debug ( LOG_WZ , " Changed team for player %d to %d " , teamChooserUp , NetPlay . players [ teamChooserUp ] . team ) ;
2006-09-26 11:14:05 -07:00
closeTeamChooser ( ) ;
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ; //restore initial options screen
}
2008-04-09 13:05:09 -07:00
// 'ready' button
2011-01-03 05:48:41 -08:00
if ( id > = MULTIOP_READY_START & & id < = MULTIOP_READY_END ) // clicked on a player
2008-04-09 13:05:09 -07:00
{
UBYTE player = ( UBYTE ) ( id - MULTIOP_READY_START ) ;
2008-05-03 10:43:55 -07:00
2011-01-04 09:51:15 -08:00
if ( player = = selectedPlayer & & teamChooserUp < 0 & & positionChooserUp < 0 )
2008-04-09 13:05:09 -07:00
{
2009-06-07 11:10:13 -07:00
SendReadyRequest ( selectedPlayer , ! NetPlay . players [ player ] . ready ) ;
2008-04-09 13:05:09 -07:00
// if hosting try to start the game if everyone is ready
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost & & multiplayPlayersReady ( false ) )
2008-04-09 13:05:09 -07:00
{
startMultiplayerGame ( ) ;
2009-02-21 14:09:58 -08:00
// reset flag in case people dropped/quit on join screen
2010-08-01 04:06:50 -07:00
NETsetPlayerConnectionStatus ( CONNECTIONSTATUS_NORMAL , NET_ALL_PLAYERS ) ;
2008-04-09 13:05:09 -07:00
}
}
2012-02-19 14:49:49 -08:00
2013-04-29 12:20:34 -07:00
if ( NetPlay . isHost & & ! alliancesSetTeamsBeforeGame ( game . alliance ) )
2012-02-19 14:49:49 -08:00
{
if ( mouseDown ( MOUSE_RMB ) & & player ! = NetPlay . hostPlayer ) // both buttons....
{
char * msg ;
sasprintf ( & msg , _ ( " The host has kicked %s from the game! " ) , getPlayerName ( player ) ) ;
sendTextMessage ( msg , true ) ;
kickPlayer ( player , " you are unwanted by the host. " , ERROR_KICKED ) ;
resetReadyStatus ( true ) ; //reset and send notification to all clients
}
}
2008-04-09 13:05:09 -07:00
}
2011-01-04 09:51:15 -08:00
if ( id > = MULTIOP_COLOUR_START & & id < = MULTIOP_COLOUR_END & & ( id - MULTIOP_COLOUR_START = = selectedPlayer | | NetPlay . isHost ) )
2007-06-28 10:47:08 -07:00
{
2011-01-10 10:58:00 -08:00
if ( teamChooserUp < 0 & & positionChooserUp < 0 & & colourChooserUp < 0 ) // not choosing something else already
2009-12-20 23:14:24 -08:00
{
2011-01-04 09:51:15 -08:00
addColourChooser ( id - MULTIOP_COLOUR_START ) ;
2007-06-28 10:47:08 -07:00
}
}
2011-01-12 13:44:14 -08:00
// clicked on a player
2011-01-03 05:48:41 -08:00
STATIC_ASSERT ( MULTIOP_PLAYER_START + MAX_PLAYERS - 1 < = MULTIOP_PLAYER_END ) ;
2012-01-14 06:59:20 -08:00
if ( id > = MULTIOP_PLAYER_START & & id < = MULTIOP_PLAYER_START + MAX_PLAYERS - 1
2013-01-05 08:02:08 -08:00
& & ! locked . position
2012-01-14 06:59:20 -08:00
& & ( id - MULTIOP_PLAYER_START = = selectedPlayer | | NetPlay . isHost
| | ( positionChooserUp > = 0 & & ! isHumanPlayer ( id - MULTIOP_PLAYER_START ) ) ) )
2007-06-28 10:47:08 -07:00
{
2011-01-04 09:51:15 -08:00
int player = id - MULTIOP_PLAYER_START ;
2011-01-12 13:44:14 -08:00
if ( ( player = = selectedPlayer | | ( NetPlay . players [ player ] . allocated & & NetPlay . isHost ) )
& & positionChooserUp < 0 & & teamChooserUp < 0 & & colourChooserUp < 0 )
2006-09-26 11:14:05 -07:00
{
2011-01-04 09:51:15 -08:00
addPositionChooser ( player ) ;
2006-09-26 11:14:05 -07:00
}
2011-01-04 09:51:15 -08:00
else if ( positionChooserUp = = player )
2009-12-20 23:14:24 -08:00
{
2011-01-04 09:51:15 -08:00
closePositionChooser ( ) ; // changed his mind
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
}
else if ( positionChooserUp > = 0 )
{
// Switch player
resetReadyStatus ( false ) ; // will reset only locally if not a host
SendPositionRequest ( positionChooserUp , NetPlay . players [ player ] . position ) ;
closePositionChooser ( ) ;
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
2007-06-28 10:47:08 -07:00
}
2013-01-05 08:02:08 -08:00
else if ( ! NetPlay . players [ player ] . allocated & & ! locked . ai & & NetPlay . isHost
2011-01-10 10:58:00 -08:00
& & positionChooserUp < 0 & & teamChooserUp < 0 & & colourChooserUp < 0 )
2011-01-10 10:26:30 -08:00
{
addAiChooser ( player ) ;
}
2007-06-28 10:47:08 -07:00
}
2011-01-10 10:58:00 -08:00
if ( id > = MULTIOP_DIFFICULTY_INIT_START & & id < = MULTIOP_DIFFICULTY_INIT_END
2013-01-05 08:02:08 -08:00
& & ! locked . difficulty & & NetPlay . isHost & & positionChooserUp < 0 & & teamChooserUp < 0 & & colourChooserUp < 0 )
2007-06-28 10:47:08 -07:00
{
2011-01-09 07:35:49 -08:00
addDifficultyChooser ( id - MULTIOP_DIFFICULTY_INIT_START ) ;
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
2007-06-28 10:47:08 -07:00
}
2011-01-03 05:48:41 -08:00
STATIC_ASSERT ( MULTIOP_COLCHOOSER + MAX_PLAYERS - 1 < = MULTIOP_COLCHOOSER_END ) ;
if ( id > = MULTIOP_COLCHOOSER & & id < MULTIOP_COLCHOOSER + MAX_PLAYERS - 1 ) // chose a new colour.
2007-06-28 10:47:08 -07:00
{
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ; // will reset only locally if not a host
2010-01-04 23:13:16 -08:00
SendColourRequest ( colourChooserUp , id - MULTIOP_COLCHOOSER ) ;
2007-06-28 10:47:08 -07:00
closeColourChooser ( ) ;
2011-01-04 09:51:15 -08:00
addPlayerBox ( ! ingame . bHostSetup | | bHosted ) ;
2007-06-28 10:47:08 -07:00
}
2011-01-04 09:51:15 -08:00
if ( id = = MULTIOP_TEAMCHOOSER_KICK )
2010-01-09 05:39:09 -08:00
{
char * msg ;
2011-01-04 09:51:15 -08:00
sasprintf ( & msg , _ ( " The host has kicked %s from the game! " ) , getPlayerName ( teamChooserUp ) ) ;
kickPlayer ( teamChooserUp , " you are unwanted by the host. " , ERROR_KICKED ) ;
2012-02-19 14:49:49 -08:00
sendTextMessage ( msg , true ) ;
2010-01-09 05:39:09 -08:00
resetReadyStatus ( true ) ; //reset and send notification to all clients
2011-01-04 09:51:15 -08:00
closeTeamChooser ( ) ;
2007-06-28 10:47:08 -07:00
}
}
2008-04-09 13:05:09 -07:00
/* Start a multiplayer or skirmish game */
void startMultiplayerGame ( void )
{
2010-11-25 03:58:28 -08:00
if ( ! bHosted )
{
debug ( LOG_ERROR , " Multiple start requests received when we already started. " ) ;
return ;
}
2008-04-09 13:05:09 -07:00
decideWRF ( ) ; // set up swrf & game.map
bMultiPlayer = true ;
2010-01-22 12:44:50 -08:00
bMultiMessages = true ;
2010-08-01 04:06:50 -07:00
NETsetPlayerConnectionStatus ( CONNECTIONSTATUS_NORMAL , NET_ALL_PLAYERS ) ; // reset disconnect conditions
2012-01-30 17:38:15 -08:00
initLoadingScreen ( true ) ;
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2008-04-09 13:05:09 -07:00
{
2010-02-16 20:12:17 -08:00
// This sets the limits to whatever the defaults are for the limiter screen
// If host sets limits, then we do not need to do the following routine.
if ( ! bLimiterLoaded )
2009-12-18 16:31:58 -08:00
{
2010-02-16 20:12:17 -08:00
debug ( LOG_NET , " limiter was NOT activated, setting defaults " ) ;
2010-02-17 14:34:37 -08:00
2013-09-07 07:27:36 -07:00
if ( ! resLoad ( " wrf/limiter_data.wrf " , 503 ) )
2009-12-18 16:31:58 -08:00
{
2010-02-17 14:34:37 -08:00
debug ( LOG_INFO , " Unable to load limiter_data. " ) ;
2009-12-18 16:31:58 -08:00
}
}
2010-02-16 20:12:17 -08:00
else
{
debug ( LOG_NET , " limiter was activated " ) ;
}
resetDataHash ( ) ; // need to reset it, since host's data has changed.
createLimitSet ( ) ;
debug ( LOG_NET , " sending our options to all clients " ) ;
2011-07-17 12:41:06 -07:00
sendOptions ( ) ;
2008-04-09 13:05:09 -07:00
NEThaltJoining ( ) ; // stop new players entering.
2009-10-04 19:49:58 -07:00
ingame . TimeEveryoneIsInGame = 0 ;
ingame . isAllPlayersDataOK = false ;
2010-02-16 20:12:17 -08:00
memset ( & ingame . DataIntegrity , 0x0 , sizeof ( ingame . DataIntegrity ) ) ; //clear all player's array
2008-04-09 13:05:09 -07:00
SendFireUp ( ) ; //bcast a fireup message
}
2011-07-17 12:41:06 -07:00
debug ( LOG_NET , " title mode STARTGAME is set--Starting Game! " ) ;
2008-04-09 13:05:09 -07:00
changeTitleMode ( STARTGAME ) ;
bHosted = false ;
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2008-04-09 13:05:09 -07:00
{
sendTextMessage ( _ ( " Host is Starting Game " ) , true ) ;
}
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
// Net message handling
void frontendMultiMessages ( void )
{
2010-02-09 09:43:53 -08:00
NETQUEUE queue ;
2008-02-13 12:25:12 -08:00
uint8_t type ;
2007-06-28 10:47:08 -07:00
2010-02-09 09:43:53 -08:00
while ( NETrecvNet ( & queue , & type ) )
2007-06-28 10:47:08 -07:00
{
2007-12-22 10:51:45 -08:00
// Copy the message to the global one used by the new NET API
2008-02-13 12:25:12 -08:00
switch ( type )
2007-06-28 10:47:08 -07:00
{
2009-12-18 16:23:37 -08:00
case NET_FILE_REQUESTED :
2010-02-09 09:43:53 -08:00
recvMapFileRequested ( queue ) ;
2007-06-28 10:47:08 -07:00
break ;
2009-09-03 12:44:37 -07:00
2009-12-18 16:23:37 -08:00
case NET_FILE_PAYLOAD :
2013-03-14 09:57:43 -07:00
{
bool done = recvMapFileData ( queue ) ;
( ( MultibuttonWidget * ) widgGetFromID ( psWScreen , MULTIOP_MAP_PREVIEW ) ) - > enable ( done ) ; // turn preview button on or off
2007-06-28 10:47:08 -07:00
break ;
2013-03-14 09:57:43 -07:00
}
2007-06-28 10:47:08 -07:00
2009-12-18 16:23:37 -08:00
case NET_FILE_CANCELLED : // host only routine
{
uint32_t reason ;
uint32_t victim ;
2012-02-19 14:49:49 -08:00
if ( ! NetPlay . isHost ) // only host should act
{
ASSERT ( false , " Host only routine detected for client! " ) ;
break ;
}
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_FILE_CANCELLED ) ;
2009-12-18 16:23:37 -08:00
NETuint32_t ( & victim ) ;
NETuint32_t ( & reason ) ;
NETend ( ) ;
2012-02-19 14:49:49 -08:00
if ( whosResponsible ( victim ) ! = queue . index )
{
HandleBadParam ( " NET_FILE_CANCELLED given incorrect params. " , victim , queue . index ) ;
return ;
}
2009-12-18 16:23:37 -08:00
switch ( reason )
{
case STUCK_IN_FILE_LOOP :
debug ( LOG_WARNING , " Received file cancel request from player %u, They are stuck in a loop? " , victim ) ;
2010-01-05 09:50:28 -08:00
kickPlayer ( victim , " the host couldn't send a file for some reason. " , ERROR_UNKNOWNFILEISSUE ) ;
2009-12-18 16:23:37 -08:00
NetPlay . players [ victim ] . wzFile . isCancelled = true ;
NetPlay . players [ victim ] . wzFile . isSending = false ;
break ;
case ALREADY_HAVE_FILE :
default :
2010-01-05 09:50:28 -08:00
debug ( LOG_WARNING , " Received file cancel request from player %u, they already have the file. " , victim ) ;
2009-12-18 16:23:37 -08:00
NetPlay . players [ victim ] . wzFile . isCancelled = true ;
NetPlay . players [ victim ] . wzFile . isSending = false ;
break ;
}
}
break ;
2007-06-28 10:47:08 -07:00
case NET_OPTIONS : // incoming options file.
2010-02-09 09:43:53 -08:00
recvOptions ( queue ) ;
2008-03-24 09:51:17 -07:00
ingame . localOptionsReceived = true ;
2007-06-28 10:47:08 -07:00
if ( titleMode = = MULTIOPTION )
{
2011-01-04 09:51:15 -08:00
addGameOptions ( ) ;
2007-06-28 10:47:08 -07:00
disableMultiButs ( ) ;
addChatBox ( ) ;
}
break ;
2010-02-12 09:40:13 -08:00
case GAME_ALLIANCE :
2010-02-09 09:43:53 -08:00
recvAlliance ( queue , false ) ;
2007-06-28 10:47:08 -07:00
break ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
case NET_COLOURREQUEST :
2010-02-09 09:43:53 -08:00
recvColourRequest ( queue ) ;
2007-06-28 10:47:08 -07:00
break ;
2009-11-26 10:33:03 -08:00
case NET_POSITIONREQUEST :
2010-02-09 09:43:53 -08:00
recvPositionRequest ( queue ) ;
2009-11-26 10:33:03 -08:00
break ;
2006-09-26 11:14:05 -07:00
case NET_TEAMREQUEST :
2010-02-09 09:43:53 -08:00
recvTeamRequest ( queue ) ;
2006-09-26 11:14:05 -07:00
break ;
2008-04-09 13:05:09 -07:00
case NET_READY_REQUEST :
2010-02-09 09:43:53 -08:00
recvReadyRequest ( queue ) ;
2008-04-09 13:05:09 -07:00
2010-11-25 03:58:28 -08:00
// If hosting and game not yet started, try to start the game if everyone is ready.
if ( NetPlay . isHost & & bHosted & & multiplayPlayersReady ( false ) )
2008-04-09 13:05:09 -07:00
{
startMultiplayerGame ( ) ;
}
break ;
2007-06-28 10:47:08 -07:00
case NET_PING : // diagnostic ping msg.
2010-02-09 09:43:53 -08:00
recvPing ( queue ) ;
2007-06-28 10:47:08 -07:00
break ;
2009-02-21 14:09:58 -08:00
case NET_PLAYER_DROPPED : // remote player got disconnected
2008-01-09 15:30:42 -08:00
{
2010-07-23 09:46:52 -07:00
uint32_t player_id = MAX_PLAYERS ;
2008-01-09 15:30:42 -08:00
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_PLAYER_DROPPED ) ;
2008-01-09 15:30:42 -08:00
{
NETuint32_t ( & player_id ) ;
}
NETend ( ) ;
2009-02-21 14:09:58 -08:00
2010-07-23 09:46:52 -07:00
if ( player_id > = MAX_PLAYERS )
{
debug ( LOG_INFO , " ** player %u has dropped - huh? " , player_id ) ;
break ;
}
2012-02-19 14:49:49 -08:00
if ( whosResponsible ( player_id ) ! = queue . index & & queue . index ! = NET_HOST_ONLY )
{
HandleBadParam ( " NET_PLAYER_DROPPED given incorrect params. " , player_id , queue . index ) ;
break ;
}
2010-07-23 09:46:52 -07:00
debug ( LOG_INFO , " ** player %u has dropped! " , player_id ) ;
2009-02-21 14:09:58 -08:00
2010-02-06 20:49:23 -08:00
MultiPlayerLeave ( player_id ) ; // get rid of their stuff
2010-07-23 09:46:52 -07:00
NET_InitPlayer ( player_id , false ) ; // sets index player's array to false
2010-08-01 04:06:50 -07:00
NETsetPlayerConnectionStatus ( CONNECTIONSTATUS_PLAYER_DROPPED , player_id ) ;
2010-07-23 09:46:52 -07:00
if ( player_id = = NetPlay . hostPlayer | | player_id = = selectedPlayer ) // if host quits or we quit, abort out
2007-06-28 10:47:08 -07:00
{
stopJoining ( ) ;
}
break ;
2008-01-09 15:30:42 -08:00
}
2007-06-28 10:47:08 -07:00
case NET_PLAYERRESPONDING : // remote player is now playing.
2008-01-09 15:42:35 -08:00
{
uint32_t player_id ;
2007-06-28 10:47:08 -07:00
2008-04-10 12:19:04 -07:00
resetReadyStatus ( false ) ;
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_PLAYERRESPONDING ) ;
2008-01-09 15:42:35 -08:00
// the player that has just responded
NETuint32_t ( & player_id ) ;
NETend ( ) ;
2008-03-24 09:51:17 -07:00
ingame . JoiningInProgress [ player_id ] = false ;
2009-10-04 19:49:58 -07:00
ingame . DataIntegrity [ player_id ] = false ;
2008-01-09 15:42:35 -08:00
break ;
}
2007-06-28 10:47:08 -07:00
case NET_FIREUP : // campaign game started.. can fire the whole shebang up...
2012-02-19 14:49:49 -08:00
if ( NET_HOST_ONLY ! = queue . index )
{
HandleBadParam ( " NET_FIREUP given incorrect params. " , 255 , queue . index ) ;
break ;
}
2011-07-17 12:41:06 -07:00
debug ( LOG_NET , " NET_FIREUP was received ... " ) ;
2007-06-28 10:47:08 -07:00
if ( ingame . localOptionsReceived )
{
2012-03-31 06:19:22 -07:00
uint32_t randomSeed = 0 ;
NETbeginDecode ( queue , NET_FIREUP ) ;
NETuint32_t ( & randomSeed ) ;
NETend ( ) ;
gameSRand ( randomSeed ) ; // Set the seed for the synchronised random number generator, using the seed given by the host.
2010-01-31 21:27:29 -08:00
debug ( LOG_NET , " & local Options Received (MP game) " ) ;
ingame . TimeEveryoneIsInGame = 0 ; // reset time
2009-10-04 19:49:58 -07:00
resetDataHash ( ) ;
2007-06-28 10:47:08 -07:00
decideWRF ( ) ;
2008-03-24 09:51:17 -07:00
bMultiPlayer = true ;
2010-01-22 12:44:50 -08:00
bMultiMessages = true ;
2007-06-28 10:47:08 -07:00
changeTitleMode ( STARTGAME ) ;
2008-03-24 09:51:17 -07:00
bHosted = false ;
2010-02-22 10:05:38 -08:00
// Start the game before processing more messages.
NETpop ( queue ) ;
return ;
2007-06-28 10:47:08 -07:00
}
2010-02-21 07:51:20 -08:00
ASSERT ( false , " NET_FIREUP was received, but !ingame.localOptionsReceived. " ) ;
break ;
2007-06-28 10:47:08 -07:00
case NET_KICK : // player is forcing someone to leave
2008-01-09 15:30:42 -08:00
{
uint32_t player_id ;
2009-04-10 21:41:14 -07:00
char reason [ MAX_KICK_REASON ] ;
2009-06-07 13:01:34 -07:00
LOBBY_ERROR_TYPES KICK_TYPE = ERROR_NOERROR ;
2008-01-09 15:30:42 -08:00
2011-01-04 09:51:15 -08:00
NETbeginDecode ( queue , NET_KICK ) ;
NETuint32_t ( & player_id ) ;
NETstring ( reason , MAX_KICK_REASON ) ;
NETenum ( & KICK_TYPE ) ;
NETend ( ) ;
2010-04-18 12:03:44 -07:00
if ( player_id = = NET_HOST_ONLY )
{
2012-02-19 14:49:49 -08:00
char buf [ 250 ] = { ' \0 ' } ;
ssprintf ( buf , " *Player %d (%s : %s) tried to kick %u " , ( int ) queue . index , NetPlay . players [ queue . index ] . name , NetPlay . players [ queue . index ] . IPtextAddress , player_id ) ;
NETlogEntry ( buf , SYNC_FLAG , 0 ) ;
debug ( LOG_ERROR , " %s " , buf ) ;
if ( NetPlay . isHost )
{
NETplayerKicked ( ( unsigned int ) queue . index ) ;
}
2010-04-18 12:03:44 -07:00
break ;
}
2009-06-07 11:10:13 -07:00
if ( selectedPlayer = = player_id ) // we've been told to leave.
2006-05-27 09:37:17 -07:00
{
2009-04-19 11:45:28 -07:00
setLobbyError ( KICK_TYPE ) ;
2007-06-28 10:47:08 -07:00
stopJoining ( ) ;
2009-04-19 11:45:28 -07:00
//screen_RestartBackDrop();
2013-10-31 19:42:23 -07:00
changeTitleMode ( GAMEFIND ) ;
2009-04-10 21:54:23 -07:00
pie_LoadBackDrop ( SCREEN_RANDOMBDROP ) ;
2011-01-04 09:51:15 -08:00
debug ( LOG_ERROR , " You have been kicked, because %s " , reason ) ;
2007-06-28 10:47:08 -07:00
}
2010-01-09 05:39:09 -08:00
else
{
NETplayerKicked ( player_id ) ;
}
2007-06-28 10:47:08 -07:00
break ;
2008-01-09 15:30:42 -08:00
}
2009-11-28 12:40:53 -08:00
case NET_HOST_DROPPED :
2010-02-09 09:43:53 -08:00
NETbeginDecode ( queue , NET_HOST_DROPPED ) ;
2009-11-28 12:40:53 -08:00
NETend ( ) ;
stopJoining ( ) ;
debug ( LOG_NET , " The host has quit! " ) ;
setLobbyError ( ERROR_HOSTDROPPED ) ;
2013-10-31 19:42:23 -07:00
changeTitleMode ( GAMEFIND ) ;
2009-11-28 12:40:53 -08:00
break ;
2007-06-28 10:47:08 -07:00
case NET_TEXTMSG : // Chat message
if ( ingame . localOptionsReceived )
{
2010-02-09 09:43:53 -08:00
recvTextMessage ( queue ) ;
2007-06-28 10:47:08 -07:00
}
break ;
2010-02-22 10:05:38 -08:00
default :
debug ( LOG_ERROR , " Didn't handle %s message! " , messageTypeToString ( type ) ) ;
break ;
2007-06-28 10:47:08 -07:00
}
2010-02-10 14:45:52 -08:00
NETpop ( queue ) ;
2007-06-28 10:47:08 -07:00
}
}
2006-09-13 02:09:05 -07:00
void runMultiOptions ( void )
2007-06-28 10:47:08 -07:00
{
2009-12-18 16:23:37 -08:00
static UDWORD lastrefresh = 0 ;
2013-02-11 15:08:37 -08:00
char oldGameMap [ 128 ] ;
2011-12-04 02:09:48 -08:00
int oldMaxPlayers ;
2007-06-28 10:47:08 -07:00
PLAYERSTATS playerStats ;
W_CONTEXT context ;
KEY_CODE k ;
2006-11-03 13:35:50 -08:00
char str [ 3 ] ;
2007-06-28 10:47:08 -07:00
frontendMultiMessages ( ) ;
2012-03-25 21:20:33 -07:00
if ( NetPlay . isHost )
2007-06-28 10:47:08 -07:00
{
2013-01-27 00:02:31 -08:00
for ( unsigned i = 0 ; i < MAX_PLAYERS ; i + + )
2009-12-18 16:23:37 -08:00
{
2012-03-25 21:20:33 -07:00
// send it for each player that needs it
if ( NetPlay . players [ i ] . wzFile . isSending )
{
sendMap ( ) ;
}
2009-12-18 16:23:37 -08:00
}
2007-06-28 10:47:08 -07:00
}
// update boxes?
2009-12-03 21:50:40 -08:00
if ( netPlayersUpdated | | ( NetPlay . isHost & & mouseDown ( MOUSE_LMB ) & & gameTime - lastrefresh > 500 ) )
2007-06-28 10:47:08 -07:00
{
2009-12-03 21:50:40 -08:00
netPlayersUpdated = false ;
2007-06-28 10:47:08 -07:00
lastrefresh = gameTime ;
2008-02-11 08:00:17 -08:00
if ( ! multiRequestUp & & ( bHosted | | ingame . localJoiningInProgress ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
addPlayerBox ( true ) ; // update the player box.
2011-01-04 09:51:15 -08:00
loadMapPreview ( false ) ;
2007-06-28 10:47:08 -07:00
}
}
// update scores and pings if far enough into the game
if ( ingame . localOptionsReceived & & ingame . localJoiningInProgress )
{
sendScoreCheck ( ) ;
sendPing ( ) ;
}
// if typing and not in an edit box then jump to chat box.
k = getQwertyKey ( ) ;
2006-05-27 09:37:17 -07:00
if ( k & & psWScreen - > psFocus = = NULL )
2007-06-28 10:47:08 -07:00
{
context . xOffset = 0 ;
context . yOffset = 0 ;
context . mx = mouseX ( ) ;
context . my = mouseY ( ) ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
keyScanToString ( k , ( char * ) & str , 3 ) ;
if ( widgGetFromID ( psWScreen , MULTIOP_CHATEDIT ) )
{
widgSetString ( psWScreen , MULTIOP_CHATEDIT , ( char * ) & str ) ; // start it up!
2010-12-20 12:37:49 -08:00
widgGetFromID ( psWScreen , MULTIOP_CHATEDIT ) - > clicked ( & context ) ;
2007-06-28 10:47:08 -07:00
}
}
// chat box handling
if ( widgGetFromID ( psWScreen , MULTIOP_CHATBOX ) )
{
2006-05-27 09:37:17 -07:00
while ( getNumberConsoleMessages ( ) > getConsoleLineInfo ( ) )
2007-06-28 10:47:08 -07:00
{
removeTopConsoleMessage ( ) ;
}
updateConsoleMessages ( ) ; // run the chatbox
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
// widget handling
if ( multiRequestUp )
{
2013-01-27 00:02:31 -08:00
WidgetTriggers const & triggers = widgRunScreen ( psRScreen ) ;
unsigned id = triggers . empty ( ) ? 0 : triggers . front ( ) . widget - > id ; // Just use first click here, since the next click could be on another menu.
2012-06-18 08:24:06 -07:00
LEVEL_DATASET * mapData ;
2011-12-04 02:09:48 -08:00
bool isHoverPreview ;
2013-02-11 15:08:37 -08:00
QString sTemp ;
if ( runMultiRequester ( id , & id , & sTemp , & mapData , & isHoverPreview ) )
2007-06-28 10:47:08 -07:00
{
2012-06-18 08:24:06 -07:00
Sha256 oldGameHash ;
2007-06-28 10:47:08 -07:00
switch ( id )
{
case MULTIOP_PNAME :
2013-02-11 15:08:37 -08:00
sstrcpy ( sPlayer , sTemp . toUtf8 ( ) . constData ( ) ) ;
widgSetString ( psWScreen , MULTIOP_PNAME , sTemp . toUtf8 ( ) . constData ( ) ) ;
2007-06-28 10:47:08 -07:00
2010-08-13 04:44:17 -07:00
removeWildcards ( ( char * ) sPlayer ) ;
printConsoleNameChange ( NetPlay . players [ selectedPlayer ] . name , sPlayer ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
NETchangePlayerName ( selectedPlayer , ( char * ) sPlayer ) ;
2006-11-03 13:35:50 -08:00
loadMultiStats ( ( char * ) sPlayer , & playerStats ) ;
2009-06-07 11:10:13 -07:00
setMultiStats ( selectedPlayer , playerStats , false ) ;
setMultiStats ( selectedPlayer , playerStats , true ) ;
2010-12-07 17:19:15 -08:00
netPlayersUpdated = true ;
2007-06-28 10:47:08 -07:00
break ;
case MULTIOP_MAP :
2012-06-18 08:24:06 -07:00
{
2011-12-04 02:09:48 -08:00
sstrcpy ( oldGameMap , game . map ) ;
2012-06-18 08:24:06 -07:00
oldGameHash = game . hash ;
2011-12-04 02:09:48 -08:00
oldMaxPlayers = game . maxPlayers ;
2012-06-18 08:24:06 -07:00
sstrcpy ( game . map , mapData - > pName ) ;
game . hash = levGetFileHash ( mapData ) ;
game . maxPlayers = mapData - > players ;
2013-11-20 19:09:40 -08:00
game . isMapMod = CheckForMod ( mapData - > realFileName ) ;
2011-12-04 02:09:48 -08:00
loadMapPreview ( ! isHoverPreview ) ;
if ( isHoverPreview )
{
sstrcpy ( game . map , oldGameMap ) ;
2012-06-18 08:24:06 -07:00
game . hash = oldGameHash ;
2011-12-04 02:09:48 -08:00
game . maxPlayers = oldMaxPlayers ;
}
2013-01-05 08:02:08 -08:00
else
{
loadMapSettings1 ( ) ;
}
2007-06-28 10:47:08 -07:00
2013-11-20 19:09:40 -08:00
widgSetString ( psWScreen , MULTIOP_MAP + 1 , mapData - > pName ) ; //What a horrible, horrible way to do this! FIX ME! (See addBlueForm)
2011-01-04 09:51:15 -08:00
addGameOptions ( ) ;
2007-06-28 10:47:08 -07:00
break ;
2012-06-18 08:24:06 -07:00
}
2007-06-28 10:47:08 -07:00
default :
2011-12-04 02:09:48 -08:00
loadMapPreview ( false ) ; // Restore the preview of the old map.
2007-06-28 10:47:08 -07:00
break ;
}
2011-12-04 02:09:48 -08:00
if ( ! isHoverPreview )
{
addPlayerBox ( ! ingame . bHostSetup ) ;
}
2007-06-28 10:47:08 -07:00
}
}
else
{
if ( hideTime ! = 0 )
{
2008-04-07 12:07:43 -07:00
// we abort the 'hidetime' on press of a mouse button.
if ( gameTime - hideTime < MAP_PREVIEW_DISPLAY_TIME & & ! mousePressed ( MOUSE_LMB ) & & ! mousePressed ( MOUSE_RMB ) )
2006-05-27 09:37:17 -07:00
{
2007-06-28 10:47:08 -07:00
return ;
}
2011-12-11 06:51:31 -08:00
inputLoseFocus ( ) ; // remove the mousepress from the input stream.
2007-06-28 10:47:08 -07:00
hideTime = 0 ;
}
2013-01-27 00:02:31 -08:00
WidgetTriggers const & triggers = widgRunScreen ( psWScreen ) ;
unsigned id = triggers . empty ( ) ? 0 : triggers . front ( ) . widget - > id ; // Just use first click here, since the next click could be on another menu.
2007-06-28 10:47:08 -07:00
processMultiopWidgets ( id ) ;
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
widgDisplayScreen ( psWScreen ) ; // show the widgets currently running
if ( multiRequestUp )
{
widgDisplayScreen ( psRScreen ) ; // show the Requester running
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
if ( widgGetFromID ( psWScreen , MULTIOP_CHATBOX ) )
{
2007-10-01 12:45:49 -07:00
iV_SetFont ( font_regular ) ; // switch to small font.
2007-06-28 10:47:08 -07:00
displayConsoleMessages ( ) ; // draw the chatbox
}
2010-06-20 16:51:52 -07:00
if ( CancelPressed ( ) )
{
2011-06-12 12:09:03 -07:00
processMultiopWidgets ( CON_CANCEL ) ; // "Press" the cancel button to clean up net connections and stuff.
2010-06-20 16:51:52 -07:00
}
2012-03-25 21:19:37 -07:00
if ( ! NetPlay . isHostAlive & & ! ingame . bHostSetup )
{
changeTitleMode ( GAMEFIND ) ;
screen_RestartBackDrop ( ) ;
}
2007-06-28 10:47:08 -07:00
}
2011-03-12 17:32:15 -08:00
bool startMultiOptions ( bool bReenter )
2007-06-28 10:47:08 -07:00
{
PLAYERSTATS nullStats ;
UBYTE i ;
2010-01-03 16:51:58 -08:00
netPlayersUpdated = true ;
2006-05-27 09:37:17 -07:00
addBackdrop ( ) ;
2011-09-09 06:41:25 -07:00
loadMapPreview ( false ) ;
2007-06-28 10:47:08 -07:00
addTopForm ( ) ;
2012-02-19 14:49:49 -08:00
if ( getLobbyError ( ) ! = ERROR_INVALID )
2009-04-19 11:45:28 -07:00
{
setLobbyError ( ERROR_NOERROR ) ;
}
2009-09-05 05:38:25 -07:00
// free limiter structure
if ( ! bReenter | | challengeActive )
{
if ( ingame . numStructureLimits )
{
ingame . numStructureLimits = 0 ;
free ( ingame . pStructureLimits ) ;
ingame . pStructureLimits = NULL ;
}
}
2011-07-17 12:41:06 -07:00
2007-06-28 10:47:08 -07:00
if ( ! bReenter )
{
2013-01-05 08:02:08 -08:00
memset ( nameOverrides , 0 , sizeof ( nameOverrides ) ) ;
memset ( & locked , 0 , sizeof ( locked ) ) ; // nothing is locked by default
2009-06-07 11:10:13 -07:00
teamChooserUp = - 1 ;
2011-01-09 07:35:49 -08:00
aiChooserUp = - 1 ;
difficultyChooserUp = - 1 ;
2011-01-04 09:51:15 -08:00
positionChooserUp = - 1 ;
colourChooserUp = - 1 ;
2010-12-05 17:12:41 -08:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2007-06-28 10:47:08 -07:00
{
2009-11-26 10:33:03 -08:00
game . skDiff [ i ] = ( DIFF_SLIDER_STOPS / 2 ) ; // reset AI (turn it on again)
setPlayerColour ( i , i ) ; //reset all colors as well
2007-06-28 10:47:08 -07:00
}
2013-11-20 19:09:40 -08:00
game . isMapMod = false ; // reset map-mod status
2011-07-03 04:50:27 -07:00
game . mapHasScavengers = true ; // FIXME, should default to false
2009-04-19 11:45:28 -07:00
if ( ! NetPlay . bComms ) // force skirmish if no comms.
2007-06-28 10:47:08 -07:00
{
2009-06-09 09:55:07 -07:00
game . type = SKIRMISH ;
2008-07-20 15:46:55 -07:00
sstrcpy ( game . map , DEFAULTSKIRMISHMAP ) ;
2012-06-20 02:26:54 -07:00
game . hash = levGetMapNameHash ( game . map ) ;
2007-06-28 10:47:08 -07:00
game . maxPlayers = 4 ;
}
2008-03-24 09:51:17 -07:00
ingame . localOptionsReceived = false ;
2007-06-28 10:47:08 -07:00
2006-11-03 13:35:50 -08:00
loadMultiStats ( ( char * ) sPlayer , & nullStats ) ;
2013-01-05 08:02:08 -08:00
}
if ( ! bReenter & & challengeActive )
{
resetReadyStatus ( false ) ;
removeWildcards ( ( char * ) sPlayer ) ;
if ( ! hostCampaign ( ( char * ) game . name , ( char * ) sPlayer ) )
2009-08-11 13:36:44 -07:00
{
2013-01-05 08:02:08 -08:00
debug ( LOG_ERROR , " Failed to host the challenge. " ) ;
return false ;
}
bHosted = true ;
2009-08-11 13:36:44 -07:00
2013-01-05 08:02:08 -08:00
loadMapSettings1 ( ) ;
loadMapSettings2 ( ) ;
2010-01-08 02:58:26 -08:00
2013-01-06 15:40:24 -08:00
WzConfig ini ( sRequestResult , WzConfig : : ReadOnly ) ;
2013-01-05 08:02:08 -08:00
ini . beginGroup ( " challenge " ) ;
sstrcpy ( game . map , ini . value ( " Map " , game . map ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
game . hash = levGetMapNameHash ( game . map ) ;
game . maxPlayers = ini . value ( " MaxPlayers " , game . maxPlayers ) . toInt ( ) ; // TODO, read from map itself, not here!!
game . scavengers = ini . value ( " Scavengers " , game . scavengers ) . toBool ( ) ;
game . alliance = ALLIANCES_TEAMS ;
netPlayersUpdated = true ;
mapDownloadProgress = 100 ;
2013-05-05 04:34:59 -07:00
game . power = ini . value ( " powerLevel " , game . power ) . toInt ( ) ;
2013-01-05 08:02:08 -08:00
game . base = ini . value ( " Bases " , game . base + 1 ) . toInt ( ) - 1 ; // count from 1 like the humans do
sstrcpy ( game . name , ini . value ( " name " ) . toString ( ) . toUtf8 ( ) . constData ( ) ) ;
locked . position = ini . value ( " AllowPositionChange " , locked . position ) . toBool ( ) ;
ini . endGroup ( ) ;
2009-08-11 13:36:44 -07:00
2013-01-05 08:02:08 -08:00
ingame . localOptionsReceived = true ;
addGameOptions ( ) ; // update game options box.
addChatBox ( ) ;
disableMultiButs ( ) ;
addPlayerBox ( true ) ;
}
else
{
addPlayerBox ( false ) ; // Players
addGameOptions ( ) ;
addChatBox ( ) ;
2013-10-27 20:42:37 -07:00
2013-10-31 12:35:09 -07:00
if ( ingame . bHostSetup )
2013-10-27 18:15:49 -07:00
{
2013-10-31 12:35:09 -07:00
char buf [ 512 ] = { ' \0 ' } ;
if ( NetPlay . bComms )
2013-10-27 20:42:37 -07:00
{
2013-10-31 12:35:09 -07:00
if ( NetPlay . isUPNP )
{
2013-11-01 19:48:12 -07:00
if ( NetPlay . isUPNP_CONFIGURED )
2013-11-01 19:09:42 -07:00
{
2013-11-01 19:48:12 -07:00
ssprintf ( buf , _ ( " UPnP has been enabled. " ) ) ;
2013-11-01 19:09:42 -07:00
}
else
{
2013-11-01 19:48:12 -07:00
if ( NetPlay . isUPNP_ERROR )
{
ssprintf ( buf , _ ( " UPnP detection faled. You must manually configure router yourself. " ) ) ;
}
else
{
ssprintf ( buf , _ ( " UPnP detection is in progress... " ) ) ;
}
2013-11-01 19:09:42 -07:00
}
2013-10-31 12:35:09 -07:00
addConsoleMessage ( buf , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
}
else
{
ssprintf ( buf , _ ( " UPnP detection disabled by user. Autoconfig of port 2100 will not happen. " ) ) ;
addConsoleMessage ( buf , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
}
2013-10-27 20:42:37 -07:00
}
2013-11-19 19:18:46 -08:00
if ( challengeActive )
{
ssprintf ( buf , _ ( " Hit the ready box to begin your challenge! " ) ) ;
2013-10-29 21:11:54 -07:00
}
else
{
2013-11-19 19:18:46 -08:00
ssprintf ( buf , _ ( " Press the start hosting button to begin hosting a game. " ) ) ;
2013-10-29 21:11:54 -07:00
}
2013-10-31 12:35:09 -07:00
addConsoleMessage ( buf , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
2013-10-27 18:15:49 -07:00
}
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
// going back to multiop after setting limits up..
2007-06-28 10:47:08 -07:00
if ( bReenter & & bHosted )
{
disableMultiButs ( ) ;
}
2011-12-04 00:38:34 -08:00
loadMapPreview ( false ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// Drawing functions
2013-02-26 01:45:50 -08:00
void displayChatEdit ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) - 4 ; // 4 is the magic number.
2007-12-02 08:38:21 -08:00
2008-03-16 05:39:08 -07:00
// draws the line at the bottom of the multiplayer join dialog separating the chat
2007-12-02 08:38:21 -08:00
// box from the input box
2013-02-18 00:05:01 -08:00
iV_Line ( x , y , x + psWidget - > width ( ) , y , WZCOL_MENU_SEPARATOR ) ;
2007-06-28 10:47:08 -07:00
return ;
}
// ////////////////////////////////////////////////////////////////////////////
2013-02-26 01:45:50 -08:00
void displayRemoteGame ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) ;
2012-01-10 18:24:32 -08:00
UDWORD gameID = psWidget - > UserData ;
char tmp [ 80 ] , name [ StringSize ] ;
2007-06-28 10:47:08 -07:00
2012-01-10 18:24:32 -08:00
if ( ( LobbyError ! = ERROR_NOERROR ) & & ( bMultiPlayer & & ! NetPlay . bComms ) )
2009-04-19 11:45:28 -07:00
{
2012-01-10 18:24:32 -08:00
addConsoleMessage ( _ ( " Can't connect to lobby server! " ) , DEFAULT_JUSTIFY , NOTIFY_MESSAGE ) ;
2009-04-19 11:45:28 -07:00
return ;
}
2012-01-10 18:24:32 -08:00
// Draw blue boxes for games (buttons) & headers
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
drawBlueBox ( x , y , GAMES_STATUS_START - 4 , psWidget - > height ( ) ) ;
drawBlueBox ( x , y , GAMES_PLAYERS_START - 4 , psWidget - > height ( ) ) ;
drawBlueBox ( x , y , GAMES_MAPNAME_START - 4 , psWidget - > height ( ) ) ;
2007-06-28 10:47:08 -07:00
//draw game info
2012-01-10 18:24:32 -08:00
iV_SetFont ( font_regular ) ;
2007-06-28 10:47:08 -07:00
2012-03-25 04:00:38 -07:00
int lamp = IMAGE_LAMP_RED ;
int statusStart = IMAGE_NOJOIN ;
bool disableButton = true ;
iV_SetTextColour ( WZCOL_TEXT_DARK ) ;
2012-01-10 18:24:32 -08:00
// As long as they got room, and mods are the same then we proccess the button(s)
2012-03-25 04:00:38 -07:00
if ( NETisCorrectVersion ( NetPlay . games [ gameID ] . game_version_major , NetPlay . games [ gameID ] . game_version_minor ) )
2010-01-03 01:17:55 -08:00
{
2012-03-25 04:00:38 -07:00
if ( strcmp ( NetPlay . games [ gameID ] . modlist , getModList ( ) ) ! = 0 )
2010-01-03 01:17:55 -08:00
{
2012-03-25 04:00:38 -07:00
// If wrong mod loaded.
statusStart = IMAGE_NOJOIN_MOD ;
}
else if ( NetPlay . games [ gameID ] . desc . dwCurrentPlayers > = NetPlay . games [ gameID ] . desc . dwMaxPlayers )
2010-01-03 01:17:55 -08:00
{
2012-03-25 04:00:38 -07:00
// If game is full.
statusStart = IMAGE_NOJOIN_FULL ;
2010-01-03 01:17:55 -08:00
}
else
2012-03-25 04:00:38 -07:00
{
// Game is ok to join!
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
lamp = IMAGE_LAMP_GREEN ;
statusStart = IMAGE_SKIRMISH_OVER ;
disableButton = false ;
if ( NetPlay . games [ gameID ] . privateGame ) // check to see if it is a private game
{
statusStart = IMAGE_LOCKED_NOBG ;
lamp = IMAGE_LAMP_AMBER ;
}
2010-01-03 01:17:55 -08:00
}
2012-01-10 18:24:32 -08:00
2012-03-25 04:00:38 -07:00
ssprintf ( tmp , " %d/%d " , NetPlay . games [ gameID ] . desc . dwCurrentPlayers , NetPlay . games [ gameID ] . desc . dwMaxPlayers ) ;
iV_DrawText ( tmp , x + GAMES_PLAYERS_START + 4 , y + 18 ) ;
2012-01-10 18:24:32 -08:00
// see what host limits are... then draw them.
if ( NetPlay . games [ gameID ] . limits )
{
if ( NetPlay . games [ gameID ] . limits & NO_TANKS )
iV_DrawImage ( FrontImages , IMAGE_NO_TANK , x + GAMES_STATUS_START + 37 , y + 2 ) ;
if ( NetPlay . games [ gameID ] . limits & NO_BORGS )
iV_DrawImage ( FrontImages , IMAGE_NO_CYBORG , x + GAMES_STATUS_START + ( 37 * 2 ) , y + 2 ) ;
if ( NetPlay . games [ gameID ] . limits & NO_VTOLS )
iV_DrawImage ( FrontImages , IMAGE_NO_VTOL , x + GAMES_STATUS_START + ( 37 * 3 ) , y + 2 ) ;
2012-03-25 04:00:38 -07:00
}
2010-01-03 01:17:55 -08:00
}
2012-03-25 04:00:38 -07:00
// Draw type overlay.
iV_DrawImage ( FrontImages , statusStart , x + GAMES_STATUS_START , y + 3 ) ;
iV_DrawImage ( FrontImages , lamp , x - 14 , y + 8 ) ;
if ( disableButton )
{
2012-01-10 18:24:32 -08:00
widgSetButtonState ( psWScreen , psWidget - > id , WBUT_DISABLE ) ;
2010-01-03 01:17:55 -08:00
}
2011-07-17 12:41:06 -07:00
2012-01-10 18:24:32 -08:00
//draw game name, chop when we get a too long name
sstrcpy ( name , NetPlay . games [ gameID ] . name ) ;
2012-01-26 19:09:09 -08:00
// box size in pixels
while ( iV_GetTextWidth ( name ) > ( GAMES_MAPNAME_START - GAMES_GAMENAME_START - 4 ) )
2010-01-03 01:17:55 -08:00
{
2012-01-10 18:24:32 -08:00
name [ strlen ( name ) - 1 ] = ' \0 ' ;
2007-06-28 10:47:08 -07:00
}
2012-01-10 18:24:32 -08:00
iV_DrawText ( name , x + GAMES_GAMENAME_START , y + 12 ) ;
2007-06-28 10:47:08 -07:00
2013-11-20 19:09:40 -08:00
if ( NetPlay . games [ gameID ] . pureMap )
{
iV_SetTextColour ( WZCOL_RED ) ;
}
else
{
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
}
2012-01-10 18:24:32 -08:00
// draw map name, chop when we get a too long name
sstrcpy ( name , NetPlay . games [ gameID ] . mapname ) ;
2012-01-26 19:09:09 -08:00
// box size in pixels
while ( iV_GetTextWidth ( name ) > ( GAMES_PLAYERS_START - GAMES_MAPNAME_START - 4 ) )
2012-01-07 15:52:38 -08:00
{
2012-01-10 18:24:32 -08:00
name [ strlen ( name ) - 1 ] = ' \0 ' ;
2012-01-07 15:52:38 -08:00
}
2012-01-10 18:24:32 -08:00
iV_DrawText ( name , x + GAMES_MAPNAME_START , y + 12 ) ; // map name
2013-11-20 19:09:40 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2012-01-10 18:24:32 -08:00
iV_SetFont ( font_small ) ;
// draw mod name (if any)
2012-01-26 19:09:09 -08:00
if ( strlen ( NetPlay . games [ gameID ] . modlist ) )
{
// FIXME: we really don't have enough space to list all mods
char tmp [ 300 ] ;
sprintf ( tmp , _ ( " Mods: %s " ) , NetPlay . games [ gameID ] . modlist ) ;
tmp [ StringSize ] = ' \0 ' ;
sstrcpy ( name , tmp ) ;
}
else
{
sstrcpy ( name , _ ( " Mods: None! " ) ) ;
}
// box size in pixels
while ( iV_GetTextWidth ( name ) > ( GAMES_PLAYERS_START - GAMES_MAPNAME_START - 8 ) )
{
name [ strlen ( name ) - 1 ] = ' \0 ' ;
}
2012-01-10 18:24:32 -08:00
iV_DrawText ( name , x + GAMES_MODNAME_START , y + 24 ) ;
2007-06-28 10:47:08 -07:00
2012-01-10 18:24:32 -08:00
// draw version string
sprintf ( name , _ ( " Version: %s " ) , NetPlay . games [ gameID ] . versionstring ) ;
2012-01-26 19:09:09 -08:00
// box size in pixels
while ( iV_GetTextWidth ( name ) > ( GAMES_MAPNAME_START - 6 - GAMES_GAMENAME_START - 4 ) )
{
name [ strlen ( name ) - 1 ] = ' \0 ' ;
}
2012-01-10 18:24:32 -08:00
iV_DrawText ( name , x + GAMES_GAMENAME_START + 6 , y + 24 ) ;
// crappy hack to only draw this once for the header. TODO fix GUI
if ( gameID = = 0 )
2007-06-28 10:47:08 -07:00
{
2012-01-10 18:24:32 -08:00
iV_SetTextColour ( WZCOL_YELLOW ) ;
// make the 'header' for the table...
drawBlueBox ( x , y - 12 , GAMES_GAMEWIDTH , 12 ) ;
ssprintf ( tmp , " Game Name " ) ;
iV_DrawText ( tmp , x - 2 + GAMES_GAMENAME_START + 48 , y - 3 ) ;
ssprintf ( tmp , " Map Name " ) ;
iV_DrawText ( tmp , x - 2 + GAMES_MAPNAME_START + 48 , y - 3 ) ;
ssprintf ( tmp , " Players " ) ;
iV_DrawText ( tmp , x - 2 + GAMES_PLAYERS_START , y - 3 ) ;
ssprintf ( tmp , " Status " ) ;
iV_DrawText ( tmp , x - 2 + GAMES_STATUS_START + 48 , y - 3 ) ;
2007-06-28 10:47:08 -07:00
}
}
2013-02-26 01:45:50 -08:00
void displayTeamChooser ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) ;
2007-11-09 13:01:23 -08:00
UDWORD i = psWidget - > UserData ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
ASSERT ( i < MAX_PLAYERS & & NetPlay . players [ i ] . team > = 0 & & NetPlay . players [ i ] . team < MAX_PLAYERS , " Team index out of bounds " ) ;
2007-06-28 10:47:08 -07:00
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2007-06-28 10:47:08 -07:00
2011-01-15 04:29:23 -08:00
if ( game . skDiff [ i ] )
{
iV_DrawImage ( FrontImages , IMAGE_TEAM0 + NetPlay . players [ i ] . team , x + 2 , y + 8 ) ;
}
2006-09-26 11:14:05 -07:00
}
2006-05-27 09:37:17 -07:00
2013-02-26 01:45:50 -08:00
void displayPosition ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2011-01-04 09:51:15 -08:00
{
2013-02-18 00:05:01 -08:00
const int x = xOffset + psWidget - > x ( ) ;
const int y = yOffset + psWidget - > y ( ) ;
2011-01-18 13:42:29 -08:00
const int i = psWidget - > UserData ;
char text [ 80 ] ;
2006-05-27 09:37:17 -07:00
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2011-01-04 09:51:15 -08:00
iV_SetFont ( font_regular ) ;
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2011-05-21 12:59:46 -07:00
ssprintf ( text , _ ( " Click to take player slot %d " ) , NetPlay . players [ i ] . position ) ;
2011-01-18 13:42:29 -08:00
iV_DrawText ( text , x + 10 , y + 22 ) ;
2007-06-28 10:47:08 -07:00
}
2013-02-26 01:45:50 -08:00
static void displayAi ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2006-09-26 11:14:05 -07:00
{
2013-02-18 00:05:01 -08:00
const int x = xOffset + psWidget - > x ( ) ;
const int y = yOffset + psWidget - > y ( ) ;
2011-01-09 07:35:49 -08:00
const int j = psWidget - > UserData ;
2011-05-21 12:59:46 -07:00
const char * commsText [ ] = { N_ ( " Open " ) , N_ ( " Closed " ) } ;
2011-01-09 07:35:49 -08:00
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2011-01-09 07:35:49 -08:00
iV_SetFont ( font_regular ) ;
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2011-05-21 12:59:46 -07:00
iV_DrawText ( ( j > = 0 ) ? aidata [ j ] . name : gettext ( commsText [ j + 2 ] ) , x + 10 , y + 22 ) ;
2011-01-09 07:35:49 -08:00
}
2006-09-26 11:14:05 -07:00
2011-01-09 07:35:49 -08:00
static int difficultyIcon ( int difficulty )
{
switch ( difficulty )
2006-09-26 11:14:05 -07:00
{
2011-01-09 07:35:49 -08:00
case 0 : return IMAGE_EASY ;
case 1 : return IMAGE_MEDIUM ;
case 2 : return IMAGE_HARD ;
case 3 : return IMAGE_INSANE ;
default : return IMAGE_NO ; /// what??
2006-09-26 11:14:05 -07:00
}
2011-01-09 07:35:49 -08:00
}
2006-09-26 11:14:05 -07:00
2013-02-26 01:45:50 -08:00
static void displayDifficulty ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2011-01-09 07:35:49 -08:00
{
2013-02-18 00:05:01 -08:00
const int x = xOffset + psWidget - > x ( ) ;
const int y = yOffset + psWidget - > y ( ) ;
2011-01-09 07:35:49 -08:00
const int j = psWidget - > UserData ;
2006-09-26 11:14:05 -07:00
2011-01-09 07:35:49 -08:00
ASSERT_OR_RETURN ( , j < ARRAY_SIZE ( difficultyList ) , " Bad difficulty found: %d " , j ) ;
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2011-01-09 07:35:49 -08:00
iV_SetFont ( font_regular ) ;
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2011-01-09 07:35:49 -08:00
iV_DrawImage ( FrontImages , difficultyIcon ( j ) , x + 5 , y + 5 ) ;
2011-05-21 12:59:46 -07:00
iV_DrawText ( gettext ( difficultyList [ j ] ) , x + 42 , y + 22 ) ;
2006-09-26 11:14:05 -07:00
}
2013-06-03 14:13:36 -07:00
static bool isKnownPlayer ( std : : map < std : : string , EcKey : : Key > const & knownPlayers , std : : string const & name , EcKey const & key )
{
if ( key . empty ( ) )
{
return false ;
}
std : : map < std : : string , EcKey : : Key > : : const_iterator i = knownPlayers . find ( name ) ;
return i ! = knownPlayers . end ( ) & & key . toBytes ( EcKey : : Public ) = = i - > second ;
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////////
2013-02-26 01:45:50 -08:00
void displayPlayer ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) ;
2009-06-07 11:10:13 -07:00
UDWORD j = psWidget - > UserData , eval ;
2007-06-28 10:47:08 -07:00
2011-01-18 14:41:09 -08:00
const int nameX = 32 ;
2007-06-28 10:47:08 -07:00
//bluboxes.
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2010-02-16 21:08:31 -08:00
if ( NetPlay . isHost & & NetPlay . players [ j ] . wzFile . isSending )
{
static char mapProgressString [ MAX_STR_LENGTH ] = { ' \0 ' } ;
int progress = ( NetPlay . players [ j ] . wzFile . currPos * 100 ) / NetPlay . players [ j ] . wzFile . fileSize_32 ;
2007-06-28 10:47:08 -07:00
2010-02-16 21:08:31 -08:00
snprintf ( mapProgressString , MAX_STR_LENGTH , _ ( " Sending Map: %d%% " ) , progress ) ;
iV_SetFont ( font_regular ) ; // font
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2010-02-16 21:08:31 -08:00
iV_DrawText ( mapProgressString , x + 15 , y + 22 ) ;
}
else if ( mapDownloadProgress ! = 100 & & j = = selectedPlayer )
2009-12-03 21:50:40 -08:00
{
static char mapProgressString [ MAX_STR_LENGTH ] = { ' \0 ' } ;
snprintf ( mapProgressString , MAX_STR_LENGTH , _ ( " Map: %d%% downloaded " ) , mapDownloadProgress ) ;
iV_SetFont ( font_regular ) ; // font
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2009-12-03 21:50:40 -08:00
iV_DrawText ( mapProgressString , x + 5 , y + 22 ) ;
return ;
}
else if ( ingame . localOptionsReceived & & NetPlay . players [ j ] . allocated ) // only draw if real player!
2007-06-28 10:47:08 -07:00
{
2013-06-03 14:13:36 -07:00
std : : string name = NetPlay . players [ j ] . name ;
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
iV_SetFont ( font_regular ) ; // font
2013-06-03 14:13:36 -07:00
std : : map < std : : string , EcKey : : Key > serverPlayers ; // TODO Fill this with players known to the server (needs implementing on the server, too). Currently useless.
if ( ingame . PingTimes [ j ] > = PING_LIMIT )
{
iV_SetTextColour ( WZCOL_FORM_PLAYER_NOPING ) ;
}
else if ( isKnownPlayer ( serverPlayers , name , getMultiStats ( j ) . identity ) )
{
iV_SetTextColour ( WZCOL_FORM_PLAYER_KNOWN_BY_SERVER ) ;
}
else if ( isKnownPlayer ( getKnownPlayers ( ) , name , getMultiStats ( j ) . identity ) )
{
iV_SetTextColour ( WZCOL_FORM_PLAYER_KNOWN ) ;
}
else
{
iV_SetTextColour ( WZCOL_FORM_PLAYER_UNKNOWN ) ;
}
2007-06-28 10:47:08 -07:00
// name
2013-02-18 00:05:01 -08:00
if ( iV_GetTextWidth ( name . c_str ( ) ) > psWidget - > width ( ) - nameX )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
while ( ! name . empty ( ) & & iV_GetTextWidth ( ( name + " ... " ) . c_str ( ) ) > psWidget - > width ( ) - nameX )
2011-01-18 14:41:09 -08:00
{
name . resize ( name . size ( ) - 1 ) ; // Clip name.
}
name + = " ... " ;
2007-06-28 10:47:08 -07:00
}
2011-02-24 14:15:57 -08:00
std : : string subText ;
2010-01-18 13:52:03 -08:00
if ( j = = NET_HOST_ONLY & & NetPlay . bComms )
{
2011-02-24 14:15:57 -08:00
subText + = _ ( " HOST " ) ;
2010-01-18 13:52:03 -08:00
}
2011-02-24 14:15:57 -08:00
if ( NetPlay . bComms & & j ! = selectedPlayer )
2010-08-29 18:48:55 -07:00
{
char buf [ 250 ] = { ' \0 ' } ;
// show "actual" ping time
2012-05-21 04:33:45 -07:00
ssprintf ( buf , " %s%s: " , subText . empty ( ) ? " " : " , " , _ ( " Ping " ) ) ;
subText + = buf ;
if ( ingame . PingTimes [ j ] < PING_LIMIT )
{
ssprintf ( buf , " %03d " , ingame . PingTimes [ j ] ) ;
}
else
{
ssprintf ( buf , " ∞ " ) ; // Player has ping of somewhat questionable quality.
}
2011-02-24 14:15:57 -08:00
subText + = buf ;
}
iV_DrawText ( name . c_str ( ) , x + nameX , y + ( subText . empty ( ) ? 22 : 18 ) ) ;
if ( ! subText . empty ( ) )
{
2010-08-29 18:48:55 -07:00
iV_SetFont ( font_small ) ;
iV_SetTextColour ( WZCOL_TEXT_MEDIUM ) ;
2011-02-24 14:15:57 -08:00
iV_DrawText ( subText . c_str ( ) , x + nameX , y + 28 ) ;
2010-08-29 18:48:55 -07:00
iV_SetFont ( font_regular ) ;
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2010-01-18 13:52:03 -08:00
}
2011-07-17 12:41:06 -07:00
2013-01-05 01:55:06 -08:00
PLAYERSTATS stat = getMultiStats ( j ) ;
if ( stat . wins + stat . losses < 5 )
2007-06-28 10:47:08 -07:00
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MEDAL_DUMMY , x + 4 , y + 13 ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2012-03-14 10:50:31 -07:00
PLAYERSTATS stat = getMultiStats ( j ) ;
2007-06-28 10:47:08 -07:00
// star 1 total droid kills
eval = stat . totalKills ;
if ( eval > 600 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK1 , x + 4 , y + 3 ) ;
2007-06-28 10:47:08 -07:00
}
else if ( eval > 300 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK2 , x + 4 , y + 3 ) ;
2007-06-28 10:47:08 -07:00
}
else if ( eval > 150 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK3 , x + 4 , y + 3 ) ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2013-01-05 01:55:06 -08:00
// star 2 games played (Cannot use stat.played, since that's just the number of times the player exited via the game menu, not the number of games played.)
eval = stat . wins + stat . losses ;
2007-06-28 10:47:08 -07:00
if ( eval > 200 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK1 , x + 4 , y + 13 ) ;
2007-06-28 10:47:08 -07:00
}
else if ( eval > 100 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK2 , x + 4 , y + 13 ) ;
2007-06-28 10:47:08 -07:00
}
else if ( eval > 50 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK3 , x + 4 , y + 13 ) ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
// star 3 games won.
eval = stat . wins ;
if ( eval > 80 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK1 , x + 4 , y + 23 ) ;
2007-06-28 10:47:08 -07:00
}
else if ( eval > 40 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK2 , x + 4 , y + 23 ) ;
2007-06-28 10:47:08 -07:00
}
else if ( eval > 10 )
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MULTIRANK3 , x + 4 , y + 23 ) ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
// medals.
2009-04-22 17:06:16 -07:00
if ( ( stat . wins > = 6 ) & & ( stat . wins > ( 2 * stat . losses ) ) ) // bronze requirement.
2007-06-28 10:47:08 -07:00
{
2009-04-22 17:06:16 -07:00
if ( ( stat . wins > = 12 ) & & ( stat . wins > ( 4 * stat . losses ) ) ) // silver requirement.
2007-06-28 10:47:08 -07:00
{
2009-04-22 17:06:16 -07:00
if ( ( stat . wins > = 24 ) & & ( stat . wins > ( 8 * stat . losses ) ) ) // gold requirement
2007-06-28 10:47:08 -07:00
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MEDAL_GOLD , x + 16 , y + 11 ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MEDAL_SILVER , x + 16 , y + 11 ) ;
2007-06-28 10:47:08 -07:00
}
}
else
{
2011-01-04 09:51:15 -08:00
iV_DrawImage ( FrontImages , IMAGE_MEDAL_BRONZE , x + 16 , y + 11 ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2009-11-28 23:24:22 -08:00
game . skDiff [ j ] = UBYTE_MAX ; // set AI difficulty to 0xFF (i.e. not an AI)
2007-06-28 10:47:08 -07:00
}
2011-01-04 09:51:15 -08:00
else // AI
2007-06-28 10:47:08 -07:00
{
2011-01-09 07:35:49 -08:00
char aitext [ 80 ] ;
2009-11-26 10:33:03 -08:00
2011-01-09 07:35:49 -08:00
if ( NetPlay . players [ j ] . ai > = 0 )
2010-02-16 21:08:31 -08:00
{
2011-01-09 07:35:49 -08:00
iV_DrawImage ( FrontImages , IMAGE_PLAYER_PC , x , y + 11 ) ;
2009-11-26 10:33:03 -08:00
}
2011-01-09 07:35:49 -08:00
iV_SetFont ( font_regular ) ;
2011-02-06 13:41:27 -08:00
iV_SetTextColour ( WZCOL_FORM_TEXT ) ;
2011-01-15 04:29:23 -08:00
ASSERT_OR_RETURN ( , NetPlay . players [ j ] . ai < ( int ) aidata . size ( ) , " Uh-oh, AI index out of bounds " ) ;
switch ( NetPlay . players [ j ] . ai )
{
2011-05-21 12:59:46 -07:00
case AI_OPEN : sstrcpy ( aitext , _ ( " Open " ) ) ; break ;
case AI_CLOSED : sstrcpy ( aitext , _ ( " Closed " ) ) ; break ;
2012-03-17 01:30:02 -07:00
default : sstrcpy ( aitext , nameOverrides [ j ] [ 0 ] = = ' \0 ' ? NetPlay . isHost ? aidata [ NetPlay . players [ j ] . ai ] . name : NetPlay . players [ j ] . name : nameOverrides [ j ] ) ; break ;
2011-01-15 04:29:23 -08:00
}
2011-01-18 14:41:09 -08:00
iV_DrawText ( aitext , x + nameX , y + 22 ) ;
2007-06-28 10:47:08 -07:00
}
}
2013-02-26 01:45:50 -08:00
void displayColour ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2011-01-04 09:51:15 -08:00
{
2013-02-18 00:05:01 -08:00
const int x = xOffset + psWidget - > x ( ) ;
const int y = yOffset + psWidget - > y ( ) ;
2011-01-04 09:51:15 -08:00
const int j = psWidget - > UserData ;
2007-06-28 10:47:08 -07:00
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2011-01-04 09:51:15 -08:00
if ( ! NetPlay . players [ j ] . wzFile . isSending & & game . skDiff [ j ] )
{
int player = getPlayerColour ( j ) ;
2011-01-03 09:16:54 -08:00
STATIC_ASSERT ( MAX_PLAYERS < = 16 ) ;
2011-03-17 12:44:34 -07:00
iV_DrawImageTc ( FrontImages , IMAGE_PLAYERN , IMAGE_PLAYERN_TC , x + 7 , y + 9 , pal_GetTeamColour ( player ) ) ;
2007-06-28 10:47:08 -07:00
}
}
// ////////////////////////////////////////////////////////////////////////////
// Display blue box
2013-02-26 01:45:50 -08:00
void intDisplayFeBox ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) ;
int w = psWidget - > width ( ) ;
int h = psWidget - > height ( ) ;
2007-06-28 10:47:08 -07:00
drawBlueBox ( x , y , w , h ) ;
}
// ////////////////////////////////////////////////////////////////////////////
// Display edit box
2013-02-26 01:45:50 -08:00
void displayMultiEditBox ( WIDGET * psWidget , UDWORD xOffset , UDWORD yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-18 00:05:01 -08:00
int x = xOffset + psWidget - > x ( ) ;
int y = yOffset + psWidget - > y ( ) ;
2007-06-28 10:47:08 -07:00
2013-02-18 00:05:01 -08:00
drawBlueBox ( x , y , psWidget - > width ( ) , psWidget - > height ( ) ) ;
2007-06-28 10:47:08 -07:00
if ( ( ( W_EDITBOX * ) psWidget ) - > state & WEDBS_DISABLE ) // disabled
2006-05-27 09:37:17 -07:00
{
2007-11-25 13:15:08 -08:00
PIELIGHT colour ;
2007-06-28 10:47:08 -07:00
2007-11-25 13:15:08 -08:00
colour . byte . r = FILLRED ;
colour . byte . b = FILLBLUE ;
colour . byte . g = FILLGREEN ;
colour . byte . a = FILLTRANS ;
2013-02-18 00:05:01 -08:00
pie_UniTransBoxFill ( x , y , x + psWidget - > width ( ) + psWidget - > height ( ) , y + psWidget - > height ( ) , colour ) ;
2007-11-25 13:15:08 -08:00
}
2007-06-28 10:47:08 -07:00
}
2013-02-25 10:25:05 -08:00
static Image getFrontHighlightImage ( Image image )
2007-06-28 10:47:08 -07:00
{
2013-02-25 10:25:05 -08:00
if ( image . isNull ( ) )
{
return Image ( ) ;
}
switch ( image . width ( ) )
{
case 30 : return Image ( FrontImages , IMAGE_HI34 ) ;
case 60 : return Image ( FrontImages , IMAGE_HI64 ) ;
case 19 : return Image ( FrontImages , IMAGE_HI23 ) ;
case 27 : return Image ( FrontImages , IMAGE_HI31 ) ;
case 35 : return Image ( FrontImages , IMAGE_HI39 ) ;
case 37 : return Image ( FrontImages , IMAGE_HI41 ) ;
case 56 : return Image ( FrontImages , IMAGE_HI56 ) ;
}
return Image ( ) ;
}
2013-02-26 01:45:50 -08:00
void WzMultiButton : : display ( int xOffset , int yOffset )
2007-06-28 10:47:08 -07:00
{
2013-02-20 00:50:21 -08:00
int x0 = xOffset + x ( ) ;
int y0 = yOffset + y ( ) ;
Image hiToUse ( NULL , 0 ) ;
2008-04-18 10:05:40 -07:00
2009-04-19 11:45:28 -07:00
// FIXME: This seems to be a way to conserve space, so you can use a
// transparent icon with these edit boxes.
2008-04-18 12:45:10 -07:00
// hack for multieditbox
2013-02-20 00:50:21 -08:00
if ( imNormal . id = = IMAGE_EDIT_MAP | | imNormal . id = = IMAGE_EDIT_GAME | | imNormal . id = = IMAGE_EDIT_PLAYER
| | imNormal . id = = IMAGE_LOCK_BLUE | | imNormal . id = = IMAGE_UNLOCK_BLUE )
2008-04-18 12:45:10 -07:00
{
2013-02-20 00:50:21 -08:00
drawBlueBox ( x0 - 2 , y0 - 2 , height ( ) , height ( ) ) ; // box on end.
2008-04-18 12:45:10 -07:00
}
2008-04-18 10:05:40 -07:00
// evaluate auto-frame
2013-02-20 00:50:21 -08:00
bool highlight = ( getState ( ) & WBUT_HIGHLIGHT ) ! = 0 ;
2006-05-27 09:37:17 -07:00
2008-04-18 10:05:40 -07:00
// evaluate auto-frame
2013-02-20 00:50:21 -08:00
if ( doHighlight = = 1 & & highlight )
2007-06-28 10:47:08 -07:00
{
2013-02-25 10:25:05 -08:00
hiToUse = getFrontHighlightImage ( imNormal ) ;
2007-06-28 10:47:08 -07:00
}
2013-02-20 00:50:21 -08:00
bool down = ( getState ( ) & ( WBUT_DOWN | WBUT_LOCK | WBUT_CLICKLOCK ) ) ! = 0 ;
bool grey = ( getState ( ) & WBUT_DISABLE ) ! = 0 ;
2008-04-20 09:33:32 -07:00
2013-02-20 00:50:21 -08:00
Image toDraw [ 3 ] ;
2011-03-17 12:44:34 -07:00
int numToDraw = 0 ;
2007-06-28 10:47:08 -07:00
// now display
2013-02-20 00:50:21 -08:00
toDraw [ numToDraw + + ] = imNormal ;
2007-06-28 10:47:08 -07:00
// hilights etc..
2013-02-20 00:50:21 -08:00
if ( down )
2007-06-28 10:47:08 -07:00
{
2013-02-20 00:50:21 -08:00
toDraw [ numToDraw + + ] = imDown ;
2011-03-17 12:44:34 -07:00
}
2013-02-20 00:50:21 -08:00
if ( highlight & & ! grey & & hiToUse . images ! = NULL )
2011-03-17 12:44:34 -07:00
{
toDraw [ numToDraw + + ] = hiToUse ;
}
for ( int n = 0 ; n < numToDraw ; + + n )
{
2013-02-20 00:50:21 -08:00
Image tcImage ( toDraw [ n ] . images , toDraw [ n ] . id + 1 ) ;
2011-03-17 12:44:34 -07:00
if ( tc = = MAX_PLAYERS )
2006-05-27 09:37:17 -07:00
{
2013-02-20 00:50:21 -08:00
iV_DrawImage ( toDraw [ n ] , x0 , y0 ) ;
2007-06-28 10:47:08 -07:00
}
2012-02-14 13:18:35 -08:00
else if ( tc = = MAX_PLAYERS + 1 )
{
const int scale = 4000 ;
int f = realTime % scale ;
PIELIGHT mix ;
mix . byte . r = 128 + iSinR ( 65536 * f / scale + 65536 * 0 / 3 , 127 ) ;
mix . byte . g = 128 + iSinR ( 65536 * f / scale + 65536 * 1 / 3 , 127 ) ;
mix . byte . b = 128 + iSinR ( 65536 * f / scale + 65536 * 2 / 3 , 127 ) ;
mix . byte . a = 255 ;
2013-02-20 00:50:21 -08:00
iV_DrawImageTc ( toDraw [ n ] , tcImage , x0 , y0 , mix ) ;
2012-02-14 13:18:35 -08:00
}
2011-03-17 12:44:34 -07:00
else
2007-06-28 10:47:08 -07:00
{
2013-02-20 00:50:21 -08:00
iV_DrawImageTc ( toDraw [ n ] , tcImage , x0 , y0 , pal_GetTeamColour ( tc ) ) ;
2007-06-28 10:47:08 -07:00
}
}
2013-02-20 00:50:21 -08:00
if ( grey )
2008-04-18 10:05:40 -07:00
{
2007-06-28 10:47:08 -07:00
// disabled, render something over it!
2013-02-20 00:50:21 -08:00
iV_TransBoxFill ( x0 , y0 , x0 + width ( ) , y0 + height ( ) ) ;
2007-06-28 10:47:08 -07:00
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// common widgets
2011-03-12 17:32:15 -08:00
static bool addMultiEditBox ( UDWORD formid , UDWORD id , UDWORD x , UDWORD y , char const * tip , char const * tipres , UDWORD icon , UDWORD iconhi , UDWORD iconid )
2007-06-28 10:47:08 -07:00
{
2010-12-22 06:02:14 -08:00
W_EDBINIT sEdInit ; // editbox
2007-06-28 10:47:08 -07:00
sEdInit . formID = formid ;
sEdInit . id = id ;
sEdInit . x = ( short ) x ;
sEdInit . y = ( short ) y ;
sEdInit . width = MULTIOP_EDITBOXW ;
sEdInit . height = MULTIOP_EDITBOXH ;
sEdInit . pText = tipres ;
sEdInit . pBoxDisplay = displayMultiEditBox ;
if ( ! widgAddEditBox ( psWScreen , & sEdInit ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2008-04-18 12:45:10 -07:00
addMultiBut ( psWScreen , MULTIOP_OPTIONS , iconid , x + MULTIOP_EDITBOXW + 2 , y + 2 , MULTIOP_EDITBOXH , MULTIOP_EDITBOXH , tip , icon , iconhi , iconhi ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
/////////////////////////////////////////////////////////////////////////////////////////
2011-03-17 12:44:34 -07:00
bool addMultiBut ( W_SCREEN * screen , UDWORD formid , UDWORD id , UDWORD x , UDWORD y , UDWORD width , UDWORD height , const char * tipres , UDWORD norm , UDWORD down , UDWORD hi , unsigned tc )
2007-06-28 10:47:08 -07:00
{
2013-02-20 00:50:21 -08:00
WzMultiButton * button = new WzMultiButton ( widgGetFromID ( screen , formid ) ) ;
button - > id = id ;
button - > setGeometry ( x , y , width , height ) ;
button - > setTip ( QString : : fromUtf8 ( tipres ) ) ;
button - > imNormal = Image ( FrontImages , norm ) ;
button - > imDown = Image ( FrontImages , down ) ;
button - > doHighlight = hi ;
button - > tc = tc ;
return true ;
2006-09-26 11:14:05 -07:00
}
2008-04-09 13:05:09 -07:00
/* 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
2013-06-03 14:13:36 -07:00
if ( NetPlay . players [ player ] . allocated & & ( ! NetPlay . players [ player ] . ready | | ingame . PingTimes [ player ] > = PING_LIMIT ) )
2008-04-09 13:05:09 -07:00
{
if ( bNotifyStatus )
{
2009-06-07 11:10:13 -07:00
for ( playerID = 0 ; playerID < = game . maxPlayers & & playerID ! = player ; playerID + + ) ;
2008-04-09 13:05:09 -07:00
console ( " %s is not ready " , getPlayerName ( playerID ) ) ;
}
bReady = false ;
}
}
return bReady ;
}