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"
2008-08-04 18:56:36 +03:00
# include "CPreGame.h"
2008-09-17 13:18:22 +03:00
# include "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"
2007-12-06 20:55:58 +02:00
# include "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"
# include "../lib/CSpellHandler.h"
# 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"
2010-12-20 23:22:53 +02:00
# include "../lib/CObjectHandler.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"
2009-12-03 06:01:14 +02:00
# ifdef _WIN32
2009-11-28 19:21:54 +02:00
# include "SDL_syswm.h"
2009-12-03 06:01:14 +02:00
# endif
2010-12-20 23:22:53 +02:00
# include "../lib/CDefObjInfoHandler.h"
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 ;
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-23 14:42:27 +03:00
# ifndef VCMI_SDL1
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 ;
# endif // VCMI_SDL1
2014-05-21 19:04:34 +03:00
2013-06-26 14:18:27 +03:00
SDL_Surface * screen = nullptr , //main screen surface
* 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
2014-05-21 19:04:34 +03:00
2009-12-28 06:08:24 +02:00
static boost : : thread * mainGUIThread ;
2009-04-11 04:32:50 +03: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 ( ) ;
2009-11-01 03:15:16 +02:00
static void listenForEvents ( ) ;
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
2010-04-04 01:06:50 +03:00
# ifndef _WIN32
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
# include <getopt.h>
# endif
2012-01-03 04:55:26 +03:00
void startGameFromFile ( const std : : string & fname )
{
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
{
2013-05-19 18:14:23 +03:00
if ( ! fname . size ( ) | | ! boost : : filesystem : : exists ( fname ) )
throw std : : runtime_error ( " Startfile \" " + fname + " \" does not exist! " ) ;
2012-01-03 04:55:26 +03:00
CLoadFile out ( fname ) ;
2012-04-14 05:20:22 +03:00
if ( ! out . sfile | | ! * out . sfile )
{
2013-05-19 18:14:23 +03:00
throw std : : runtime_error ( " Cannot read from startfile \" " + fname + " \" ! " ) ;
2012-04-14 05:20:22 +03:00
}
2012-01-03 04:55:26 +03:00
out > > si ;
}
2013-05-19 18:14:23 +03:00
catch ( std : : exception & e )
{
2014-03-07 16:21:09 +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 ;
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " \t Initializing minors: " < < pomtime . getDiff ( ) ;
2009-07-18 06:13:13 +03:00
2009-06-24 09:56:36 +03:00
//initializing audio
// Note: because of interface button range, volume can only be a
// multiple of 11, from 0 to 99.
2010-12-19 16:39:56 +02:00
CCS - > soundh = new CSoundHandler ;
CCS - > soundh - > init ( ) ;
2012-01-12 18:23:00 +03:00
CCS - > soundh - > setVolume ( settings [ " general " ] [ " sound " ] . Float ( ) ) ;
2010-12-19 16:39:56 +02:00
CCS - > musich = new CMusicHandler ;
2011-08-17 23:44:14 +03:00
CCS - > musich - > init ( ) ;
2012-01-12 18:23:00 +03:00
CCS - > musich - > setVolume ( settings [ " general " ] [ " music " ] . Float ( ) ) ;
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " \t Initializing sound: " < < pomtime . getDiff ( ) ;
logGlobal - > infoStream ( ) < < " Initializing screen and sound handling: " < < tmh . getDiff ( ) ;
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
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Initializing VCMI_Lib: " < < tmh . getDiff ( ) ;
2009-06-24 09:56:36 +03:00
2011-12-14 00:23:17 +03:00
pomtime . getDiff ( ) ;
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
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 ( ) ;
logGlobal - > infoStream ( ) < < " \t Main graphics: " < < tmh . getDiff ( ) ;
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 ( ) ) ;
2014-03-01 21:46:54 +03:00
printf ( " Copyright (C) 2007-2014 VCMI dev team - see AUTHORS file \n " ) ;
2010-04-04 01:06:50 +03:00
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 " ) ;
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
}
2013-03-02 00:32:26 +03:00
# ifdef __APPLE__
void OSX_checkForUpdates ( ) ;
# endif
2010-04-04 01:06:50 +03:00
2014-01-05 20:48:50 +03:00
# if defined(_WIN32) && !defined (__GNUC__)
2013-04-20 14:34:01 +03:00
int wmain ( int argc , wchar_t * argv [ ] )
# elif defined(__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
{
2012-12-01 09:30:52 +03:00
# ifdef __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
2013-07-11 23:10:17 +03:00
FILE * check = fopen ( ( VCMIDirs : : get ( ) . userDataPath ( ) + " /game_data_prepared " ) . 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 " )
2012-01-03 04:55:26 +03:00
( " start " , po : : value < std : : string > ( ) , " 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 " )
2011-03-20 00:27:05 +02:00
( " nointro,i " , " skips intro movies " ) ;
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
}
2010-04-04 01:06:50 +03:00
2010-01-29 22:52:45 +02:00
//Set environment vars to make window centered. Sometimes work, sometimes not. :/
2011-03-22 15:19:07 +02:00
putenv ( ( char * ) " SDL_VIDEO_WINDOW_POS " ) ;
putenv ( ( char * ) " SDL_VIDEO_CENTERED=1 " ) ;
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 " ) ;
2013-04-09 17:31:36 +03: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 ;
2013-07-02 18:23:32 +03:00
* console - > cb = boost : : bind ( & processCommand , _1 ) ;
2009-06-23 11:14:49 +03:00
console - > start ( ) ;
atexit ( dispose ) ;
2008-11-09 00:29:19 +02:00
2014-02-27 23:44:20 +03:00
const auto logPath = VCMIDirs : : get ( ) . userCachePath ( ) + " /VCMI_Client_log.txt " ;
CBasicLogConfigurator logConfig ( logPath , console ) ;
2013-04-10 20:18:01 +03: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
2014-02-20 21:53:18 +03:00
# ifdef __ANDROID__
// boost will crash without this
setenv ( " LANG " , " C " , 1 ) ;
# endif
2013-04-09 17:31:36 +03:00
// Init filesystem and settings
2013-04-11 18:58:01 +03:00
preinitDLL ( : : console ) ;
2013-04-09 17:31:36 +03:00
settings . init ( ) ;
// Initialize logging based on settings
2013-04-10 20:18:01 +03:00
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 ;
2013-04-09 17:31:36 +03: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 " ) | |
! testFile ( " MODS/VCMI/MOD.JSON " , " VCMI mod " ) | |
2013-03-12 17:56:23 +03:00
! testFile ( " DATA/StackQueueBgBig.PCX " , " VCMI data " ) )
exit ( 1 ) ; // These are unrecoverable errors
// 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 ( ) ;
2013-04-09 17:31:36 +03: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 )
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Fatal error: failed to load settings! " ;
logGlobal - > errorStream ( ) < < " Possible reasons: " ;
2013-07-08 23:55:22 +03:00
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 " ;
2013-04-09 17:31:36 +03:00
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-23 13:51:38 +03:00
# ifdef VCMI_SDL1
2013-06-17 18:45:55 +03:00
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO ) )
2014-05-21 21:43:44 +03:00
# else
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) )
# endif
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 ) ;
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
2014-05-23 14:42:27 +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
2012-08-18 13:29:54 +03:00
# if 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
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " \t Initializing video: " < < pomtime . getDiff ( ) ;
2009-08-17 11:50:31 +03:00
2013-06-17 18:45:55 +03:00
2014-05-21 21:43:44 +03:00
//
//#ifndef __ANDROID__
// //we can properly play intro only in the main thread, so we have to move loading to the separate thread
// boost::thread loading(init);
//#else
2014-02-20 21:53:18 +03:00
// on Android threaded init is broken
init ( ) ;
2014-05-21 21:43:44 +03:00
//#endif
2010-12-22 22:14:40 +02:00
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
if ( ! vm . count ( " battle " ) & & ! vm . count ( " nointro " ) )
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-05-21 21:43:44 +03:00
//#ifndef __ANDROID__
// loading.join();
//#endif
2013-04-09 17:31:36 +03: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 " ) ;
2012-01-03 04:55:26 +03:00
2012-07-20 23:57:18 +03:00
std : : string fileToStartFrom ; //none by default
if ( vm . count ( " start " ) )
fileToStartFrom = vm [ " start " ] . as < std : : string > ( ) ;
2012-01-03 04:55:26 +03:00
2012-07-20 23:57:18 +03:00
if ( fileToStartFrom . size ( ) & & boost : : filesystem : : 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
{
if ( fileToStartFrom . size ( ) )
{
2013-04-09 17:31:36 +03: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 )
{
2013-06-26 14:18:27 +03:00
mainGUIThread = new boost : : thread ( & CGuiHandler : : run , & GH ) ;
2013-06-17 18:45:55 +03:00
listenForEvents ( ) ;
}
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 )
{
2013-04-09 17:31:36 +03:00
std : : stringstream sbuffer ;
sbuffer < < std : : string ( level , ' \t ' ) ;
2010-10-24 14:35:14 +03:00
2013-04-09 17:31:36 +03: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
2013-04-09 17:31:36 +03:00
sbuffer < < " inactive " ;
sbuffer < < " at " < < obj - > pos . x < < " x " < < obj - > pos . y ;
sbuffer < < " ( " < < obj - > pos . w < < " x " < < obj - > pos . h < < " ) " ;
2013-08-29 16:46:27 +03:00
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 ;
2009-04-04 22:26:41 +03:00
if ( LOCPLINT & & LOCPLINT - > cingconsole )
LOCPLINT - > cingconsole - > print ( message ) ;
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 ) ;
2013-04-09 17:31:36 +03: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 ;
2013-04-09 17:31:36 +03: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 " )
{
2013-04-09 17:31:36 +03:00
std : : cout < < " Screenbuf points to " ;
2009-08-17 11:50:31 +03:00
if ( screenBuf = = screen )
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " screen " ;
2009-08-17 11:50:31 +03:00
else if ( screenBuf = = screen2 )
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " screen2 " ;
2009-08-17 11:50:31 +03:00
else
2013-04-09 17:31:36 +03: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 ) ;
2013-04-09 17:31:36 +03:00
}
2008-09-17 13:18:22 +03:00
else if ( message = = " get txt " )
{
2013-04-09 17:31:36 +03:00
std : : cout < < " Command accepted. \t " ;
2013-06-10 20:02:37 +03:00
2013-07-08 23:55:22 +03:00
std : : string outPath = 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
{
2013-07-28 17:49:50 +03:00
std : : string outName = outPath + filename . getName ( ) ;
2013-06-10 20:02:37 +03:00
boost : : filesystem : : create_directories ( outName . substr ( 0 , outName . find_last_of ( " / " ) ) ) ;
std : : ofstream file ( outName + " .TXT " ) ;
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 ) ;
}
2013-04-09 17:31:36 +03:00
std : : cout < < " \r Extracting done :) \n " ;
2013-06-10 20:02:37 +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 ;
2013-04-09 17:31:36 +03: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 ) )
2013-04-09 17:31:36 +03: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 " )
{
2013-04-09 17:31:36 +03:00
std : : cout < < " Bonuses of " < < adventureInt - > selection - > getHoverText ( ) < < std : : endl
2011-07-13 21:39:02 +03:00
< < adventureInt - > selection - > getBonusList ( ) < < std : : endl ;
2010-07-12 13:20:25 +03:00
2013-04-09 17:31:36 +03: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
{
2013-04-09 17:31:36 +03: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
2013-04-09 17:31:36 +03: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 ) ) )
2013-04-09 17:31:36 +03: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 ) ;
2013-07-29 14:38:18 +03:00
std : : string outName = URI ;
2013-07-08 23:55:22 +03:00
std : : string outPath = VCMIDirs : : get ( ) . userCachePath ( ) + " /extracted/ " ;
2013-06-10 20:02:37 +03:00
boost : : filesystem : : create_directories ( outPath + outName ) ;
for ( size_t i = 0 ; i < cde - > ourImages . size ( ) ; i + + )
{
2013-06-20 00:26:27 +03:00
std : : string filename = outPath + outName + ' / ' + boost : : lexical_cast < std : : string > ( i ) + " .bmp " ;
2013-06-10 20:02:37 +03:00
SDL_SaveBMP ( cde - > ourImages [ i ] . bitmap , filename . c_str ( ) ) ;
}
}
else
logGlobal - > errorStream ( ) < < " File not found! " ;
}
else if ( cn = = " extract " )
{
std : : string URI ;
readed > > URI ;
if ( CResourceHandler : : get ( ) - > existsResource ( ResourceID ( URI ) ) )
{
2013-07-29 14:38:18 +03:00
std : : string outName = URI ;
2013-07-08 23:55:22 +03:00
std : : string outPath = VCMIDirs : : get ( ) . userCachePath ( ) + " /extracted/ " ;
2013-06-10 20:02:37 +03:00
std : : string fullPath = outPath + outName ;
2013-07-28 17:49:50 +03:00
auto data = CResourceHandler : : get ( ) - > load ( ResourceID ( URI ) ) - > readAll ( ) ;
2013-06-10 20:02:37 +03:00
boost : : filesystem : : create_directories ( fullPath . substr ( 0 , fullPath . find_last_of ( " / " ) ) ) ;
2013-09-08 19:49:23 +03:00
std : : ofstream outFile ( outPath + outName , std : : 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 ;
2013-04-09 17:31:36 +03: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 ;
2013-04-09 17:31:36 +03: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
{
2013-04-09 17:31:36 +03: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
}
}
2014-02-02 17:39:32 +03:00
else if ( cn = = " autoskip " )
{
Settings session = settings . write [ " session " ] ;
session [ " autoSkip " ] . Bool ( ) = ! session [ " autoSkip " ] . Bool ( ) ;
}
2012-02-17 00:46:28 +03:00
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 ) ;
2008-10-19 02:20:48 +03: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 ( )
{
2010-12-19 16:39:56 +02:00
if ( CCS - > videoh - > openAndPlayVideo ( " 3DOLOGO.SMK " , 60 , 40 , screen , true ) )
2009-06-24 09:56:36 +03:00
{
2010-12-19 16:39:56 +02:00
CCS - > videoh - > openAndPlayVideo ( " AZVS.SMK " , 60 , 80 , screen , 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 )
{
2014-05-23 14:42:27 +03:00
# ifndef VCMI_SDL1
2014-05-21 19:04:34 +03:00
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 ;
}
}
return false ;
2014-05-23 14:42:27 +03:00
# else
bpp = SDL_VideoModeOK ( w , h , bpp , SDL_SWSURFACE | ( fullscreen ? SDL_FULLSCREEN : 0 ) ) ;
return ! ( bpp = = 0 )
# endif // VCMI_SDL1
2014-05-21 19:04:34 +03:00
}
2014-05-23 14:42:27 +03:00
# ifndef VCMI_SDL1
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
{
2014-05-21 19:04:34 +03:00
// VCMI will only work with 2, 3 or 4 bytes per pixel
2011-12-14 00:23:17 +03:00
vstd : : amax ( bpp , 16 ) ;
vstd : : amin ( bpp , 32 ) ;
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 ;
}
if ( nullptr ! = mainRenderer )
{
SDL_DestroyRenderer ( mainRenderer ) ;
mainRenderer = nullptr ;
2009-07-16 02:58:47 +03:00
}
2014-05-21 19:04:34 +03:00
if ( nullptr ! = mainWindow )
{
SDL_DestroyWindow ( mainWindow ) ;
mainWindow = nullptr ;
}
2009-08-22 16:59:15 +03:00
bool bufOnScreen = ( screenBuf = = screen ) ;
2014-05-21 19:04:34 +03:00
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED , w , h , ( fullscreen ? SDL_FULLSCREEN : 0 ) ) ;
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
}
2014-05-21 19:04:34 +03:00
//create first available renderer. Use no flags, so HW accelerated will be preferred but SW renderer also will possible
mainRenderer = SDL_CreateRenderer ( mainWindow , - 1 , 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 " ) ;
}
SDL_RenderSetLogicalSize ( mainRenderer , w , h ) ;
2014-03-07 16:21:09 +03:00
2009-05-17 07:14:30 +03:00
2014-05-21 19:04:34 +03:00
screenBuf = nullptr ; //it`s a link - just nullify
2009-08-22 16:59:15 +03:00
2009-04-14 15:47:09 +03:00
if ( screen2 )
SDL_FreeSurface ( screen2 ) ;
2014-05-21 19:04:34 +03:00
//logGlobal->infoStream() << "New screen flags: " << screen->flags;
SDL_FreeSurface ( screen ) ;
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 ;
logGlobal - > errorStream ( ) < < SDL_GetError ( ) ;
throw std : : runtime_error ( " Unable to create surface " ) ;
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 " ) ;
2014-05-21 19:04:34 +03: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 " ) ;
}
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 ) ;
2014-05-21 19:04:34 +03:00
return true ;
}
2014-05-23 14:42:27 +03:00
# endif
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
# ifdef VCMI_SDL1
2014-05-21 19:04:34 +03:00
2014-05-23 14:42:27 +03:00
// VCMI will only work with 2, 3 or 4 bytes per pixel
vstd : : amax ( bpp , 16 ) ;
vstd : : amin ( bpp , 32 ) ;
// Try to use the best screen depth for the display
int suggestedBpp = SDL_VideoModeOK ( w , h , bpp , SDL_SWSURFACE | ( fullscreen ? SDL_FULLSCREEN : 0 ) ) ;
if ( suggestedBpp = = 0 )
2009-11-28 19:21:54 +02:00
{
2014-05-23 14:42:27 +03:00
logGlobal - > errorStream ( ) < < " Error: SDL says that " < < w < < " x " < < h < < " resolution is not available! " ;
2014-05-21 19:04:34 +03:00
return ;
2009-11-28 19:21:54 +02:00
}
2014-05-21 19:04:34 +03:00
2014-05-23 14:42:27 +03:00
bool bufOnScreen = ( screenBuf = = screen ) ;
2014-05-21 21:43:44 +03:00
2014-05-23 14:42:27 +03:00
if ( suggestedBpp ! = bpp )
{
logGlobal - > infoStream ( ) < < boost : : format ( " Using %s bpp (bits per pixel) for the video mode. Default or overridden setting was %s bpp. " ) % suggestedBpp % bpp ;
}
//For some reason changing fullscreen via config window checkbox result in SDL_Quit event
if ( resetVideo )
{
if ( screen ) //screen has been already initialized
SDL_QuitSubSystem ( SDL_INIT_VIDEO ) ;
SDL_InitSubSystem ( SDL_INIT_VIDEO ) ;
}
if ( ( screen = SDL_SetVideoMode ( w , h , suggestedBpp , SDL_SWSURFACE | ( fullscreen ? SDL_FULLSCREEN : 0 ) ) ) = = nullptr )
{
logGlobal - > errorStream ( ) < < " Requested screen resolution is not available ( " < < w < < " x " < < h < < " x " < < suggestedBpp < < " bpp) " ;
throw std : : runtime_error ( " Requested screen resolution is not available \n " ) ;
}
2014-05-21 19:04:34 +03:00
2014-05-23 14:42:27 +03:00
logGlobal - > infoStream ( ) < < " New screen flags: " < < screen - > flags ;
if ( screen2 )
SDL_FreeSurface ( screen2 ) ;
screen2 = CSDL_Ext : : copySurface ( screen ) ;
SDL_EnableUNICODE ( 1 ) ;
SDL_WM_SetCaption ( NAME . c_str ( ) , " " ) ; //set window title
2014-05-21 19:04:34 +03:00
SDL_ShowCursor ( SDL_DISABLE ) ;
2014-05-23 14:42:27 +03:00
SDL_EnableKeyRepeat ( SDL_DEFAULT_REPEAT_DELAY , SDL_DEFAULT_REPEAT_INTERVAL ) ;
# ifdef _WIN32
SDL_SysWMinfo wm ;
SDL_VERSION ( & wm . version ) ;
int getwm = SDL_GetWMInfo ( & wm ) ;
if ( getwm = = 1 )
{
int sw = GetSystemMetrics ( SM_CXSCREEN ) ,
sh = GetSystemMetrics ( SM_CYSCREEN ) ;
RECT curpos ;
GetWindowRect ( wm . window , & curpos ) ;
int ourw = curpos . right - curpos . left ,
ourh = curpos . bottom - curpos . top ;
SetWindowPos ( wm . window , 0 , ( sw - ourw ) / 2 , ( sh - ourh ) / 2 , 0 , 0 , SWP_NOZORDER | SWP_NOSIZE ) ;
}
else
{
logGlobal - > warnStream ( ) < < " Something went wrong, getwm= " < < getwm ;
logGlobal - > warnStream ( ) < < " SDL says: " < < SDL_GetError ( ) ;
logGlobal - > warnStream ( ) < < " Window won't be centered. " ;
}
# endif
2009-11-28 19:21:54 +02:00
//TODO: centering game window on other platforms (or does the environment do their job correctly there?)
2014-05-23 14:42:27 +03:00
screenBuf = bufOnScreen ? screen : screen2 ;
//setResolution = true;
# else
if ( ! recreateWindow ( w , h , bpp , fullscreen ) )
{
return ;
}
2014-05-21 19:04:34 +03:00
2014-05-23 14:42:27 +03:00
# endif // VCMI_SDL1
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 ;
2014-05-23 14:42:27 +03:00
# ifdef VCMI_SDL1
bitsPerPixel = SDL_VideoModeOK ( screen - > w , screen - > h , bitsPerPixel , SDL_SWSURFACE | ( toFullscreen ? SDL_FULLSCREEN : 0 ) ) ;
if ( bitsPerPixel = = 0 )
{
logGlobal - > errorStream ( ) < < " Error: SDL says that " < < screen - > w < < " x " < < screen - > h < < " resolution is not available! " ;
return ;
}
bool bufOnScreen = ( screenBuf = = screen ) ;
screen = SDL_SetVideoMode ( screen - > w , screen - > h , bitsPerPixel , SDL_SWSURFACE | ( toFullscreen ? SDL_FULLSCREEN : 0 ) ) ;
screenBuf = bufOnScreen ? screen : screen2 ;
# else
2014-05-21 19:04:34 +03:00
auto w = screen - > w ;
auto h = screen - > h ;
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
return ;
2014-05-23 14:42:27 +03:00
}
# endif
2012-02-24 23:41:14 +03:00
GH . totalRedraw ( ) ;
}
2009-11-01 03:15:16 +02:00
static void listenForEvents ( )
2009-08-17 13:47:08 +03:00
{
2012-02-24 23:41:14 +03:00
SettingsListener resChanged = settings . listen [ " video " ] [ " fullscreen " ] ;
2012-09-11 17:25:19 +03:00
resChanged ( [ ] ( const JsonNode & newState ) { CGuiHandler : : pushSDLEvent ( SDL_USEREVENT , FULLSCREEN_TOGGLED ) ; } ) ;
2012-02-24 23:41:14 +03:00
2009-08-17 13:47:08 +03:00
while ( 1 ) //main SDL events loop
{
2012-09-11 17:25:19 +03:00
SDL_Event ev ;
2014-05-23 19:46:54 +03:00
2012-09-11 17:25:19 +03:00
int ret = SDL_WaitEvent ( & ev ) ;
if ( ret = = 0 | | ( ev . type = = SDL_QUIT ) | |
( ev . type = = SDL_KEYDOWN & & ev . key . keysym . sym = = SDLK_F4 & & ( ev . key . keysym . mod & KMOD_ALT ) ) )
2009-08-17 13:47:08 +03:00
{
2013-06-17 18:45:55 +03:00
handleQuit ( ) ;
2013-12-07 21:26:15 +03:00
continue ;
2009-08-17 13:47:08 +03:00
}
2012-09-11 17:25:19 +03:00
else if ( LOCPLINT & & ev . type = = SDL_KEYDOWN & & ev . key . keysym . sym = = SDLK_F4 )
2009-08-17 13:47:08 +03:00
{
2012-02-24 23:41:14 +03:00
Settings full = settings . write [ " video " ] [ " fullscreen " ] ;
full - > Bool ( ) = ! full - > Bool ( ) ;
2009-11-01 03:15:16 +02:00
continue ;
2009-08-17 13:47:08 +03:00
}
2012-09-11 17:25:19 +03:00
else if ( ev . type = = SDL_USEREVENT )
2009-08-22 16:59:15 +03:00
{
2012-09-11 17:25:19 +03:00
switch ( ev . user . code )
2010-08-20 16:34:39 +03:00
{
2012-04-08 05:29:11 +03:00
case RETURN_TO_MAIN_MENU :
2012-09-18 20:47:52 +03:00
{
2013-04-09 17:31:36 +03:00
endGame ( ) ;
GH . curInt = CGPreGame : : create ( ) ; ;
GH . defActionsDef = 63 ;
2012-09-18 20:47:52 +03:00
}
2010-08-20 16:34:39 +03:00
break ;
2012-04-08 05:29:11 +03:00
case STOP_CLIENT :
client - > endGame ( false ) ;
break ;
2012-04-08 06:06:27 +03:00
case RESTART_GAME :
{
2012-05-23 00:08:16 +03:00
StartInfo si = * client - > getStartInfo ( true ) ;
2012-04-09 05:53:50 +03:00
endGame ( ) ;
2012-04-08 06:06:27 +03:00
startGame ( & si ) ;
}
break ;
2013-12-16 21:39:56 +03:00
case PREPARE_RESTART_CAMPAIGN :
{
auto si = reinterpret_cast < StartInfo * > ( ev . user . data1 ) ;
endGame ( ) ;
startGame ( si ) ;
}
break ;
2012-04-09 05:53:50 +03:00
case RETURN_TO_MENU_LOAD :
endGame ( ) ;
2012-05-18 20:35:46 +03:00
CGPreGame : : create ( ) ;
2012-04-09 05:53:50 +03:00
GH . defActionsDef = 63 ;
CGP - > update ( ) ;
CGP - > menu - > switchToTab ( vstd : : find_pos ( CGP - > menu - > menuNameToEntry , " load " ) ) ;
GH . curInt = CGP ;
break ;
2012-09-11 17:25:19 +03:00
case FULLSCREEN_TOGGLED :
fullScreenChanged ( ) ;
break ;
2012-04-08 04:43:40 +03:00
default :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Error: unknown user event. Code " < < ev . user . code ;
2012-04-08 04:43:40 +03:00
assert ( 0 ) ;
2010-08-20 16:34:39 +03:00
}
2010-01-29 22:52:45 +02:00
2009-11-01 03:15:16 +02:00
continue ;
2014-03-07 16:21:09 +03:00
}
2012-02-20 00:03:43 +03:00
{
2014-03-07 16:21:09 +03:00
boost : : unique_lock < boost : : mutex > lock ( eventsM ) ;
2012-02-20 00:03:43 +03:00
events . push ( ev ) ;
}
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 " ) ;
2009-12-28 06:08:24 +02:00
client - > loadGame ( fname ) ;
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 ) ;
}
2013-06-17 18:45:55 +03:00
void handleQuit ( )
{
2013-12-07 21:26:15 +03:00
auto quitApplication = [ ] ( )
{
if ( client ) client - > endGame ( ) ;
if ( mainGUIThread )
{
GH . terminate = true ;
if ( mainGUIThread - > get_id ( ) ! = boost : : this_thread : : get_id ( ) ) mainGUIThread - > join ( ) ;
delete mainGUIThread ;
mainGUIThread = nullptr ;
}
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 ) ;
} ;
if ( client & & LOCPLINT )
{
CCS - > curh - > changeGraphic ( ECursor : : ADVENTURE , 0 ) ;
LOCPLINT - > showYesNoDialog ( CGI - > generaltexth - > allTexts [ 69 ] , quitApplication , 0 ) ;
}
else
{
quitApplication ( ) ;
}
2013-06-17 18:45:55 +03:00
}