2007-06-06 22:29:40 +03:00
// CMT.cpp : Defines the entry point for the console application.
//
2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2008-12-21 21:17:35 +02:00
# include <SDL_mixer.h>
2013-04-07 14:52:07 +03:00
# include "gui/SDL_Extensions.h"
2008-08-04 18:56:36 +03:00
# include "CGameInfo.h"
2010-04-06 11:59:24 +03:00
# include "mapHandler.h"
2011-12-14 00:23:17 +03:00
2013-07-28 17:49:50 +03:00
# include "../lib/filesystem/Filesystem.h"
2016-01-16 20:00:53 +02:00
# include "../lib/filesystem/FileStream.h"
2008-08-04 18:56:36 +03:00
# include "CPreGame.h"
2014-07-13 20:53:37 +03:00
# include "windows/CCastleInterface.h"
2011-12-14 00:23:17 +03:00
# include "../lib/CConsoleHandler.h"
2013-04-07 14:52:07 +03:00
# include "gui/CCursorHandler.h"
2009-05-20 13:08:56 +03:00
# include "../lib/CGameState.h"
# include "../CCallback.h"
2007-11-19 00:58:28 +02:00
# include "CPlayerInterface.h"
2014-07-13 20:53:37 +03:00
# include "windows/CAdvmapInterface.h"
2010-12-20 23:22:53 +02:00
# include "../lib/CBuildingHandler.h"
# include "CVideoHandler.h"
# include "../lib/CHeroHandler.h"
# include "../lib/CCreatureHandler.h"
2015-02-02 10:25:26 +02:00
# include "../lib/spells/CSpellHandler.h"
2010-12-20 23:22:53 +02:00
# include "CMusicHandler.h"
# include "CVideoHandler.h"
# include "CDefHandler.h"
# include "../lib/CGeneralTextHandler.h"
2009-05-20 13:08:56 +03:00
# include "Graphics.h"
# include "Client.h"
2012-09-29 13:59:43 +03:00
# include "../lib/CConfigHandler.h"
2009-05-20 13:08:56 +03:00
# include "../lib/Connection.h"
# include "../lib/VCMI_Lib.h"
2009-10-10 08:47:59 +03:00
# include "../lib/VCMIDirs.h"
2009-05-20 13:08:56 +03:00
# include "../lib/NetPacks.h"
2010-02-08 16:38:06 +02:00
# include "CMessage.h"
2012-09-21 22:49:35 +03:00
# include "../lib/CModHandler.h"
2013-04-20 21:44:55 +03:00
# include "../lib/CTownHandler.h"
2011-01-15 04:17:56 +02:00
# include "../lib/CArtHandler.h"
2011-06-20 14:41:04 +03:00
# include "../lib/CScriptingModule.h"
2011-12-14 00:23:17 +03:00
# include "../lib/GameConstants.h"
2013-04-07 14:52:07 +03:00
# include "gui/CGuiHandler.h"
2013-04-09 17:31:36 +03:00
# include "../lib/logging/CBasicLogConfigurator.h"
2014-07-15 10:14:49 +03:00
# include "../lib/CondSh.h"
2016-02-24 21:26:39 +02:00
# include "../lib/StringConstants.h"
# include "../lib/CPlayerState.h"
2009-12-03 06:01:14 +02:00
2014-08-26 13:19:04 +03:00
# ifdef VCMI_WINDOWS
2009-11-28 19:21:54 +02:00
# include "SDL_syswm.h"
2009-12-03 06:01:14 +02:00
# endif
2012-02-20 00:03:43 +03:00
# include "../lib/UnlockGuard.h"
2013-06-17 18:45:55 +03:00
# include "CMT.h"
2008-12-21 21:17:35 +02:00
2009-02-08 17:39:26 +02:00
# if __MINGW32__
# undef main
# endif
2009-04-15 17:03:31 +03:00
2010-12-22 22:14:40 +02:00
namespace po = boost : : program_options ;
2014-08-11 00:42:39 +03:00
namespace bfs = boost : : filesystem ;
2010-12-22 22:14:40 +02:00
2009-04-15 17:03:31 +03:00
/*
* CMT . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2009-07-31 23:10:22 +03:00
std : : string NAME_AFFIX = " client " ;
2011-12-14 00:23:17 +03:00
std : : string NAME = GameConstants : : VCMI_VERSION + std : : string ( " ( " ) + NAME_AFFIX + ' ) ' ; //application name
2009-08-07 01:36:51 +03:00
CGuiHandler GH ;
2013-06-26 14:18:27 +03:00
static CClient * client = nullptr ;
2014-05-21 19:04:34 +03:00
2014-05-24 15:14:37 +03:00
int preferredDriverIndex = - 1 ;
2014-05-21 19:04:34 +03:00
SDL_Window * mainWindow = nullptr ;
SDL_Renderer * mainRenderer = nullptr ;
2014-05-23 14:42:27 +03:00
SDL_Texture * screenTexture = nullptr ;
2014-05-21 19:04:34 +03:00
2014-06-01 19:50:19 +03:00
extern boost : : thread_specific_ptr < bool > inGuiThread ;
2013-06-26 14:18:27 +03:00
SDL_Surface * screen = nullptr , //main screen surface
2014-08-11 00:42:39 +03:00
* screen2 = nullptr , //and hlp surface (used to store not-active interfaces layer)
2009-05-25 02:21:55 +03:00
* screenBuf = screen ; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
2016-01-18 15:05:43 +02:00
2012-09-11 17:25:19 +03:00
std : : queue < SDL_Event > events ;
2008-08-04 18:56:36 +03:00
boost : : mutex eventsM ;
2009-04-11 04:32:50 +03:00
2013-06-17 18:45:55 +03:00
bool gNoGUI = false ;
2013-06-21 23:59:32 +03:00
static po : : variables_map vm ;
2012-05-18 20:35:46 +03:00
//static bool setResolution = false; //set by event handling thread after resolution is adjusted
2009-04-11 04:32:50 +03:00
2011-06-11 02:50:32 +03:00
static bool ermInteractiveMode = false ; //structurize when time is right
2009-08-17 11:50:31 +03:00
void processCommand ( const std : : string & message ) ;
2012-02-24 23:41:14 +03:00
static void setScreenRes ( int w , int h , int bpp , bool fullscreen , bool resetVideo = true ) ;
2009-06-23 11:14:49 +03:00
void dispose ( ) ;
2009-06-24 09:56:36 +03:00
void playIntro ( ) ;
2014-06-01 18:31:37 +03:00
static void mainLoop ( ) ;
2012-05-18 20:35:46 +03:00
//void requestChangingResolution();
2013-06-26 14:18:27 +03:00
void startGame ( StartInfo * options , CConnection * serv = nullptr ) ;
2013-12-17 15:12:25 +03:00
void endGame ( ) ;
2009-06-24 09:56:36 +03:00
2014-08-26 13:19:04 +03:00
# ifndef VCMI_WINDOWS
2010-04-04 01:06:50 +03:00
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
# include <getopt.h>
# endif
2014-08-11 00:42:39 +03:00
void startGameFromFile ( const bfs : : path & fname )
2012-01-03 04:55:26 +03:00
{
2013-05-19 18:14:23 +03:00
StartInfo si ;
try //attempt retrieving start info from given file
2012-01-03 04:55:26 +03:00
{
2014-08-11 00:42:39 +03:00
if ( fname . empty ( ) | | ! bfs : : exists ( fname ) )
throw std : : runtime_error ( " Startfile \" " + fname . string ( ) + " \" does not exist! " ) ;
2013-05-19 18:14:23 +03:00
2012-01-03 04:55:26 +03:00
CLoadFile out ( fname ) ;
2014-08-11 00:42:39 +03:00
if ( ! out . sfile | | ! * out . sfile )
throw std : : runtime_error ( " Cannot read from startfile \" " + fname . string ( ) + " \" ! " ) ;
2012-01-03 04:55:26 +03:00
out > > si ;
}
2013-05-19 18:14:23 +03:00
catch ( std : : exception & e )
{
2014-08-11 00:42:39 +03:00
logGlobal - > errorStream ( ) < < " Failed to start from the file: " < < fname < < " . Error: " < < e . what ( )
2013-05-19 18:14:23 +03:00
< < " Falling back to main menu. " ;
GH . curInt = CGPreGame : : create ( ) ;
return ;
}
while ( GH . topInt ( ) )
GH . popIntTotally ( GH . topInt ( ) ) ;
startGame ( & si ) ;
2012-01-03 04:55:26 +03:00
}
2009-06-24 09:56:36 +03:00
void init ( )
{
2011-12-17 21:59:59 +03:00
CStopWatch tmh , pomtime ;
2009-06-24 09:56:36 +03:00
2012-12-12 14:13:57 +03:00
loadDLLClasses ( ) ;
2010-12-19 00:11:28 +02:00
const_cast < CGameInfo * > ( CGI ) - > setFromLib ( ) ;
2014-03-10 19:00:58 +03:00
2016-03-12 03:41:27 +02:00
logGlobal - > infoStream ( ) < < " Initializing VCMI_Lib: " < < tmh . getDiff ( ) ;
2009-06-24 09:56:36 +03:00
2014-07-03 11:26:15 +03:00
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
2014-07-03 11:26:15 +03:00
pomtime . getDiff ( ) ;
2013-06-17 18:45:55 +03:00
CCS - > curh = new CCursorHandler ;
graphics = new Graphics ( ) ; // should be before curh->init()
2013-04-22 22:51:22 +03:00
2013-06-17 18:45:55 +03:00
CCS - > curh - > initCursor ( ) ;
CCS - > curh - > show ( ) ;
logGlobal - > infoStream ( ) < < " Screen handler: " < < pomtime . getDiff ( ) ;
pomtime . getDiff ( ) ;
2013-04-22 22:51:22 +03:00
2013-06-17 18:45:55 +03:00
graphics - > loadHeroAnims ( ) ;
2014-07-03 11:26:15 +03:00
logGlobal - > infoStream ( ) < < " \t Main graphics: " < < pomtime . getDiff ( ) ;
2013-06-17 18:45:55 +03:00
logGlobal - > infoStream ( ) < < " Initializing game graphics: " < < tmh . getDiff ( ) ;
2009-06-24 09:56:36 +03:00
2013-06-17 18:45:55 +03:00
CMessage : : init ( ) ;
logGlobal - > infoStream ( ) < < " Message handler: " < < tmh . getDiff ( ) ;
}
2009-06-24 09:56:36 +03:00
}
2009-04-14 15:47:09 +03:00
2010-04-04 01:06:50 +03:00
static void prog_version ( void )
{
2011-12-14 00:23:17 +03:00
printf ( " %s \n " , GameConstants : : VCMI_VERSION . c_str ( ) ) ;
2014-03-20 21:17:40 +03:00
std : : cout < < VCMIDirs : : get ( ) . genHelpString ( ) ;
2010-04-04 01:06:50 +03:00
}
2012-01-03 04:55:26 +03:00
static void prog_help ( const po : : options_description & opts )
2010-04-04 01:06:50 +03:00
{
2011-12-14 00:23:17 +03:00
printf ( " %s - A Heroes of Might and Magic 3 clone \n " , GameConstants : : VCMI_VERSION . c_str ( ) ) ;
2015-12-13 21:14:37 +02:00
printf ( " Copyright (C) 2007-2016 VCMI dev team - see AUTHORS file \n " ) ;
printf ( " This is free software; see the source for copying conditions. There is NO \n " ) ;
printf ( " warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \n " ) ;
2010-04-04 01:06:50 +03:00
printf ( " \n " ) ;
printf ( " Usage: \n " ) ;
2012-01-03 04:55:26 +03:00
std : : cout < < opts ;
// printf(" -h, --help display this help and exit\n");
// printf(" -v, --version display version information and exit\n");
2010-04-04 01:06:50 +03:00
}
2015-06-22 21:19:32 +02:00
static void SDLLogCallback ( void * userdata ,
int category ,
SDL_LogPriority priority ,
const char * message )
{
//todo: convert SDL log priority to vcmi log priority
//todo: make separate log domain for SDL
2016-01-18 15:05:43 +02:00
2015-06-22 21:19:32 +02:00
logGlobal - > debugStream ( ) < < " SDL(category " < < category < < " ; priority " < < priority < < " ) " < < message ;
}
2014-08-26 13:19:04 +03:00
# ifdef VCMI_APPLE
2013-03-02 00:32:26 +03:00
void OSX_checkForUpdates ( ) ;
# endif
2010-04-04 01:06:50 +03:00
2014-08-26 13:19:04 +03:00
# if defined(VCMI_WINDOWS) && !defined (__GNUC__)
2013-04-20 14:34:01 +03:00
int wmain ( int argc , wchar_t * argv [ ] )
2014-08-26 13:19:04 +03:00
# elif defined(VCMI_APPLE)
2012-12-01 09:30:52 +03:00
int SDL_main ( int argc , char * argv [ ] )
2008-08-04 18:56:36 +03:00
# else
2008-09-10 00:10:24 +03:00
int main ( int argc , char * * argv )
2008-08-04 18:56:36 +03:00
# endif
2009-02-08 17:39:26 +02:00
{
2014-11-02 15:19:14 +02:00
# ifdef VCMI_ANDROID
// boost will crash without this
setenv ( " LANG " , " C " , 1 ) ;
# endif
2014-08-26 13:19:04 +03:00
# ifdef VCMI_APPLE
2014-03-23 15:59:03 +03:00
// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
2012-12-01 09:30:52 +03:00
std : : string executablePath = argv [ 0 ] ;
std : : string workDir = executablePath . substr ( 0 , executablePath . rfind ( ' / ' ) ) ;
chdir ( workDir . c_str ( ) ) ;
2014-03-07 16:21:09 +03:00
2013-03-02 00:32:26 +03:00
// Check for updates
OSX_checkForUpdates ( ) ;
2013-02-06 18:39:34 +03:00
// Check that game data is prepared. Otherwise run vcmibuilder helper application
2014-08-30 16:04:00 +03:00
FILE * check = fopen ( ( VCMIDirs : : get ( ) . userDataPath ( ) / " game_data_prepared " ) . string ( ) . c_str ( ) , " r " ) ;
2013-06-26 14:18:27 +03:00
if ( check = = nullptr ) {
2012-12-15 10:24:25 +03:00
system ( " open ./vcmibuilder.app " ) ;
return 0 ;
}
fclose ( check ) ;
2012-12-01 09:30:52 +03:00
# endif
2013-04-09 17:31:36 +03:00
std : : cout < < " Starting... " < < std : : endl ;
2010-12-22 22:14:40 +02:00
po : : options_description opts ( " Allowed options " ) ;
opts . add_options ( )
( " help,h " , " display help and exit " )
( " version,v " , " display version information and exit " )
2011-03-20 00:27:05 +02:00
( " battle,b " , po : : value < std : : string > ( ) , " runs game in duel mode (battle-only " )
2014-08-11 00:42:39 +03:00
( " start " , po : : value < bfs : : path > ( ) , " starts game from saved StartInfo file " )
2013-06-17 18:45:55 +03:00
( " onlyAI " , " runs without human player, all players will be default AI " )
( " noGUI " , " runs without GUI, implies --onlyAI " )
2013-06-21 23:59:32 +03:00
( " ai " , po : : value < std : : vector < std : : string > > ( ) , " AI to be used for the player, can be specified several times for the consecutive players " )
2012-02-29 04:31:48 +03:00
( " oneGoodAI " , " puts one default AI and the rest will be EmptyAI " )
2012-01-03 04:55:26 +03:00
( " autoSkip " , " automatically skip turns in GUI " )
2012-05-05 11:32:55 +03:00
( " disable-video " , " disable video player " )
2014-10-19 14:47:09 +03:00
( " nointro,i " , " skips intro movies " )
( " loadserver " , " specifies we are the multiplayer server for loaded games " )
( " loadnumplayers " , po : : value < int > ( ) , " specifies the number of players connecting to a multiplayer game " )
( " loadhumanplayerindices " , po : : value < std : : vector < int > > ( ) , " Indexes of human players (0=Red, etc.) " )
( " loadplayer " , po : : value < int > ( ) , " specifies which player we are in multiplayer loaded games (0=Red, etc.) " )
( " loadserverip " , po : : value < std : : string > ( ) , " IP for loaded game server " )
2015-12-13 21:14:37 +02:00
( " loadserverport " , po : : value < std : : string > ( ) , " port for loaded game server " )
( " testingport " , po : : value < std : : string > ( ) , " port for testing, override specified in config file " )
( " testingfileprefix " , po : : value < std : : string > ( ) , " prefix for auto save files " ) ;
2010-12-22 22:14:40 +02:00
if ( argc > 1 )
{
try
{
po : : store ( po : : parse_command_line ( argc , argv , opts ) , vm ) ;
}
2014-03-07 16:21:09 +03:00
catch ( std : : exception & e )
2010-12-22 22:14:40 +02:00
{
2013-04-09 17:31:36 +03:00
std : : cerr < < " Failure during parsing command-line options: \n " < < e . what ( ) < < std : : endl ;
2010-04-04 01:06:50 +03:00
}
}
2010-12-22 22:14:40 +02:00
po : : notify ( vm ) ;
if ( vm . count ( " help " ) )
{
2012-01-03 04:55:26 +03:00
prog_help ( opts ) ;
2010-12-22 22:14:40 +02:00
return 0 ;
}
if ( vm . count ( " version " ) )
{
prog_version ( ) ;
return 0 ;
2010-04-04 01:06:50 +03:00
}
2013-06-17 18:45:55 +03:00
if ( vm . count ( " noGUI " ) )
{
gNoGUI = true ;
2013-06-21 23:59:32 +03:00
vm . insert ( std : : pair < std : : string , po : : variable_value > ( " onlyAI " , po : : variable_value ( ) ) ) ;
2013-06-17 18:45:55 +03:00
}
2009-09-07 05:29:44 +03:00
2013-01-21 01:49:34 +03:00
// Have effect on X11 system only (Linux).
// For whatever reason in fullscreen mode SDL takes "raw" mouse input from DGA X11 extension
// (DGA = Direct graphics access). Because this is raw input (before any speed\acceleration proceesing)
// it may result in very small \ very fast mouse when game in fullscreen mode
putenv ( ( char * ) " SDL_VIDEO_X11_DGAMOUSE=0 " ) ;
2015-12-13 21:14:37 +02:00
// Init old logging system and new (temporary) logging system
2011-12-17 21:59:59 +03:00
CStopWatch total , pomtime ;
2008-11-15 15:44:32 +02:00
std : : cout . flags ( std : : ios : : unitbuf ) ;
2009-06-23 11:14:49 +03:00
console = new CConsoleHandler ;
2014-08-11 00:42:39 +03:00
* console - > cb = processCommand ;
2009-06-23 11:14:49 +03:00
console - > start ( ) ;
atexit ( dispose ) ;
2008-11-09 00:29:19 +02:00
2014-08-11 22:24:31 +03:00
const bfs : : path logPath = VCMIDirs : : get ( ) . userCachePath ( ) / " VCMI_Client_log.txt " ;
2014-02-27 23:44:20 +03:00
CBasicLogConfigurator logConfig ( logPath , console ) ;
2015-12-13 21:14:37 +02:00
logConfig . configureDefault ( ) ;
2014-02-27 23:44:20 +03:00
logGlobal - > infoStream ( ) < < " Creating console and configuring logger: " < < pomtime . getDiff ( ) ;
logGlobal - > infoStream ( ) < < " The log file will be saved to " < < logPath ;
2013-04-09 17:31:36 +03:00
2015-12-13 21:14:37 +02:00
// Init filesystem and settings
2013-04-11 18:58:01 +03:00
preinitDLL ( : : console ) ;
2015-12-13 21:14:37 +02:00
settings . init ( ) ;
2013-04-09 17:31:36 +03:00
2015-12-13 21:14:37 +02:00
// Init special testing settings
Settings testingSettings = settings . write [ " testing " ] ;
if ( vm . count ( " testingport " ) & & vm . count ( " testingfileprefix " ) )
{
testingSettings [ " enabled " ] . Bool ( ) = true ;
testingSettings [ " port " ] . String ( ) = vm [ " testingport " ] . as < std : : string > ( ) ;
testingSettings [ " prefix " ] . String ( ) = vm [ " testingfileprefix " ] . as < std : : string > ( ) ;
}
// Initialize logging based on settings
logConfig . configure ( ) ;
2012-08-02 14:03:26 +03:00
2013-03-12 17:56:23 +03:00
// Some basic data validation to produce better error messages in cases of incorrect install
auto testFile = [ ] ( std : : string filename , std : : string message ) - > bool
{
if ( CResourceHandler : : get ( ) - > existsResource ( ResourceID ( filename ) ) )
return true ;
2015-12-13 21:14:37 +02:00
logGlobal - > errorStream ( ) < < " Error: " < < message < < " was not found! " ;
2013-03-12 17:56:23 +03:00
return false ;
} ;
2013-07-28 17:49:50 +03:00
if ( ! testFile ( " DATA/HELP.TXT " , " Heroes III data " ) | |
2015-12-13 21:14:37 +02:00
! testFile ( " MODS/VCMI/MOD.JSON " , " VCMI data " ) )
{
2013-03-12 17:56:23 +03:00
exit ( 1 ) ; // These are unrecoverable errors
2015-12-13 21:14:37 +02:00
}
2013-03-12 17:56:23 +03:00
// these two are optional + some installs have them on CD and not in data directory
testFile ( " VIDEO/GOOD1A.SMK " , " campaign movies " ) ;
testFile ( " SOUNDS/G1A.WAV " , " campaign music " ) ; //technically not a music but voiced intro sounds
2008-11-09 00:29:19 +02:00
conf . init ( ) ;
2016-03-12 03:41:27 +02:00
logGlobal - > infoStream ( ) < < " Loading settings: " < < pomtime . getDiff ( ) ;
logGlobal - > infoStream ( ) < < NAME ;
2008-11-09 00:29:19 +02:00
2013-06-26 14:18:27 +03:00
srand ( time ( nullptr ) ) ;
2014-03-07 16:21:09 +03:00
2009-08-17 11:50:31 +03:00
2012-01-12 18:23:00 +03:00
const JsonNode & video = settings [ " video " ] ;
2012-05-18 20:35:46 +03:00
const JsonNode & res = video [ " screenRes " ] ;
2012-01-12 18:23:00 +03:00
2012-06-22 14:40:16 +03:00
//something is really wrong...
if ( res [ " width " ] . Float ( ) < 100 | | res [ " height " ] . Float ( ) < 100 )
{
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " Fatal error: failed to load settings! " ;
logGlobal - > errorStream ( ) < < " Possible reasons: " ;
logGlobal - > errorStream ( ) < < " \t Corrupted local configuration file at " < < VCMIDirs : : get ( ) . userConfigPath ( ) < < " /settings.json " ;
logGlobal - > errorStream ( ) < < " \t Missing or corrupted global configuration file at " < < VCMIDirs : : get ( ) . userConfigPath ( ) < < " /schemas/settings.json " ;
logGlobal - > errorStream ( ) < < " VCMI will now exit... " ;
2012-06-22 14:40:16 +03:00
exit ( EXIT_FAILURE ) ;
}
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
2014-05-21 21:43:44 +03:00
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) )
2013-06-17 18:45:55 +03:00
{
logGlobal - > errorStream ( ) < < " Something was wrong: " < < SDL_GetError ( ) ;
exit ( - 1 ) ;
}
2014-03-07 16:21:09 +03:00
GH . mainFPSmng - > init ( ) ; //(!)init here AFTER SDL_Init() while using SDL for FPS management
2013-06-17 18:45:55 +03:00
atexit ( SDL_Quit ) ;
2016-01-18 15:05:43 +02:00
2015-06-22 21:19:32 +02:00
SDL_LogSetOutputFunction ( & SDLLogCallback , nullptr ) ;
2016-01-18 15:05:43 +02:00
2014-05-23 22:39:10 +03:00
int driversCount = SDL_GetNumRenderDrivers ( ) ;
2014-05-24 15:14:37 +03:00
std : : string preferredDriverName = video [ " driver " ] . String ( ) ;
2016-01-18 15:05:43 +02:00
2014-05-23 22:39:10 +03:00
logGlobal - > infoStream ( ) < < " Found " < < driversCount < < " render drivers " ;
2016-01-18 15:05:43 +02:00
2014-05-23 22:39:10 +03:00
for ( int it = 0 ; it < driversCount ; it + + )
{
SDL_RendererInfo info ;
SDL_GetRenderDriverInfo ( it , & info ) ;
2016-01-18 15:05:43 +02:00
2014-05-23 22:39:10 +03:00
std : : string driverName ( info . name ) ;
2016-01-18 15:05:43 +02:00
2014-05-24 15:14:37 +03:00
if ( ! preferredDriverName . empty ( ) & & driverName = = preferredDriverName )
2014-05-23 22:39:10 +03:00
{
2014-05-24 15:14:37 +03:00
preferredDriverIndex = it ;
2014-09-18 14:20:53 +03:00
logGlobal - > infoStream ( ) < < " \t " < < driverName < < " (active) " ;
}
else
logGlobal - > infoStream ( ) < < " \t " < < driverName ;
2016-01-18 15:05:43 +02:00
}
2014-09-18 14:20:53 +03:00
config : : CConfigHandler : : GuiOptionsMap : : key_type resPair ( res [ " width " ] . Float ( ) , res [ " height " ] . Float ( ) ) ;
if ( conf . guiOptions . count ( resPair ) = = 0 )
{
// selected resolution was not found - complain & fallback to something that we do have.
logGlobal - > errorStream ( ) < < " Selected resolution " < < resPair . first < < " x " < < resPair . second < < " was not found! " ;
if ( conf . guiOptions . empty ( ) )
{
logGlobal - > errorStream ( ) < < " Unable to continue - no valid resolutions found! Please reinstall VCMI to fix this " ;
exit ( 1 ) ;
}
else
{
Settings newRes = settings . write [ " video " ] [ " screenRes " ] ;
newRes [ " width " ] . Float ( ) = conf . guiOptions . begin ( ) - > first . first ;
newRes [ " height " ] . Float ( ) = conf . guiOptions . begin ( ) - > first . second ;
conf . SetResolution ( newRes [ " width " ] . Float ( ) , newRes [ " height " ] . Float ( ) ) ;
logGlobal - > errorStream ( ) < < " Falling back to " < < newRes [ " width " ] . Float ( ) < < " x " < < newRes [ " height " ] . Float ( ) ;
}
}
2013-06-17 18:45:55 +03:00
setScreenRes ( res [ " width " ] . Float ( ) , res [ " height " ] . Float ( ) , video [ " bitsPerPixel " ] . Float ( ) , video [ " fullscreen " ] . Bool ( ) ) ;
logGlobal - > infoStream ( ) < < " \t Initializing screen: " < < pomtime . getDiff ( ) ;
}
2009-08-17 11:50:31 +03:00
2013-06-17 18:45:55 +03:00
CCS = new CClientState ;
CGI = new CGameInfo ; //contains all global informations about game (texts, lodHandlers, map handler etc.)
2009-08-17 11:50:31 +03:00
// Initialize video
2014-05-24 16:52:43 +03:00
# ifdef DISABLE_VIDEO
2011-08-08 10:12:18 +03:00
CCS - > videoh = new CEmptyVideoPlayer ;
# else
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI & & ! vm . count ( " disable-video " ) )
2012-05-05 11:32:55 +03:00
CCS - > videoh = new CVideoPlayer ;
else
CCS - > videoh = new CEmptyVideoPlayer ;
2011-08-08 10:12:18 +03:00
# endif
2012-08-18 13:29:54 +03:00
2016-03-12 03:41:27 +02:00
logGlobal - > infoStream ( ) < < " \t Initializing video: " < < pomtime . getDiff ( ) ;
2009-08-17 11:50:31 +03:00
2014-08-26 13:19:04 +03:00
# if defined(VCMI_ANDROID)
2014-07-02 22:53:23 +03:00
//on Android threaded init is broken
# define VCMI_NO_THREADED_LOAD
# endif // defined
2013-06-17 18:45:55 +03:00
2014-07-03 11:26:15 +03:00
//initializing audio
CCS - > soundh = new CSoundHandler ;
CCS - > soundh - > init ( ) ;
CCS - > soundh - > setVolume ( settings [ " general " ] [ " sound " ] . Float ( ) ) ;
CCS - > musich = new CMusicHandler ;
CCS - > musich - > init ( ) ;
CCS - > musich - > setVolume ( settings [ " general " ] [ " music " ] . Float ( ) ) ;
2016-03-12 03:41:27 +02:00
logGlobal - > infoStream ( ) < < " Initializing screen and sound handling: " < < pomtime . getDiff ( ) ;
2014-07-02 22:53:23 +03:00
2016-01-18 15:05:43 +02:00
# ifdef __APPLE__
// Ctrl+click should be treated as a right click on Mac OS X
SDL_SetHint ( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK , " 1 " ) ;
# endif
2014-07-02 22:53:23 +03:00
# ifndef VCMI_NO_THREADED_LOAD
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
boost : : thread loading ( init ) ;
2016-01-18 15:05:43 +02:00
# else
2014-02-20 21:53:18 +03:00
init ( ) ;
2014-07-02 22:53:23 +03:00
# endif
2010-12-22 22:14:40 +02:00
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
2014-08-04 14:03:57 +03:00
if ( ! vm . count ( " battle " ) & & ! vm . count ( " nointro " ) & & settings [ " video " ] [ " showIntro " ] . Bool ( ) )
2013-06-17 18:45:55 +03:00
playIntro ( ) ;
2013-06-26 14:18:27 +03:00
SDL_FillRect ( screen , nullptr , 0 ) ;
2013-06-17 18:45:55 +03:00
}
2010-12-22 22:14:40 +02:00
2011-04-05 20:38:24 +03:00
CSDL_Ext : : update ( screen ) ;
2014-07-02 22:53:23 +03:00
# ifndef VCMI_NO_THREADED_LOAD
loading . join ( ) ;
# endif
2016-03-12 03:41:27 +02:00
logGlobal - > infoStream ( ) < < " Initialization of VCMI (together): " < < total . getDiff ( ) ;
2009-08-17 11:50:31 +03:00
2010-12-22 22:14:40 +02:00
if ( ! vm . count ( " battle " ) )
{
2012-01-12 18:23:00 +03:00
Settings session = settings . write [ " session " ] ;
session [ " autoSkip " ] . Bool ( ) = vm . count ( " autoSkip " ) ;
session [ " oneGoodAI " ] . Bool ( ) = vm . count ( " oneGoodAI " ) ;
2016-02-24 21:26:39 +02:00
session [ " aiSolo " ] . Bool ( ) = false ;
2012-01-03 04:55:26 +03:00
2014-08-11 00:42:39 +03:00
bfs : : path fileToStartFrom ; //none by default
2012-07-20 23:57:18 +03:00
if ( vm . count ( " start " ) )
2014-08-11 00:42:39 +03:00
fileToStartFrom = vm [ " start " ] . as < bfs : : path > ( ) ;
2012-01-03 04:55:26 +03:00
2014-08-11 00:42:39 +03:00
if ( ! fileToStartFrom . empty ( ) & & bfs : : exists ( fileToStartFrom ) )
2014-03-23 15:59:03 +03:00
startGameFromFile ( fileToStartFrom ) ; //ommit pregame and start the game using settings from file
2012-01-03 04:55:26 +03:00
else
2012-07-20 23:57:18 +03:00
{
2014-08-11 00:42:39 +03:00
if ( ! fileToStartFrom . empty ( ) )
2012-07-20 23:57:18 +03:00
{
2016-03-12 03:41:27 +02:00
logGlobal - > warnStream ( ) < < " Warning: cannot find given file to start from ( " < < fileToStartFrom
< < " ). Falling back to main menu. " ;
2012-07-20 23:57:18 +03:00
}
GH . curInt = CGPreGame : : create ( ) ; //will set CGP pointer to itself
}
2010-12-22 22:14:40 +02:00
}
else
{
2013-06-29 16:05:48 +03:00
auto si = new StartInfo ( ) ;
2010-12-22 22:14:40 +02:00
si - > mode = StartInfo : : DUEL ;
2011-01-21 04:36:30 +02:00
si - > mapname = vm [ " battle " ] . as < std : : string > ( ) ;
2013-03-03 20:06:03 +03:00
si - > playerInfos [ PlayerColor ( 0 ) ] . color = PlayerColor ( 0 ) ;
si - > playerInfos [ PlayerColor ( 1 ) ] . color = PlayerColor ( 1 ) ;
2010-12-22 22:14:40 +02:00
startGame ( si ) ;
}
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
2014-06-01 18:31:37 +03:00
mainLoop ( ) ;
2013-06-17 18:45:55 +03:00
}
else
{
while ( true )
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 1000 ) ) ;
}
2009-10-26 07:39:30 +02:00
return 0 ;
2007-06-07 20:45:56 +03:00
}
2008-09-17 13:18:22 +03:00
2010-10-24 14:35:14 +03:00
void printInfoAboutIntObject ( const CIntObject * obj , int level )
{
2016-03-12 03:41:27 +02:00
std : : stringstream sbuffer ;
sbuffer < < std : : string ( level , ' \t ' ) ;
2010-10-24 14:35:14 +03:00
2016-03-12 03:41:27 +02:00
sbuffer < < typeid ( * obj ) . name ( ) < < " *** " ;
2012-06-02 18:16:54 +03:00
if ( obj - > active )
{
2013-04-09 17:31:36 +03:00
# define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
2012-06-02 18:16:54 +03:00
PRINT ( LCLICK , ' L ' ) ;
PRINT ( RCLICK , ' R ' ) ;
PRINT ( HOVER , ' H ' ) ;
PRINT ( MOVE , ' M ' ) ;
PRINT ( KEYBOARD , ' K ' ) ;
PRINT ( TIME , ' T ' ) ;
PRINT ( GENERAL , ' A ' ) ;
PRINT ( WHEEL , ' W ' ) ;
PRINT ( DOUBLECLICK , ' D ' ) ;
# undef PRINT
}
else
2016-03-12 03:41:27 +02:00
sbuffer < < " inactive " ;
sbuffer < < " at " < < obj - > pos . x < < " x " < < obj - > pos . y ;
sbuffer < < " ( " < < obj - > pos . w < < " x " < < obj - > pos . h < < " ) " ;
logGlobal - > infoStream ( ) < < sbuffer . str ( ) ;
2010-10-24 14:35:14 +03:00
2013-06-29 16:05:48 +03:00
for ( const CIntObject * child : obj - > children )
2010-10-24 14:35:14 +03:00
printInfoAboutIntObject ( child , level + 1 ) ;
}
2009-08-17 11:50:31 +03:00
void processCommand ( const std : : string & message )
2008-09-17 13:18:22 +03:00
{
std : : istringstream readed ;
readed . str ( message ) ;
std : : string cn ; //command name
readed > > cn ;
2015-11-08 21:16:58 +02:00
// Check mantis issue 2292 for details
// if(LOCPLINT && LOCPLINT->cingconsole)
// LOCPLINT->cingconsole->print(message);
2009-04-04 22:26:41 +03:00
2011-06-11 02:50:32 +03:00
if ( ermInteractiveMode )
{
if ( cn = = " exit " )
{
ermInteractiveMode = false ;
return ;
}
else
{
if ( client & & client - > erm )
client - > erm - > executeUserCommand ( message ) ;
2016-03-12 03:41:27 +02:00
std : : cout < < " erm> " ;
2011-06-11 02:50:32 +03:00
}
}
2011-06-24 00:42:30 +03:00
else if ( message = = std : : string ( " die, fool " ) )
2011-06-11 02:50:32 +03:00
{
2008-12-21 21:17:35 +02:00
exit ( EXIT_SUCCESS ) ;
2011-06-11 02:50:32 +03:00
}
else if ( cn = = " erm " )
{
ermInteractiveMode = true ;
2016-03-12 03:41:27 +02:00
std : : cout < < " erm> " ;
2011-06-11 02:50:32 +03:00
}
2008-09-17 13:18:22 +03:00
else if ( cn = = std : : string ( " activate " ) )
{
int what ;
readed > > what ;
switch ( what )
{
case 0 :
2009-08-07 01:36:51 +03:00
GH . topInt ( ) - > activate ( ) ;
2008-09-17 13:18:22 +03:00
break ;
case 1 :
2010-02-20 15:24:38 +02:00
adventureInt - > activate ( ) ;
2008-09-17 13:18:22 +03:00
break ;
case 2 :
LOCPLINT - > castleInt - > activate ( ) ;
break ;
}
}
2009-08-22 16:59:15 +03:00
else if ( cn = = " redraw " )
{
GH . totalRedraw ( ) ;
}
2009-08-17 11:50:31 +03:00
else if ( cn = = " screen " )
{
2016-03-12 03:41:27 +02:00
std : : cout < < " Screenbuf points to " ;
2009-08-17 11:50:31 +03:00
if ( screenBuf = = screen )
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " screen " ;
2009-08-17 11:50:31 +03:00
else if ( screenBuf = = screen2 )
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " screen2 " ;
2009-08-17 11:50:31 +03:00
else
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " ?!? " ;
2009-08-17 11:50:31 +03:00
SDL_SaveBMP ( screen , " Screen_c.bmp " ) ;
SDL_SaveBMP ( screen2 , " Screen2_c.bmp " ) ;
}
2008-11-16 03:06:15 +02:00
else if ( cn = = " save " )
{
std : : string fname ;
readed > > fname ;
client - > save ( fname ) ;
}
2009-01-11 00:08:18 +02:00
else if ( cn = = " load " )
{
2009-11-01 03:15:16 +02:00
// TODO: this code should end the running game and manage to call startGame instead
2009-01-11 00:08:18 +02:00
std : : string fname ;
readed > > fname ;
2009-11-01 03:15:16 +02:00
client - > loadGame ( fname ) ;
2016-03-12 03:41:27 +02:00
}
2008-09-17 13:18:22 +03:00
else if ( message = = " get txt " )
{
2016-03-12 03:41:27 +02:00
std : : cout < < " Command accepted. \t " ;
2013-06-10 20:02:37 +03:00
2014-08-11 22:24:31 +03:00
const bfs : : path outPath =
2014-08-11 00:42:39 +03:00
VCMIDirs : : get ( ) . userCachePath ( ) / " extracted " ;
2013-06-10 20:02:37 +03:00
2013-07-28 17:49:50 +03:00
auto list = CResourceHandler : : get ( ) - > getFilteredFiles ( [ ] ( const ResourceID & ident )
2012-08-01 15:02:54 +03:00
{
return ident . getType ( ) = = EResType : : TEXT & & boost : : algorithm : : starts_with ( ident . getName ( ) , " DATA/ " ) ;
} ) ;
2013-07-28 17:49:50 +03:00
for ( auto & filename : list )
2012-08-01 15:02:54 +03:00
{
2014-08-11 22:24:31 +03:00
const bfs : : path filePath = outPath / ( filename . getName ( ) + " .TXT " ) ;
2016-01-18 15:05:43 +02:00
2014-08-11 22:24:31 +03:00
bfs : : create_directories ( filePath . parent_path ( ) ) ;
2013-06-10 20:02:37 +03:00
2014-08-11 22:24:31 +03:00
bfs : : ofstream file ( filePath ) ;
2013-07-28 17:49:50 +03:00
auto text = CResourceHandler : : get ( ) - > load ( filename ) - > readAll ( ) ;
2012-08-01 15:02:54 +03:00
file . write ( ( char * ) text . first . get ( ) , text . second ) ;
}
2016-03-12 03:41:27 +02:00
std : : cout < < " \r Extracting done :) \n " ;
2014-08-11 22:24:31 +03:00
std : : cout < < " Extracted files can be found in " < < outPath < < " directory \n " ;
2008-09-17 13:18:22 +03:00
}
2009-07-31 23:10:22 +03:00
else if ( cn = = " crash " )
{
2013-06-26 14:18:27 +03:00
int * ptr = nullptr ;
2009-07-31 23:10:22 +03:00
* ptr = 666 ;
//disaster!
}
2009-08-08 02:17:12 +03:00
else if ( cn = = " onlyai " )
{
2013-06-21 23:59:32 +03:00
vm . insert ( std : : pair < std : : string , po : : variable_value > ( " onlyAI " , po : : variable_value ( ) ) ) ;
2009-08-08 02:17:12 +03:00
}
2010-11-28 18:39:13 +02:00
else if ( cn = = " ai " )
{
VLC - > IS_AI_ENABLED = ! VLC - > IS_AI_ENABLED ;
2016-03-12 03:41:27 +02:00
std : : cout < < " Current AI status: " < < ( VLC - > IS_AI_ENABLED ? " enabled " : " disabled " ) < < std : : endl ;
2010-11-28 18:39:13 +02:00
}
2010-05-31 23:38:14 +03:00
else if ( cn = = " mp " & & adventureInt )
{
if ( const CGHeroInstance * h = dynamic_cast < const CGHeroInstance * > ( adventureInt - > selection ) )
2016-03-12 03:41:27 +02:00
std : : cout < < h - > movement < < " ; max: " < < h - > maxMovePoints ( true ) < < " / " < < h - > maxMovePoints ( false ) < < std : : endl ;
2010-05-31 23:38:14 +03:00
}
2010-07-12 13:20:25 +03:00
else if ( cn = = " bonuses " )
{
2014-06-24 20:39:36 +03:00
std : : cout < < " Bonuses of " < < adventureInt - > selection - > getObjectName ( ) < < std : : endl
2011-07-13 21:39:02 +03:00
< < adventureInt - > selection - > getBonusList ( ) < < std : : endl ;
2010-07-12 13:20:25 +03:00
2016-03-12 03:41:27 +02:00
std : : cout < < " \n Inherited bonuses: \n " ;
2010-07-12 13:20:25 +03:00
TCNodes parents ;
adventureInt - > selection - > getParents ( parents ) ;
2013-06-29 16:05:48 +03:00
for ( const CBonusSystemNode * parent : parents )
2010-07-12 13:20:25 +03:00
{
2016-03-12 03:41:27 +02:00
std : : cout < < " \n Bonuses from " < < typeid ( * parent ) . name ( ) < < std : : endl < < parent - > getBonusList ( ) < < std : : endl ;
2010-07-12 13:20:25 +03:00
}
}
2010-07-24 14:46:04 +03:00
else if ( cn = = " not dialog " )
{
LOCPLINT - > showingDialog - > setn ( false ) ;
}
2010-10-24 14:35:14 +03:00
else if ( cn = = " gui " )
{
2013-06-29 16:05:48 +03:00
for ( const IShowActivatable * child : GH . listInt )
2010-10-24 14:35:14 +03:00
{
if ( const CIntObject * obj = dynamic_cast < const CIntObject * > ( child ) )
printInfoAboutIntObject ( obj , 0 ) ;
else
2016-03-12 03:41:27 +02:00
std : : cout < < typeid ( * obj ) . name ( ) < < std : : endl ;
2010-10-24 14:35:14 +03:00
}
}
2011-01-15 04:17:56 +02:00
else if ( cn = = " tell " )
{
std : : string what ;
int id1 , id2 ;
readed > > what > > id1 > > id2 ;
if ( what = = " hs " )
{
2013-06-29 16:05:48 +03:00
for ( const CGHeroInstance * h : LOCPLINT - > cb - > getHeroesInfo ( ) )
2013-05-19 01:30:48 +03:00
if ( h - > type - > ID . getNum ( ) = = id1 )
2013-02-12 22:49:40 +03:00
if ( const CArtifactInstance * a = h - > getArt ( ArtifactPosition ( id2 ) ) )
2016-03-12 03:41:27 +02:00
std : : cout < < a - > nodeName ( ) ;
2011-01-15 04:17:56 +02:00
}
}
2012-05-14 19:29:06 +03:00
else if ( cn = = " set " )
2011-05-25 16:11:03 +03:00
{
2012-05-14 19:29:06 +03:00
std : : string what , value ;
readed > > what ;
Settings conf = settings . write [ " session " ] [ what ] ;
readed > > value ;
if ( value = = " on " )
conf - > Bool ( ) = true ;
else if ( value = = " off " )
conf - > Bool ( ) = false ;
2011-05-25 16:11:03 +03:00
}
2012-01-03 04:55:26 +03:00
else if ( cn = = " sinfo " )
{
std : : string fname ;
readed > > fname ;
if ( fname . size ( ) & & SEL )
{
CSaveFile out ( fname ) ;
out < < SEL - > sInfo ;
}
}
else if ( cn = = " start " )
{
std : : string fname ;
readed > > fname ;
startGameFromFile ( fname ) ;
}
2012-02-20 00:03:43 +03:00
else if ( cn = = " unlock " )
{
std : : string mxname ;
readed > > mxname ;
if ( mxname = = " pim " & & LOCPLINT )
LOCPLINT - > pim - > unlock ( ) ;
}
2013-06-10 20:02:37 +03:00
else if ( cn = = " def2bmp " )
{
std : : string URI ;
readed > > URI ;
if ( CResourceHandler : : get ( ) - > existsResource ( ResourceID ( " SPRITES/ " + URI ) ) )
{
CDefEssential * cde = CDefHandler : : giveDefEss ( URI ) ;
2014-08-26 13:19:04 +03:00
const bfs : : path outPath = VCMIDirs : : get ( ) . userCachePath ( ) / " extracted " / URI ;
2014-08-11 22:24:31 +03:00
bfs : : create_directories ( outPath ) ;
2013-06-10 20:02:37 +03:00
2014-08-11 00:42:39 +03:00
for ( size_t i = 0 ; i < cde - > ourImages . size ( ) ; + + i )
2013-06-10 20:02:37 +03:00
{
2014-08-11 22:24:31 +03:00
const bfs : : path filePath = outPath / ( boost : : lexical_cast < std : : string > ( i ) + " .bmp " ) ;
SDL_SaveBMP ( cde - > ourImages [ i ] . bitmap , filePath . string ( ) . c_str ( ) ) ;
2013-06-10 20:02:37 +03:00
}
}
else
logGlobal - > errorStream ( ) < < " File not found! " ;
}
else if ( cn = = " extract " )
{
std : : string URI ;
readed > > URI ;
if ( CResourceHandler : : get ( ) - > existsResource ( ResourceID ( URI ) ) )
{
2014-08-11 22:24:31 +03:00
const bfs : : path outPath = VCMIDirs : : get ( ) . userCachePath ( ) / " extracted " / URI ;
2013-06-10 20:02:37 +03:00
2013-07-28 17:49:50 +03:00
auto data = CResourceHandler : : get ( ) - > load ( ResourceID ( URI ) ) - > readAll ( ) ;
2013-06-10 20:02:37 +03:00
2014-08-11 22:24:31 +03:00
bfs : : create_directories ( outPath . parent_path ( ) ) ;
bfs : : ofstream outFile ( outPath , bfs : : ofstream : : binary ) ;
2013-06-10 20:02:37 +03:00
outFile . write ( ( char * ) data . first . get ( ) , data . second ) ;
}
else
logGlobal - > errorStream ( ) < < " File not found! " ;
}
2012-09-29 13:59:43 +03:00
else if ( cn = = " setBattleAI " )
{
std : : string fname ;
readed > > fname ;
2016-03-12 03:41:27 +02:00
std : : cout < < " Will try loading that AI to see if it is correct name... \n " ;
2013-01-20 15:06:49 +03:00
try
2012-09-29 13:59:43 +03:00
{
2013-01-20 15:06:49 +03:00
if ( auto ai = CDynLibHandler : : getNewBattleAI ( fname ) ) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
{
Settings neutralAI = settings . write [ " server " ] [ " neutralAI " ] ;
neutralAI - > String ( ) = fname ;
2016-03-12 03:41:27 +02:00
std : : cout < < " Setting changed, from now the battle ai will be " < < fname < < " ! \n " ;
2013-01-20 15:06:49 +03:00
}
2012-09-29 13:59:43 +03:00
}
2013-01-20 15:06:49 +03:00
catch ( std : : exception & e )
2012-09-29 13:59:43 +03:00
{
2016-03-12 03:41:27 +02:00
logGlobal - > warnStream ( ) < < " Failed opening " < < fname < < " : " < < e . what ( ) ;
logGlobal - > warnStream ( ) < < " Setting not changes, AI not found or invalid! " ;
2012-09-29 13:59:43 +03:00
}
}
2016-02-24 21:26:39 +02:00
auto removeGUI = [ & ] ( )
{
// CClient::endGame
GH . curInt = nullptr ;
if ( GH . topInt ( ) )
GH . topInt ( ) - > deactivate ( ) ;
GH . listInt . clear ( ) ;
GH . objsToBlit . clear ( ) ;
GH . statusbar = nullptr ;
logNetwork - > infoStream ( ) < < " Removed GUI. " ;
LOCPLINT = nullptr ;
} ;
auto giveTurn = [ & ] ( PlayerColor player )
{
YourTurn yt ;
yt . player = player ;
yt . daysWithoutCastle = client - > getPlayer ( player ) - > daysWithoutCastle ;
yt . applyCl ( client ) ;
} ;
Settings session = settings . write [ " session " ] ;
if ( cn = = " autoskip " )
2014-02-02 17:39:32 +03:00
{
session [ " autoSkip " ] . Bool ( ) = ! session [ " autoSkip " ] . Bool ( ) ;
}
2016-02-24 21:26:39 +02:00
else if ( cn = = " gosolo " )
{
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
PlayerColor color ;
if ( session [ " aiSolo " ] . Bool ( ) )
{
for ( auto & elem : client - > gameState ( ) - > players )
{
if ( elem . second . human )
client - > installNewPlayerInterface ( std : : make_shared < CPlayerInterface > ( elem . first ) , elem . first ) ;
}
}
else
{
color = LOCPLINT - > playerID ;
removeGUI ( ) ;
for ( auto & elem : client - > gameState ( ) - > players )
{
if ( elem . second . human )
{
auto AiToGive = client - > aiNameForPlayer ( * client - > getPlayerSettings ( elem . first ) , false ) ;
logNetwork - > infoStream ( ) < < boost : : format ( " Player %s will be lead by %s " ) % elem . first % AiToGive ;
client - > installNewPlayerInterface ( CDynLibHandler : : getNewAI ( AiToGive ) , elem . first ) ;
}
}
GH . totalRedraw ( ) ;
giveTurn ( color ) ;
}
session [ " aiSolo " ] . Bool ( ) = ! session [ " aiSolo " ] . Bool ( ) ;
}
else if ( cn = = " controlai " )
{
std : : string colorName ;
readed > > colorName ;
boost : : to_lower ( colorName ) ;
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
PlayerColor color ;
if ( LOCPLINT )
color = LOCPLINT - > playerID ;
for ( auto & elem : client - > gameState ( ) - > players )
{
if ( elem . second . human | | ( colorName . length ( ) & &
elem . first . getNum ( ) ! = vstd : : find_pos ( GameConstants : : PLAYER_COLOR_NAMES , colorName ) ) )
{
continue ;
}
removeGUI ( ) ;
client - > installNewPlayerInterface ( std : : make_shared < CPlayerInterface > ( elem . first ) , elem . first ) ;
}
GH . totalRedraw ( ) ;
if ( color ! = PlayerColor : : NEUTRAL )
giveTurn ( color ) ;
}
2015-11-08 21:16:58 +02:00
// Check mantis issue 2292 for details
/* else if(client && client->serv && client->serv->connected && LOCPLINT) //send to server
2008-10-19 02:20:48 +03:00
{
2012-02-17 00:46:28 +03:00
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
LOCPLINT - > cb - > sendMessage ( message ) ;
2015-11-08 21:16:58 +02:00
} */
2009-04-14 15:47:09 +03:00
}
2009-06-24 09:56:36 +03:00
//plays intro, ends when intro is over or button has been pressed (handles events)
void playIntro ( )
{
2014-07-10 13:18:21 +03:00
if ( CCS - > videoh - > openAndPlayVideo ( " 3DOLOGO.SMK " , 60 , 40 , screen , true , true ) )
2009-06-24 09:56:36 +03:00
{
2014-07-10 13:18:21 +03:00
CCS - > videoh - > openAndPlayVideo ( " AZVS.SMK " , 60 , 80 , screen , true , true ) ;
2009-06-24 09:56:36 +03:00
}
}
2009-06-23 11:14:49 +03:00
void dispose ( )
{
2009-10-26 07:39:30 +02:00
if ( console )
delete console ;
2013-12-19 22:43:16 +03:00
// cleanup, mostly to remove false leaks from analyzer
CResourceHandler : : clear ( ) ;
2014-03-08 19:05:23 +03:00
if ( CCS )
{
CCS - > musich - > release ( ) ;
CCS - > soundh - > release ( ) ;
}
2013-12-19 22:43:16 +03:00
CMessage : : dispose ( ) ;
2009-06-23 11:14:49 +03:00
}
2014-05-21 19:04:34 +03:00
static bool checkVideoMode ( int monitorIndex , int w , int h , int & bpp , bool fullscreen )
{
SDL_DisplayMode mode ;
const int modeCount = SDL_GetNumDisplayModes ( monitorIndex ) ;
for ( int i = 0 ; i < modeCount ; i + + ) {
SDL_GetDisplayMode ( 0 , i , & mode ) ;
if ( ! mode . w | | ! mode . h | | ( w > = mode . w & & h > = mode . h ) ) {
return true ;
}
}
2016-01-18 15:05:43 +02:00
return false ;
2014-05-21 19:04:34 +03:00
}
static bool recreateWindow ( int w , int h , int bpp , bool fullscreen )
2012-01-12 18:23:00 +03:00
{
2016-01-18 15:05:43 +02:00
// VCMI will only work with 2 or 4 bytes per pixel
2011-12-14 00:23:17 +03:00
vstd : : amax ( bpp , 16 ) ;
vstd : : amin ( bpp , 32 ) ;
2014-05-23 22:39:10 +03:00
if ( bpp > 16 )
bpp = 32 ;
2016-01-18 15:05:43 +02:00
2014-05-21 19:04:34 +03:00
int suggestedBpp = bpp ;
2009-05-17 07:14:30 +03:00
2014-05-21 19:04:34 +03:00
if ( ! checkVideoMode ( 0 , w , h , suggestedBpp , fullscreen ) )
2009-07-16 02:58:47 +03:00
{
2014-03-20 21:17:40 +03:00
logGlobal - > errorStream ( ) < < " Error: SDL says that " < < w < < " x " < < h < < " resolution is not available! " ;
2014-05-21 19:04:34 +03:00
return false ;
2016-01-18 15:05:43 +02:00
}
2014-05-23 22:39:10 +03:00
bool bufOnScreen = ( screenBuf = = screen ) ;
screenBuf = nullptr ; //it`s a link - just nullify
if ( nullptr ! = screen2 )
{
SDL_FreeSurface ( screen2 ) ;
screen2 = nullptr ;
}
2016-01-18 15:05:43 +02:00
2014-05-23 22:39:10 +03:00
if ( nullptr ! = screen )
{
SDL_FreeSurface ( screen ) ;
screen = nullptr ;
2016-01-18 15:05:43 +02:00
}
2014-05-23 22:39:10 +03:00
if ( nullptr ! = screenTexture )
{
SDL_DestroyTexture ( screenTexture ) ;
screenTexture = nullptr ;
}
2016-01-18 15:05:43 +02:00
if ( nullptr ! = mainRenderer )
2014-05-21 19:04:34 +03:00
{
SDL_DestroyRenderer ( mainRenderer ) ;
mainRenderer = nullptr ;
2009-07-16 02:58:47 +03:00
}
2016-01-18 15:05:43 +02:00
2014-05-21 19:04:34 +03:00
if ( nullptr ! = mainWindow )
{
SDL_DestroyWindow ( mainWindow ) ;
mainWindow = nullptr ;
2016-01-18 15:05:43 +02:00
}
2014-05-23 21:23:04 +03:00
if ( fullscreen )
{
//in full-screen mode always use desktop resolution
2014-05-24 15:14:37 +03:00
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_UNDEFINED , SDL_WINDOWPOS_UNDEFINED , 0 , 0 , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
SDL_SetHint ( SDL_HINT_RENDER_SCALE_QUALITY , " linear " ) ;
2014-05-23 21:23:04 +03:00
}
else
{
2014-05-24 15:14:37 +03:00
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED , w , h , 0 ) ;
2014-05-23 21:23:04 +03:00
}
2016-01-18 15:05:43 +02:00
2014-05-21 19:04:34 +03:00
if ( nullptr = = mainWindow )
2009-07-16 02:58:47 +03:00
{
2014-05-21 19:04:34 +03:00
throw std : : runtime_error ( " Unable to create window \n " ) ;
2009-07-16 02:58:47 +03:00
}
2016-01-18 15:05:43 +02:00
2014-05-24 15:14:37 +03:00
//create first available renderer if preferred not set. Use no flags, so HW accelerated will be preferred but SW renderer also will possible
mainRenderer = SDL_CreateRenderer ( mainWindow , preferredDriverIndex , 0 ) ;
2009-07-16 02:58:47 +03:00
2014-05-21 19:04:34 +03:00
if ( nullptr = = mainRenderer )
2012-02-24 23:41:14 +03:00
{
2014-05-21 19:04:34 +03:00
throw std : : runtime_error ( " Unable to create renderer \n " ) ;
2016-01-18 15:05:43 +02:00
}
2014-05-23 22:39:10 +03:00
SDL_RendererInfo info ;
SDL_GetRendererInfo ( mainRenderer , & info ) ;
2016-01-18 15:05:43 +02:00
logGlobal - > infoStream ( ) < < " Created renderer " < < info . name ;
2014-05-21 19:04:34 +03:00
SDL_RenderSetLogicalSize ( mainRenderer , w , h ) ;
2016-01-18 15:05:43 +02:00
2014-06-01 18:31:37 +03:00
SDL_RenderSetViewport ( mainRenderer , nullptr ) ;
2014-03-07 16:21:09 +03:00
2009-05-17 07:14:30 +03:00
2016-01-18 15:05:43 +02:00
2014-05-23 13:51:38 +03:00
# if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
int bmask = 0xff000000 ;
int gmask = 0x00ff0000 ;
int rmask = 0x0000ff00 ;
int amask = 0x000000ff ;
# else
int bmask = 0x000000ff ;
int gmask = 0x0000ff00 ;
int rmask = 0x00ff0000 ;
int amask = 0xFF000000 ;
# endif
2014-05-21 19:04:34 +03:00
2014-05-23 13:51:38 +03:00
screen = SDL_CreateRGBSurface ( 0 , w , h , bpp , rmask , gmask , bmask , amask ) ;
2014-05-21 19:04:34 +03:00
if ( nullptr = = screen )
{
2014-05-21 19:27:48 +03:00
logGlobal - > errorStream ( ) < < " Unable to create surface " ;
logGlobal - > errorStream ( ) < < w < < " " < < h < < " " < < bpp ;
2016-01-18 15:05:43 +02:00
2014-05-21 19:27:48 +03:00
logGlobal - > errorStream ( ) < < SDL_GetError ( ) ;
throw std : : runtime_error ( " Unable to create surface " ) ;
2016-01-18 15:05:43 +02:00
}
2014-07-03 17:05:07 +03:00
//No blending for screen itself. Required for proper cursor rendering.
SDL_SetSurfaceBlendMode ( screen , SDL_BLENDMODE_NONE ) ;
2016-01-18 15:05:43 +02:00
2014-05-21 19:04:34 +03:00
screenTexture = SDL_CreateTexture ( mainRenderer ,
SDL_PIXELFORMAT_ARGB8888 ,
SDL_TEXTUREACCESS_STREAMING ,
w , h ) ;
if ( nullptr = = screenTexture )
{
2014-05-21 19:27:48 +03:00
logGlobal - > errorStream ( ) < < " Unable to create screen texture " ;
logGlobal - > errorStream ( ) < < SDL_GetError ( ) ;
throw std : : runtime_error ( " Unable to create screen texture " ) ;
2016-01-18 15:05:43 +02:00
}
2009-04-14 15:47:09 +03:00
screen2 = CSDL_Ext : : copySurface ( screen ) ;
2009-08-22 16:59:15 +03:00
2014-05-21 19:04:34 +03:00
if ( nullptr = = screen2 )
{
throw std : : runtime_error ( " Unable to copy surface \n " ) ;
2016-01-18 15:05:43 +02:00
}
2014-05-21 19:04:34 +03:00
screenBuf = bufOnScreen ? screen : screen2 ;
2014-05-21 21:43:44 +03:00
SDL_SetRenderDrawColor ( mainRenderer , 0 , 0 , 0 , 0 ) ;
SDL_RenderClear ( mainRenderer ) ;
SDL_RenderPresent ( mainRenderer ) ;
2016-01-18 15:05:43 +02:00
return true ;
2014-05-21 19:04:34 +03:00
}
//used only once during initialization
static void setScreenRes ( int w , int h , int bpp , bool fullscreen , bool resetVideo )
{
2014-05-23 14:42:27 +03:00
if ( ! recreateWindow ( w , h , bpp , fullscreen ) )
{
2014-07-03 11:26:15 +03:00
throw std : : runtime_error ( " Requested screen resolution is not available \n " ) ;
2016-01-18 15:05:43 +02:00
}
2009-05-06 05:32:36 +03:00
}
2009-08-17 11:50:31 +03:00
2012-09-11 17:25:19 +03:00
static void fullScreenChanged ( )
2012-02-24 23:41:14 +03:00
{
boost : : unique_lock < boost : : recursive_mutex > lock ( * LOCPLINT - > pim ) ;
2012-05-18 20:35:46 +03:00
2012-09-11 17:25:19 +03:00
Settings full = settings . write [ " video " ] [ " fullscreen " ] ;
const bool toFullscreen = full - > Bool ( ) ;
2014-05-21 19:04:34 +03:00
auto bitsPerPixel = screen - > format - > BitsPerPixel ;
2016-01-18 15:05:43 +02:00
2014-05-21 19:04:34 +03:00
auto w = screen - > w ;
auto h = screen - > h ;
2016-01-18 15:05:43 +02:00
2014-05-23 14:42:27 +03:00
if ( ! recreateWindow ( w , h , bitsPerPixel , toFullscreen ) )
2012-05-18 20:35:46 +03:00
{
2014-05-21 19:04:34 +03:00
//will return false and report error if video mode is not supported
2016-01-18 15:05:43 +02:00
return ;
}
2012-02-24 23:41:14 +03:00
GH . totalRedraw ( ) ;
}
2014-06-01 18:31:37 +03:00
static void handleEvent ( SDL_Event & ev )
2009-08-17 13:47:08 +03:00
{
2014-06-01 18:31:37 +03:00
if ( ( ev . type = = SDL_QUIT ) | | ( ev . type = = SDL_KEYDOWN & & ev . key . keysym . sym = = SDLK_F4 & & ( ev . key . keysym . mod & KMOD_ALT ) ) )
{
2016-01-18 15:05:43 +02:00
handleQuit ( ) ;
2014-06-01 18:31:37 +03:00
return ;
}
else if ( ev . type = = SDL_KEYDOWN & & ev . key . keysym . sym = = SDLK_F4 )
2009-08-17 13:47:08 +03:00
{
2014-06-01 18:31:37 +03:00
Settings full = settings . write [ " video " ] [ " fullscreen " ] ;
full - > Bool ( ) = ! full - > Bool ( ) ;
return ;
}
else if ( ev . type = = SDL_USEREVENT )
{
switch ( ev . user . code )
2009-08-22 16:59:15 +03:00
{
2015-06-21 19:30:19 +02:00
case FORCE_QUIT :
{
2016-01-18 15:05:43 +02:00
handleQuit ( false ) ;
return ;
2015-06-21 19:30:19 +02:00
}
break ;
2014-06-01 18:31:37 +03:00
case RETURN_TO_MAIN_MENU :
2010-08-20 16:34:39 +03:00
{
2012-04-09 05:53:50 +03:00
endGame ( ) ;
2014-06-01 18:31:37 +03:00
GH . curInt = CGPreGame : : create ( ) ; ;
2012-04-09 05:53:50 +03:00
GH . defActionsDef = 63 ;
2010-08-20 16:34:39 +03:00
}
2014-06-01 18:31:37 +03:00
break ;
case STOP_CLIENT :
client - > endGame ( false ) ;
break ;
case RESTART_GAME :
{
StartInfo si = * client - > getStartInfo ( true ) ;
endGame ( ) ;
startGame ( & si ) ;
}
break ;
case PREPARE_RESTART_CAMPAIGN :
{
auto si = reinterpret_cast < StartInfo * > ( ev . user . data1 ) ;
endGame ( ) ;
startGame ( si ) ;
}
break ;
case RETURN_TO_MENU_LOAD :
endGame ( ) ;
CGPreGame : : create ( ) ;
GH . defActionsDef = 63 ;
CGP - > update ( ) ;
CGP - > menu - > switchToTab ( vstd : : find_pos ( CGP - > menu - > menuNameToEntry , " load " ) ) ;
GH . curInt = CGP ;
break ;
case FULLSCREEN_TOGGLED :
fullScreenChanged ( ) ;
break ;
default :
2016-01-18 15:05:43 +02:00
logGlobal - > errorStream ( ) < < " Unknown user event. Code " < < ev . user . code ;
break ;
2014-03-07 16:21:09 +03:00
}
2014-06-01 18:31:37 +03:00
return ;
}
2015-11-29 00:56:18 +02:00
else if ( ev . type = = SDL_WINDOWEVENT )
{
switch ( ev . window . event ) {
case SDL_WINDOWEVENT_RESTORED :
fullScreenChanged ( ) ;
break ;
}
return ;
}
2014-06-01 18:31:37 +03:00
{
boost : : unique_lock < boost : : mutex > lock ( eventsM ) ;
events . push ( ev ) ;
2016-01-18 15:05:43 +02:00
}
2014-06-01 18:31:37 +03:00
}
static void mainLoop ( )
{
SettingsListener resChanged = settings . listen [ " video " ] [ " fullscreen " ] ;
resChanged ( [ ] ( const JsonNode & newState ) { CGuiHandler : : pushSDLEvent ( SDL_USEREVENT , FULLSCREEN_TOGGLED ) ; } ) ;
2014-06-01 19:50:19 +03:00
inGuiThread . reset ( new bool ( true ) ) ;
2014-06-01 18:31:37 +03:00
GH . mainFPSmng - > init ( ) ;
while ( 1 ) //main SDL events loop
{
SDL_Event ev ;
2016-01-18 15:05:43 +02:00
2014-06-01 18:31:37 +03:00
while ( 1 = = SDL_PollEvent ( & ev ) )
2012-02-20 00:03:43 +03:00
{
2014-06-01 18:31:37 +03:00
handleEvent ( ev ) ;
2012-02-20 00:03:43 +03:00
}
2016-01-18 15:05:43 +02:00
2014-06-01 18:31:37 +03:00
GH . renderFrame ( ) ;
2009-08-17 13:47:08 +03:00
}
}
2013-06-26 14:18:27 +03:00
void startGame ( StartInfo * options , CConnection * serv /* = nullptr*/ )
2009-08-17 13:47:08 +03:00
{
2013-06-21 23:59:32 +03:00
if ( vm . count ( " onlyAI " ) )
2009-08-17 13:47:08 +03:00
{
2013-06-22 21:22:44 +03:00
auto ais = vm . count ( " ai " ) ? vm [ " ai " ] . as < std : : vector < std : : string > > ( ) : std : : vector < std : : string > ( ) ;
2013-06-21 23:59:32 +03:00
int i = 0 ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : options - > playerInfos )
2009-08-17 13:47:08 +03:00
{
2013-06-29 16:05:48 +03:00
elem . second . playerID = PlayerSettings : : PLAYER_AI ;
2013-06-21 23:59:32 +03:00
if ( i < ais . size ( ) )
2013-06-29 16:05:48 +03:00
elem . second . name = ais [ i + + ] ;
2009-08-17 13:47:08 +03:00
}
}
2010-07-14 04:08:27 +03:00
2013-04-09 17:31:36 +03:00
client = new CClient ;
2010-08-01 17:46:19 +03:00
CPlayerInterface : : howManyPeople = 0 ;
2010-05-08 21:56:38 +03:00
switch ( options - > mode ) //new game
2009-08-17 13:47:08 +03:00
{
2010-08-18 12:50:25 +03:00
case StartInfo : : NEW_GAME :
case StartInfo : : CAMPAIGN :
2010-12-22 22:14:40 +02:00
case StartInfo : : DUEL :
2010-10-24 14:35:14 +03:00
client - > newGame ( serv , options ) ;
2010-05-08 21:56:38 +03:00
break ;
2010-08-18 12:50:25 +03:00
case StartInfo : : LOAD_GAME :
2009-08-17 13:47:08 +03:00
std : : string fname = options - > mapname ;
boost : : algorithm : : erase_last ( fname , " .vlgm1 " ) ;
2014-10-19 14:47:09 +03:00
if ( ! vm . count ( " loadplayer " ) )
client - > loadGame ( fname ) ;
else
client - > loadGame ( fname , vm . count ( " loadserver " ) , vm . count ( " loadhumanplayerindices " ) ? vm [ " loadhumanplayerindices " ] . as < std : : vector < int > > ( ) : std : : vector < int > ( ) , vm . count ( " loadnumplayers " ) ? vm [ " loadnumplayers " ] . as < int > ( ) : 1 , vm [ " loadplayer " ] . as < int > ( ) , vm . count ( " loadserverip " ) ? vm [ " loadserverip " ] . as < std : : string > ( ) : " " , vm . count ( " loadserverport " ) ? vm [ " loadserverport " ] . as < std : : string > ( ) : " 3030 " ) ;
2010-05-08 21:56:38 +03:00
break ;
2009-08-17 13:47:08 +03:00
}
2009-11-01 03:15:16 +02:00
2012-02-16 20:10:58 +03:00
client - > connectionHandler = new boost : : thread ( & CClient : : run , client ) ;
2009-10-04 05:02:45 +03:00
}
2013-06-17 18:45:55 +03:00
2013-12-17 15:12:25 +03:00
void endGame ( )
{
client - > endGame ( ) ;
vstd : : clear_pointer ( client ) ;
}
2015-06-21 19:30:19 +02:00
void handleQuit ( bool ask /* = true*/ )
2013-06-17 18:45:55 +03:00
{
2013-12-07 21:26:15 +03:00
auto quitApplication = [ ] ( )
{
2014-06-01 18:31:37 +03:00
if ( client )
endGame ( ) ;
2013-12-07 21:26:15 +03:00
delete console ;
console = nullptr ;
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 750 ) ) ;
if ( ! gNoGUI )
SDL_Quit ( ) ;
2013-06-17 18:45:55 +03:00
2013-12-07 21:26:15 +03:00
std : : cout < < " Ending... \n " ;
exit ( 0 ) ;
} ;
2015-06-21 19:30:19 +02:00
if ( client & & LOCPLINT & & ask )
2013-12-07 21:26:15 +03:00
{
CCS - > curh - > changeGraphic ( ECursor : : ADVENTURE , 0 ) ;
LOCPLINT - > showYesNoDialog ( CGI - > generaltexth - > allTexts [ 69 ] , quitApplication , 0 ) ;
}
else
{
quitApplication ( ) ;
}
2013-06-17 18:45:55 +03:00
}