2017-07-13 10:26:03 +02: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
*
*/
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>
2016-11-28 20:00:56 +02:00
# include <boost/program_options.hpp>
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"
2018-01-05 19:21:07 +02:00
# include "mainmenu/CMainMenu.h"
# include "lobby/CSelectionBase.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 "../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"
2016-09-10 02:32:40 +02:00
# include "../lib/serializer/BinaryDeserializer.h"
# include "../lib/serializer/BinarySerializer.h"
2009-05-20 13:08:56 +03:00
# 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"
2016-02-24 21:26:39 +02:00
# include "../lib/StringConstants.h"
# include "../lib/CPlayerState.h"
2016-11-25 14:23:28 +02:00
# include "gui/CAnimation.h"
2018-01-05 19:21:07 +02:00
# include "../lib/serializer/Connection.h"
# include "CServerHandler.h"
# include <boost/asio.hpp>
# include "mainmenu/CPrologEpilogVideo.h"
2018-04-03 03:37:09 +02:00
# include <vstd/StringUtils.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
2017-05-25 19:57:20 +02:00
# ifdef VCMI_ANDROID
# include "lib/CAndroidVMHelper.h"
# 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 ;
2017-06-26 01:40:48 +02:00
namespace po_style = boost : : program_options : : command_line_style ;
2014-08-11 00:42:39 +03:00
namespace bfs = boost : : filesystem ;
2010-12-22 22:14:40 +02:00
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 ;
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-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 ) ;
2016-08-30 20:51:21 +02:00
static void setScreenRes ( int w , int h , int bpp , bool fullscreen , int displayIndex , bool resetVideo = true ) ;
2009-06-24 09:56:36 +03:00
void playIntro ( ) ;
2014-06-01 18:31:37 +03:00
static void mainLoop ( ) ;
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
2009-06-24 09:56:36 +03:00
void init ( )
{
2018-07-25 00:36:48 +02:00
CStopWatch tmh ;
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
2017-08-10 20:59:55 +02:00
logGlobal - > info ( " Initializing VCMI_Lib: %d ms " , tmh . getDiff ( ) ) ;
2009-06-24 09:56:36 +03:00
}
2009-04-14 15:47:09 +03:00
2018-01-13 10:43:26 +02:00
static void prog_version ( )
2010-04-04 01:06:50 +03:00
{
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
{
2017-06-26 01:40:48 +02:00
auto time = std : : time ( 0 ) ;
2011-12-14 00:23:17 +03:00
printf ( " %s - A Heroes of Might and Magic 3 clone \n " , GameConstants : : VCMI_VERSION . c_str ( ) ) ;
2017-06-26 01:40:48 +02:00
printf ( " Copyright (C) 2007-%d VCMI dev team - see AUTHORS file \n " , std : : localtime ( & time ) - > tm_year + 1900 ) ;
2015-12-13 21:14:37 +02: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 " ) ;
2010-04-04 01:06:50 +03:00
printf ( " \n " ) ;
2012-01-03 04:55:26 +03:00
std : : cout < < opts ;
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
2017-08-11 13:38:10 +02:00
logGlobal - > debug ( " SDL(category %d; priority %d) %s " , category , priority , message ) ;
2015-06-22 21:19:32 +02:00
}
2017-08-16 15:29:18 +02:00
# if defined(VCMI_WINDOWS) && !defined(__GNUC__) && defined(VCMI_WITH_DEBUG_CONSOLE)
int wmain ( int argc , wchar_t * argv [ ] )
# elif defined(VCMI_APPLE) || defined(VCMI_ANDROID)
2012-12-01 09:30:52 +03:00
int SDL_main ( int argc , char * argv [ ] )
2008-08-04 18:56:36 +03:00
# else
2017-08-09 00:09:29 +02: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
2017-08-13 16:20:57 +02:00
# ifndef VCMI_ANDROID
2014-03-23 15:59:03 +03:00
// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
2017-08-13 16:20:57 +02:00
boost : : filesystem : : current_path ( boost : : filesystem : : system_complete ( argv [ 0 ] ) . parent_path ( ) ) ;
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 " )
2017-06-04 14:59:11 +02:00
( " disable-shm " , " force disable shared memory usage " )
( " enable-shm-uuid " , " use UUID for shared memory identifier " )
2017-03-12 09:54:24 +02:00
( " testmap " , po : : value < std : : string > ( ) , " " )
2018-01-05 19:21:07 +02:00
( " testsave " , po : : value < std : : string > ( ) , " " )
2017-06-03 07:25:10 +02:00
( " spectate,s " , " enable spectator interface for AI-only games " )
( " spectate-ignore-hero " , " wont follow heroes on adventure map " )
( " spectate-hero-speed " , po : : value < int > ( ) , " hero movement speed on adventure map " )
( " spectate-battle-speed " , po : : value < int > ( ) , " battle animation speed for spectator " )
( " spectate-skip-battle " , " skip battles in spectator view " )
( " spectate-skip-battle-result " , " skip battle result window " )
2018-01-05 19:21:07 +02:00
( " onlyAI " , " allow to run without human player, all players will be default AI " )
2017-03-12 09:54:24 +02:00
( " headless " , " 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 " )
2016-09-16 19:01:44 +02:00
( " donotstartserver,d " , " do not attempt to start server and just connect to it instead server " )
2017-06-04 07:49:23 +02:00
( " serverport " , po : : value < si64 > ( ) , " override port specified in config file " )
( " saveprefix " , po : : value < std : : string > ( ) , " prefix for auto save files " )
( " savefrequency " , po : : value < si64 > ( ) , " limit auto save creation to each N days " ) ;
2010-12-22 22:14:40 +02:00
if ( argc > 1 )
{
try
{
2017-06-26 01:40:48 +02:00
po : : store ( po : : parse_command_line ( argc , argv , opts , po_style : : unix_style | po_style : : case_insensitive ) , vm ) ;
2010-12-22 22:14:40 +02:00
}
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-01-21 01:49:34 +03:00
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 ) ;
2017-07-16 11:58:05 +02: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 ( ) ;
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 ( ) ;
2017-08-11 13:38:10 +02:00
logGlobal - > info ( NAME ) ;
2017-08-10 20:59:55 +02:00
logGlobal - > info ( " Creating console and configuring logger: %d ms " , pomtime . getDiff ( ) ) ;
2017-08-11 13:38:10 +02:00
logGlobal - > info ( " The log file will be saved to %s " , 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 ( ) ;
2017-03-12 09:54:24 +02:00
Settings session = settings . write [ " session " ] ;
2018-04-03 03:37:09 +02:00
auto setSettingBool = [ ] ( std : : string key , std : : string arg ) {
Settings s = settings . write ( vstd : : split ( key , " / " ) ) ;
if ( : : vm . count ( arg ) )
s - > Bool ( ) = true ;
else if ( s - > isNull ( ) )
s - > Bool ( ) = false ;
} ;
auto setSettingInteger = [ ] ( std : : string key , std : : string arg , si64 defaultValue ) {
Settings s = settings . write ( vstd : : split ( key , " / " ) ) ;
if ( : : vm . count ( arg ) )
s - > Integer ( ) = : : vm [ arg ] . as < si64 > ( ) ;
else if ( s - > isNull ( ) )
s - > Integer ( ) = defaultValue ;
} ;
auto setSettingString = [ ] ( std : : string key , std : : string arg , std : : string defaultValue ) {
Settings s = settings . write ( vstd : : split ( key , " / " ) ) ;
if ( : : vm . count ( arg ) )
s - > String ( ) = : : vm [ arg ] . as < std : : string > ( ) ;
else if ( s - > isNull ( ) )
s - > String ( ) = defaultValue ;
} ;
setSettingBool ( " session/onlyai " , " onlyAI " ) ;
2017-03-12 09:54:24 +02:00
if ( vm . count ( " headless " ) )
{
session [ " headless " ] . Bool ( ) = true ;
2017-03-14 01:40:39 +02:00
session [ " onlyai " ] . Bool ( ) = true ;
2017-03-12 09:54:24 +02:00
}
2018-01-05 19:21:07 +02:00
else if ( vm . count ( " spectate " ) )
{
session [ " spectate " ] . Bool ( ) = true ;
session [ " spectate-ignore-hero " ] . Bool ( ) = vm . count ( " spectate-ignore-hero " ) ;
session [ " spectate-skip-battle " ] . Bool ( ) = vm . count ( " spectate-skip-battle " ) ;
session [ " spectate-skip-battle-result " ] . Bool ( ) = vm . count ( " spectate-skip-battle-result " ) ;
if ( vm . count ( " spectate-hero-speed " ) )
session [ " spectate-hero-speed " ] . Integer ( ) = vm [ " spectate-hero-speed " ] . as < int > ( ) ;
if ( vm . count ( " spectate-battle-speed " ) )
session [ " spectate-battle-speed " ] . Float ( ) = vm [ " spectate-battle-speed " ] . as < int > ( ) ;
}
2017-06-26 01:40:48 +02:00
// Server settings
2018-04-03 03:37:09 +02:00
setSettingBool ( " session/donotstartserver " , " donotstartserver " ) ;
2017-06-26 01:40:48 +02:00
2017-06-04 14:59:11 +02:00
// Shared memory options
2018-04-03 03:37:09 +02:00
setSettingBool ( " session/disable-shm " , " disable-shm " ) ;
setSettingBool ( " session/enable-shm-uuid " , " enable-shm-uuid " ) ;
2013-04-09 17:31:36 +03:00
2015-12-13 21:14:37 +02:00
// Init special testing settings
2018-04-03 03:37:09 +02:00
setSettingInteger ( " session/serverport " , " serverport " , 0 ) ;
setSettingString ( " session/saveprefix " , " saveprefix " , " " ) ;
setSettingInteger ( " general/saveFrequency " , " savefrequency " , 1 ) ;
2015-12-13 21:14:37 +02:00
// Initialize logging based on settings
logConfig . configure ( ) ;
2018-04-03 03:37:09 +02:00
logGlobal - > debug ( " settings = %s " , settings . toJsonNode ( ) . toJson ( ) ) ;
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 ;
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Error: %s was not found! " , message ) ;
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 ( ) ;
2017-08-10 20:59:55 +02:00
logGlobal - > info ( " Loading settings: %d ms " , pomtime . getDiff ( ) ) ;
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 )
{
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " Fatal error: failed to load settings! " ) ;
logGlobal - > error ( " Possible reasons: " ) ;
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " \t Corrupted local configuration file at %s/settings.json " , VCMIDirs : : get ( ) . userConfigPath ( ) ) ;
logGlobal - > error ( " \t Missing or corrupted global configuration file at %s/schemas/settings.json " , VCMIDirs : : get ( ) . userConfigPath ( ) ) ;
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " VCMI will now exit... " ) ;
2012-06-22 14:40:16 +03:00
exit ( EXIT_FAILURE ) ;
}
2017-03-12 09:54:24 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) )
2013-06-17 18:45:55 +03:00
{
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
{
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Something was wrong: %s " , SDL_GetError ( ) ) ;
2013-06-17 18:45:55 +03:00
exit ( - 1 ) ;
}
2017-06-16 22:54:24 +02:00
# ifdef VCMI_ANDROID
// manually setting egl pixel format, as a possible solution for sdl2<->android problem
// https://bugzilla.libsdl.org/show_bug.cgi?id=2291
SDL_GL_SetAttribute ( SDL_GL_RED_SIZE , 5 ) ;
SDL_GL_SetAttribute ( SDL_GL_GREEN_SIZE , 6 ) ;
SDL_GL_SetAttribute ( SDL_GL_BLUE_SIZE , 5 ) ;
SDL_GL_SetAttribute ( SDL_GL_DEPTH_SIZE , 0 ) ;
# endif // VCMI_ANDROID
2014-03-07 16:21:09 +03:00
GH . mainFPSmng - > init ( ) ; //(!)init here AFTER SDL_Init() while using SDL for FPS management
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
2017-08-11 13:38:10 +02:00
logGlobal - > info ( " Found %d render drivers " , driversCount ) ;
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 ;
2017-08-11 13:38:10 +02:00
logGlobal - > info ( " \t %s (active) " , driverName ) ;
2014-09-18 14:20:53 +03:00
}
else
2017-08-11 13:38:10 +02:00
logGlobal - > info ( " \t %s " , 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.
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Selected resolution %dx%d was not found! " , resPair . first , resPair . second ) ;
2014-09-18 14:20:53 +03:00
if ( conf . guiOptions . empty ( ) )
{
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " Unable to continue - no valid resolutions found! Please reinstall VCMI to fix this " ) ;
2014-09-18 14:20:53 +03:00
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 ( ) ) ;
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Falling back to %dx%d " , newRes [ " width " ] . Integer ( ) , newRes [ " height " ] . Integer ( ) ) ;
2014-09-18 14:20:53 +03:00
}
}
2016-09-08 21:33:47 +02:00
setScreenRes ( res [ " width " ] . Float ( ) , res [ " height " ] . Float ( ) , video [ " bitsPerPixel " ] . Float ( ) , video [ " fullscreen " ] . Bool ( ) , video [ " displayIndex " ] . Float ( ) ) ;
2017-08-10 20:59:55 +02:00
logGlobal - > info ( " \t Initializing screen: %d ms " , pomtime . getDiff ( ) ) ;
2013-06-17 18:45:55 +03:00
}
2009-08-17 11:50:31 +03:00
2017-07-16 11:58:05 +02:00
CCS = new CClientState ( ) ;
CGI = new CGameInfo ( ) ; //contains all global informations about game (texts, lodHandlers, map handler etc.)
2018-01-05 19:21:07 +02:00
CSH = new CServerHandler ( ) ;
2009-08-17 11:50:31 +03:00
// Initialize video
2014-05-24 16:52:43 +03:00
# ifdef DISABLE_VIDEO
2017-07-16 11:58:05 +02:00
CCS - > videoh = new CEmptyVideoPlayer ( ) ;
2011-08-08 10:12:18 +03:00
# else
2017-03-12 09:54:24 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) & & ! vm . count ( " disable-video " ) )
2017-07-16 11:58:05 +02:00
CCS - > videoh = new CVideoPlayer ( ) ;
2012-05-05 11:32:55 +03:00
else
2017-07-16 11:58:05 +02:00
CCS - > videoh = new CEmptyVideoPlayer ( ) ;
2011-08-08 10:12:18 +03:00
# endif
2012-08-18 13:29:54 +03:00
2017-08-10 20:59:55 +02:00
logGlobal - > info ( " \t Initializing video: %d ms " , pomtime . getDiff ( ) ) ;
2009-08-17 11:50:31 +03:00
2018-01-05 19:21:07 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) )
{
//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 ( ) ) ;
logGlobal - > info ( " Initializing screen and sound handling: %d ms " , pomtime . getDiff ( ) ) ;
}
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
2017-03-12 09:54:24 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) )
2013-06-17 18:45:55 +03:00
{
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 ( ) ;
2017-05-25 19:57:20 +02:00
SDL_SetRenderDrawColor ( mainRenderer , 0 , 0 , 0 , 255 ) ;
SDL_RenderClear ( mainRenderer ) ;
2018-07-25 00:36:48 +02:00
SDL_RenderPresent ( mainRenderer ) ;
2013-06-17 18:45:55 +03:00
}
2018-07-25 00:36:48 +02:00
2014-07-02 22:53:23 +03:00
# ifndef VCMI_NO_THREADED_LOAD
2017-05-25 19:57:20 +02:00
# ifdef VCMI_ANDROID // android loads the data quite slowly so we display native progressbar to prevent having only black screen for few seconds
{
CAndroidVMHelper vmHelper ;
vmHelper . callStaticVoidMethod ( CAndroidVMHelper : : NATIVE_METHODS_DEFAULT_CLASS , " showProgress " ) ;
# endif // ANDROID
loading . join ( ) ;
# ifdef VCMI_ANDROID
vmHelper . callStaticVoidMethod ( CAndroidVMHelper : : NATIVE_METHODS_DEFAULT_CLASS , " hideProgress " ) ;
}
# endif // ANDROID
# endif // THREADED
2018-07-25 00:36:48 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) )
{
pomtime . getDiff ( ) ;
CCS - > curh = new CCursorHandler ( ) ;
graphics = new Graphics ( ) ; // should be before curh->init()
CCS - > curh - > initCursor ( ) ;
logGlobal - > info ( " Screen handler: %d ms " , pomtime . getDiff ( ) ) ;
pomtime . getDiff ( ) ;
graphics - > load ( ) ; //must be after Content loading but should be in main thread
logGlobal - > info ( " Main graphics: %d ms " , pomtime . getDiff ( ) ) ;
CMessage : : init ( ) ;
logGlobal - > info ( " Message handler: %d ms " , pomtime . getDiff ( ) ) ;
CCS - > curh - > show ( ) ;
}
2017-08-10 20:59:55 +02:00
logGlobal - > info ( " Initialization of VCMI (together): %d ms " , total . getDiff ( ) ) ;
2009-08-17 11:50:31 +03:00
2017-07-01 15:30:13 +02:00
session [ " autoSkip " ] . Bool ( ) = vm . count ( " autoSkip " ) ;
session [ " oneGoodAI " ] . Bool ( ) = vm . count ( " oneGoodAI " ) ;
session [ " aiSolo " ] . Bool ( ) = false ;
2012-01-03 04:55:26 +03:00
2017-07-01 15:30:13 +02:00
if ( vm . count ( " testmap " ) )
{
session [ " testmap " ] . String ( ) = vm [ " testmap " ] . as < std : : string > ( ) ;
2018-01-05 19:21:07 +02:00
session [ " onlyai " ] . Bool ( ) = true ;
boost : : thread ( & CServerHandler : : debugStartTest , CSH , session [ " testmap " ] . String ( ) , false ) ;
2017-07-01 15:30:13 +02:00
}
2018-01-05 19:21:07 +02:00
else if ( vm . count ( " testsave " ) )
2017-07-01 15:30:13 +02:00
{
2018-01-05 19:21:07 +02:00
session [ " testsave " ] . String ( ) = vm [ " testsave " ] . as < std : : string > ( ) ;
session [ " onlyai " ] . Bool ( ) = true ;
boost : : thread ( & CServerHandler : : debugStartTest , CSH , session [ " testsave " ] . String ( ) , true ) ;
2017-07-01 15:30:13 +02:00
}
else
{
2018-07-25 00:36:48 +02:00
GH . curInt = CMainMenu : : create ( ) . get ( ) ;
2010-12-22 22:14:40 +02:00
}
2013-06-17 18:45:55 +03:00
2017-03-12 09:54:24 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) )
2013-06-17 18:45:55 +03:00
{
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 < < " ) " ;
2017-08-11 13:38:10 +02:00
logGlobal - > info ( 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 ) ;
}
2017-03-14 01:40:39 +02:00
void removeGUI ( )
{
// CClient::endGame
GH . curInt = nullptr ;
if ( GH . topInt ( ) )
GH . topInt ( ) - > deactivate ( ) ;
GH . listInt . clear ( ) ;
GH . objsToBlit . clear ( ) ;
GH . statusbar = nullptr ;
2017-08-10 18:39:27 +02:00
logGlobal - > info ( " Removed GUI. " ) ;
2017-03-14 01:40:39 +02:00
LOCPLINT = nullptr ;
2017-07-12 21:01:10 +02:00
}
2017-03-14 01:40:39 +02:00
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
{
2018-01-05 19:21:07 +02:00
if ( CSH - > client & & CSH - > client - > erm )
CSH - > 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 )
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " screen " ) ;
2009-08-17 11:50:31 +03:00
else if ( screenBuf = = screen2 )
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " screen2 " ) ;
2009-08-17 11:50:31 +03:00
else
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " ?!? " ) ;
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 " )
{
2018-01-05 19:21:07 +02:00
if ( ! CSH - > client )
2016-11-28 01:01:07 +02:00
{
std : : cout < < " Game in not active " ;
return ;
}
2008-11-16 03:06:15 +02:00
std : : string fname ;
readed > > fname ;
2018-01-05 19:21:07 +02:00
CSH - > client - > save ( fname ) ;
2008-11-16 03:06:15 +02:00
}
2016-11-28 01:01:07 +02:00
// else if(cn=="load")
// {
// // TODO: this code should end the running game and manage to call startGame instead
// std::string fname;
// readed >> fname;
2018-01-05 19:21:07 +02:00
// CSH->client->loadGame(fname);
2016-11-28 01:01:07 +02:00
// }
2017-11-16 22:23:03 +02:00
else if ( message = = " convert txt " )
{
std : : cout < < " Command accepted. \t " ;
const bfs : : path outPath =
VCMIDirs : : get ( ) . userCachePath ( ) / " extracted " ;
bfs : : create_directories ( outPath ) ;
auto extractVector = [ = ] ( const std : : vector < std : : string > & source , const std : : string & name )
{
2017-11-26 23:18:18 +02:00
JsonNode data ( JsonNode : : JsonType : : DATA_VECTOR ) ;
2017-11-16 22:23:03 +02:00
size_t index = 0 ;
for ( auto & line : source )
{
2017-11-26 23:18:18 +02:00
JsonNode lineNode ( JsonNode : : JsonType : : DATA_STRUCT ) ;
2017-11-16 22:23:03 +02:00
lineNode [ " text " ] . String ( ) = line ;
lineNode [ " index " ] . Integer ( ) = index + + ;
data . Vector ( ) . push_back ( lineNode ) ;
}
const bfs : : path filePath = outPath / ( name + " .json " ) ;
bfs : : ofstream file ( filePath ) ;
file < < data . toJson ( ) ;
} ;
extractVector ( VLC - > generaltexth - > allTexts , " generalTexts " ) ;
extractVector ( VLC - > generaltexth - > jktexts , " jkTexts " ) ;
extractVector ( VLC - > generaltexth - > arraytxt , " arrayTexts " ) ;
std : : cout < < " \r Extracting done :) \n " ;
std : : cout < < " Extracted files can be found in " < < outPath < < " directory \n " ;
}
2017-07-20 06:08:49 +02:00
else if ( message = = " get config " )
{
std : : cout < < " Command accepted. \t " ;
const bfs : : path outPath =
VCMIDirs : : get ( ) . userCachePath ( ) / " extracted " / " configuration " ;
bfs : : create_directories ( outPath ) ;
const std : : vector < std : : string > contentNames = { " heroClasses " , " artifacts " , " creatures " , " factions " , " objects " , " heroes " , " spells " , " skills " } ;
for ( auto contentName : contentNames )
{
auto & content = VLC - > modh - > content [ contentName ] ;
auto contentOutPath = outPath / contentName ;
bfs : : create_directories ( contentOutPath ) ;
for ( auto & iter : content . modData )
{
const JsonNode & modData = iter . second . modData ;
for ( auto & nameAndObject : modData . Struct ( ) )
{
const JsonNode & object = nameAndObject . second ;
std : : string name = CModHandler : : normalizeIdentifier ( object . meta , " core " , nameAndObject . first ) ;
boost : : algorithm : : replace_all ( name , " : " , " _ " ) ;
const bfs : : path filePath = contentOutPath / ( name + " .json " ) ;
bfs : : ofstream file ( filePath ) ;
file < < object . toJson ( ) ;
}
}
}
std : : cout < < " \r Extracting done :) \n " ;
std : : cout < < " Extracted files can be found in " < < outPath < < " directory \n " ;
}
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!
}
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 " )
{
2018-03-27 09:54:58 +02:00
bool jsonFormat = ( message = = " bonuses json " ) ;
auto format = [ jsonFormat ] ( const BonusList & b ) - > std : : string
{
if ( jsonFormat )
return b . toJsonNode ( ) . toJson ( true ) ;
std : : ostringstream ss ;
ss < < b ;
return ss . str ( ) ;
} ;
2014-06-24 20:39:36 +03:00
std : : cout < < " Bonuses of " < < adventureInt - > selection - > getObjectName ( ) < < std : : endl
2018-03-27 09:54:58 +02:00
< < format ( 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
{
2018-03-27 09:54:58 +02:00
std : : cout < < " \n Bonuses from " < < typeid ( * parent ) . name ( ) < < std : : endl < < format ( * parent - > getAllBonuses ( Selector : : all , Selector : : all ) ) < < 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 " )
{
2019-01-19 12:52:02 +02:00
for ( auto & child : GH . listInt )
2010-10-24 14:35:14 +03:00
{
2019-01-19 12:52:02 +02:00
const auto childPtr = child . get ( ) ;
if ( const CIntObject * obj = dynamic_cast < const CIntObject * > ( childPtr ) )
2010-10-24 14:35:14 +03:00
printInfoAboutIntObject ( obj , 0 ) ;
else
2019-01-19 12:52:02 +02:00
std : : cout < < typeid ( childPtr ) . 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 ;
2016-09-26 15:05:27 +02:00
2012-05-14 19:29:06 +03:00
if ( value = = " on " )
2016-09-26 15:05:27 +02:00
{
2012-05-14 19:29:06 +03:00
conf - > Bool ( ) = true ;
2016-09-26 15:05:27 +02:00
logGlobal - > info ( " Option %s enabled! " , what ) ;
}
2012-05-14 19:29:06 +03:00
else if ( value = = " off " )
2016-09-26 15:05:27 +02:00
{
2012-05-14 19:29:06 +03:00
conf - > Bool ( ) = false ;
2016-09-26 15:05:27 +02:00
logGlobal - > info ( " Option %s disabled! " , what ) ;
}
2011-05-25 16:11:03 +03:00
}
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 ;
2016-11-25 14:23:28 +02:00
std : : unique_ptr < CAnimation > anim = make_unique < CAnimation > ( URI ) ;
anim - > preload ( ) ;
anim - > exportBitmaps ( VCMIDirs : : get ( ) . userCachePath ( ) / " extracted " ) ;
2013-06-10 20:02:37 +03:00
}
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
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " File not found! " ) ;
2013-06-10 20:02:37 +03:00
}
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
{
2017-08-11 13:38:10 +02:00
logGlobal - > warn ( " Failed opening %s: %s " , fname , e . what ( ) ) ;
2017-08-10 18:39:27 +02:00
logGlobal - > warn ( " 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 giveTurn = [ & ] ( PlayerColor player )
{
YourTurn yt ;
yt . player = player ;
2018-01-05 19:21:07 +02:00
yt . daysWithoutCastle = CSH - > client - > getPlayer ( player ) - > daysWithoutCastle ;
yt . applyCl ( CSH - > client ) ;
2016-02-24 21:26:39 +02:00
} ;
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 " )
{
2016-11-25 21:12:22 +02:00
boost : : unique_lock < boost : : recursive_mutex > un ( * CPlayerInterface : : pim ) ;
2018-01-05 19:21:07 +02:00
if ( ! CSH - > client )
2016-11-28 01:01:07 +02:00
{
std : : cout < < " Game in not active " ;
return ;
}
2016-02-24 21:26:39 +02:00
PlayerColor color ;
if ( session [ " aiSolo " ] . Bool ( ) )
{
2018-01-05 19:21:07 +02:00
for ( auto & elem : CSH - > client - > gameState ( ) - > players )
2016-02-24 21:26:39 +02:00
{
if ( elem . second . human )
2018-01-05 19:21:07 +02:00
CSH - > client - > installNewPlayerInterface ( std : : make_shared < CPlayerInterface > ( elem . first ) , elem . first ) ;
2016-02-24 21:26:39 +02:00
}
}
else
{
color = LOCPLINT - > playerID ;
removeGUI ( ) ;
2018-01-05 19:21:07 +02:00
for ( auto & elem : CSH - > client - > gameState ( ) - > players )
2016-02-24 21:26:39 +02:00
{
if ( elem . second . human )
{
2018-01-05 19:21:07 +02:00
auto AiToGive = CSH - > client - > aiNameForPlayer ( * CSH - > client - > getPlayerSettings ( elem . first ) , false ) ;
2017-08-10 19:17:10 +02:00
logNetwork - > info ( " Player %s will be lead by %s " , elem . first , AiToGive ) ;
2018-01-05 19:21:07 +02:00
CSH - > client - > installNewPlayerInterface ( CDynLibHandler : : getNewAI ( AiToGive ) , elem . first ) ;
2016-02-24 21:26:39 +02:00
}
}
GH . totalRedraw ( ) ;
giveTurn ( color ) ;
}
session [ " aiSolo " ] . Bool ( ) = ! session [ " aiSolo " ] . Bool ( ) ;
}
else if ( cn = = " controlai " )
{
std : : string colorName ;
readed > > colorName ;
boost : : to_lower ( colorName ) ;
2016-11-25 21:12:22 +02:00
boost : : unique_lock < boost : : recursive_mutex > un ( * CPlayerInterface : : pim ) ;
2018-01-05 19:21:07 +02:00
if ( ! CSH - > client )
2016-11-28 01:01:07 +02:00
{
std : : cout < < " Game in not active " ;
return ;
}
2016-02-24 21:26:39 +02:00
PlayerColor color ;
if ( LOCPLINT )
color = LOCPLINT - > playerID ;
2018-01-05 19:21:07 +02:00
for ( auto & elem : CSH - > client - > gameState ( ) - > players )
2016-02-24 21:26:39 +02:00
{
if ( elem . second . human | | ( colorName . length ( ) & &
elem . first . getNum ( ) ! = vstd : : find_pos ( GameConstants : : PLAYER_COLOR_NAMES , colorName ) ) )
{
continue ;
}
removeGUI ( ) ;
2018-01-05 19:21:07 +02:00
CSH - > client - > installNewPlayerInterface ( std : : make_shared < CPlayerInterface > ( elem . first ) , elem . first ) ;
2016-02-24 21:26:39 +02:00
}
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
{
2016-11-25 21:12:22 +02:00
boost : : unique_lock < boost : : recursive_mutex > un ( * CPlayerInterface : : pim ) ;
2012-02-17 00:46:28 +03:00
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 ( )
{
2018-07-25 00:36:48 +02:00
if ( CCS - > videoh - > openAndPlayVideo ( " 3DOLOGO.SMK " , 0 , 1 , true , true ) )
2009-06-24 09:56:36 +03:00
{
2018-07-25 00:36:48 +02:00
CCS - > videoh - > openAndPlayVideo ( " AZVS.SMK " , 0 , 1 , true , true ) ;
2009-06-24 09:56:36 +03:00
}
}
2016-08-30 02:27:53 +02:00
static bool checkVideoMode ( int monitorIndex , int w , int h )
2014-05-21 19:04:34 +03:00
{
2016-08-30 02:27:53 +02:00
//we only check that our desired window size fits on screen
2014-05-21 19:04:34 +03:00
SDL_DisplayMode mode ;
2016-08-30 02:27:53 +02:00
if ( 0 ! = SDL_GetDesktopDisplayMode ( monitorIndex , & mode ) )
{
logGlobal - > error ( " SDL_GetDesktopDisplayMode failed " ) ;
logGlobal - > error ( SDL_GetError ( ) ) ;
return false ;
2014-05-21 19:04:34 +03:00
}
2016-08-30 02:27:53 +02:00
logGlobal - > info ( " Check display mode: requested %d x %d; available up to %d x %d " , w , h , mode . w , mode . h ) ;
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
}
2016-08-30 02:43:49 +02:00
static void cleanupRenderer ( )
2012-01-12 18:23:00 +03:00
{
2014-05-23 22:39:10 +03:00
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-08-30 02:43:49 +02:00
}
2016-08-30 20:51:21 +02:00
static bool recreateWindow ( int w , int h , int bpp , bool fullscreen , int displayIndex )
2016-08-30 02:43:49 +02:00
{
// VCMI will only work with 2 or 4 bytes per pixel
vstd : : amax ( bpp , 16 ) ;
vstd : : amin ( bpp , 32 ) ;
if ( bpp > 16 )
bpp = 32 ;
2016-08-30 20:51:21 +02:00
if ( displayIndex < 0 )
{
if ( mainWindow ! = nullptr )
displayIndex = SDL_GetWindowDisplayIndex ( mainWindow ) ;
if ( displayIndex < 0 )
displayIndex = 0 ;
}
if ( ! checkVideoMode ( displayIndex , w , h ) )
2016-08-30 02:43:49 +02:00
{
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Error: SDL says that %dx%d resolution is not available! " , w , h ) ;
2016-08-30 02:43:49 +02:00
return false ;
}
bool bufOnScreen = ( screenBuf = = screen ) ;
2018-07-25 00:36:48 +02:00
bool realFullscreen = settings [ " video " ] [ " realFullscreen " ] . Bool ( ) ;
2016-01-18 15:05:43 +02:00
2016-08-30 02:43:49 +02:00
cleanupRenderer ( ) ;
2016-01-18 15:05:43 +02:00
2018-07-25 00:36:48 +02:00
if ( nullptr = = mainWindow )
{
2017-07-08 18:01:58 +02:00
2018-07-25 00:36:48 +02:00
# ifdef VCMI_ANDROID
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , 0 , 0 , SDL_WINDOW_FULLSCREEN ) ;
# else
if ( fullscreen )
{
if ( realFullscreen )
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , w , h , SDL_WINDOW_FULLSCREEN ) ;
else //in windowed full-screen mode use desktop resolution
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , 0 , 0 , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
SDL_SetHint ( SDL_HINT_RENDER_SCALE_QUALITY , " linear " ) ;
}
else
{
mainWindow = SDL_CreateWindow ( NAME . c_str ( ) , SDL_WINDOWPOS_CENTERED_DISPLAY ( displayIndex ) , SDL_WINDOWPOS_CENTERED_DISPLAY ( displayIndex ) , w , h , 0 ) ;
}
# endif
if ( nullptr = = mainWindow )
{
throw std : : runtime_error ( " Unable to create window \n " ) ;
}
//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 ) ;
if ( nullptr = = mainRenderer )
{
throw std : : runtime_error ( " Unable to create renderer \n " ) ;
}
SDL_RendererInfo info ;
SDL_GetRendererInfo ( mainRenderer , & info ) ;
logGlobal - > info ( " Created renderer %s " , info . name ) ;
2017-07-08 18:01:58 +02:00
2014-05-23 21:23:04 +03:00
}
else
{
2018-07-25 00:36:48 +02:00
# ifndef VCMI_ANDROID
2016-01-18 15:05:43 +02:00
2018-07-25 00:36:48 +02:00
if ( fullscreen )
{
if ( realFullscreen )
{
SDL_SetWindowFullscreen ( mainWindow , SDL_WINDOW_FULLSCREEN ) ;
2016-01-18 15:05:43 +02:00
2018-07-25 00:36:48 +02:00
SDL_DisplayMode mode ;
SDL_GetDesktopDisplayMode ( displayIndex , & mode ) ;
mode . w = w ;
mode . h = h ;
2016-01-18 15:05:43 +02:00
2018-07-25 00:36:48 +02:00
SDL_SetWindowDisplayMode ( mainWindow , & mode ) ;
}
else
{
SDL_SetWindowFullscreen ( mainWindow , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
}
2009-07-16 02:58:47 +03:00
2018-07-25 00:36:48 +02:00
SDL_SetWindowPosition ( mainWindow , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) , SDL_WINDOWPOS_UNDEFINED_DISPLAY ( displayIndex ) ) ;
2016-01-18 15:05:43 +02:00
2018-07-25 00:36:48 +02:00
SDL_SetHint ( SDL_HINT_RENDER_SCALE_QUALITY , " linear " ) ;
}
else
{
SDL_SetWindowFullscreen ( mainWindow , 0 ) ;
SDL_SetWindowSize ( mainWindow , w , h ) ;
SDL_SetWindowPosition ( mainWindow , SDL_WINDOWPOS_CENTERED_DISPLAY ( displayIndex ) , SDL_WINDOWPOS_CENTERED_DISPLAY ( displayIndex ) ) ;
}
# endif
}
2016-01-18 15:05:43 +02:00
2017-07-08 18:01:58 +02:00
if ( ! ( fullscreen & & realFullscreen ) )
{
SDL_RenderSetLogicalSize ( mainRenderer , w , h ) ;
2016-01-18 15:05:43 +02:00
2018-08-11 16:41:25 +02:00
//following line is bugged not only on android, do not re-enable without checking
//#ifndef VCMI_ANDROID
// // on android this stretches the game to fit the screen, not preserving aspect and apparently this also breaks coordinates scaling in mouse events
// SDL_RenderSetViewport(mainRenderer, nullptr);
//#endif
2017-07-08 18:01:58 +02: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 )
{
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Unable to create surface %dx%d with %d bpp: %s " , w , h , bpp , SDL_GetError ( ) ) ;
2014-05-21 19:27:48 +03:00
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 )
{
2017-08-10 18:39:27 +02:00
logGlobal - > error ( " Unable to create screen texture " ) ;
2017-08-11 13:38:10 +02:00
logGlobal - > error ( SDL_GetError ( ) ) ;
2014-05-21 19:27:48 +03:00
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
2016-08-30 20:51:21 +02:00
static void setScreenRes ( int w , int h , int bpp , bool fullscreen , int displayIndex , bool resetVideo )
2014-05-21 19:04:34 +03:00
{
2016-08-30 20:51:21 +02:00
if ( ! recreateWindow ( w , h , bpp , fullscreen , displayIndex ) )
2014-05-23 14:42:27 +03:00
{
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
{
2016-11-25 21:12:22 +02:00
boost : : unique_lock < boost : : recursive_mutex > lock ( * CPlayerInterface : : 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
2016-08-30 20:51:21 +02:00
if ( ! recreateWindow ( w , h , bitsPerPixel , toFullscreen , - 1 ) )
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 ) ) )
{
2017-05-25 19:57:20 +02:00
# ifdef VCMI_ANDROID
handleQuit ( false ) ;
# else
2016-01-18 15:05:43 +02:00
handleQuit ( ) ;
2017-05-25 19:57:20 +02:00
# endif
2014-06-01 18:31:37 +03:00
return ;
}
2017-05-25 19:57:20 +02:00
# ifdef VCMI_ANDROID
else if ( ev . type = = SDL_KEYDOWN & & ev . key . keysym . scancode = = SDL_SCANCODE_AC_BACK )
{
handleQuit ( true ) ;
}
# endif
2014-06-01 18:31:37 +03:00
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
{
2018-01-05 19:21:07 +02:00
case EUserEvent : : FORCE_QUIT :
2015-06-21 19:30:19 +02:00
{
2016-01-18 15:05:43 +02:00
handleQuit ( false ) ;
return ;
2015-06-21 19:30:19 +02:00
}
break ;
2018-01-05 19:21:07 +02:00
case EUserEvent : : RETURN_TO_MAIN_MENU :
2010-08-20 16:34:39 +03:00
{
2018-01-05 19:21:07 +02:00
CSH - > endGameplay ( ) ;
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 ;
2018-01-05 19:21:07 +02:00
case EUserEvent : : RESTART_GAME :
2014-06-01 18:31:37 +03:00
{
2018-01-05 19:21:07 +02:00
CSH - > sendStartGame ( ) ;
2014-06-01 18:31:37 +03:00
}
break ;
2018-01-05 19:21:07 +02:00
case EUserEvent : : CAMPAIGN_START_SCENARIO :
2014-06-01 18:31:37 +03:00
{
2019-03-30 01:28:33 +02:00
CSH - > campaignServerRestartLock . set ( true ) ;
2018-01-05 19:21:07 +02:00
CSH - > endGameplay ( ) ;
auto ourCampaign = std : : shared_ptr < CCampaignState > ( reinterpret_cast < CCampaignState * > ( ev . user . data1 ) ) ;
auto & epilogue = ourCampaign - > camp - > scenarios [ ourCampaign - > mapsConquered . back ( ) ] . epilog ;
auto finisher = [ = ] ( )
{
if ( ourCampaign - > mapsRemaining . size ( ) )
{
CMM - > openCampaignLobby ( ourCampaign ) ;
}
} ;
if ( epilogue . hasPrologEpilog )
{
2018-07-25 00:36:48 +02:00
GH . pushIntT < CPrologEpilogVideo > ( epilogue , finisher ) ;
2018-01-05 19:21:07 +02:00
}
else
{
2019-03-30 01:28:33 +02:00
CSH - > campaignServerRestartLock . waitUntil ( false ) ;
2018-01-05 19:21:07 +02:00
finisher ( ) ;
}
2014-06-01 18:31:37 +03:00
}
break ;
2018-01-05 19:21:07 +02:00
case EUserEvent : : RETURN_TO_MENU_LOAD :
CSH - > endGameplay ( ) ;
2014-06-01 18:31:37 +03:00
GH . defActionsDef = 63 ;
2018-04-07 13:42:11 +02:00
CMM - > menu - > switchToTab ( " load " ) ;
2014-06-01 18:31:37 +03:00
break ;
2018-01-05 19:21:07 +02:00
case EUserEvent : : FULLSCREEN_TOGGLED :
2014-06-01 18:31:37 +03:00
fullScreenChanged ( ) ;
break ;
2018-01-05 19:21:07 +02:00
case EUserEvent : : INTERFACE_CHANGED :
2017-09-13 02:35:58 +02:00
if ( LOCPLINT )
LOCPLINT - > updateAmbientSounds ( ) ;
break ;
2014-06-01 18:31:37 +03:00
default :
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Unknown user event. Code %d " , ev . user . code ) ;
2016-01-18 15:05:43 +02:00
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 ;
}
2018-07-25 00:36:48 +02:00
//preprocessing
if ( ev . type = = SDL_MOUSEMOTION )
{
CCS - > curh - > cursorMove ( ev . motion . x , ev . motion . y ) ;
}
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 " ] ;
2018-01-05 19:21:07 +02:00
resChanged ( [ ] ( const JsonNode & newState ) { CGuiHandler : : pushSDLEvent ( SDL_USEREVENT , EUserEvent : : FULLSCREEN_TOGGLED ) ; } ) ;
2014-06-01 18:31:37 +03:00
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
2018-01-05 19:21:07 +02:00
CSH - > applyPacksOnLobbyScreen ( ) ;
2014-06-01 18:31:37 +03:00
GH . renderFrame ( ) ;
2009-08-17 13:47:08 +03:00
}
}
2017-07-15 13:08:20 +02:00
void handleQuit ( bool ask )
2013-06-17 18:45:55 +03:00
{
2013-12-07 21:26:15 +03:00
auto quitApplication = [ ] ( )
{
2018-01-05 19:21:07 +02:00
if ( CSH - > client )
CSH - > endGameplay ( ) ;
2018-11-07 10:11:07 +02:00
GH . listInt . clear ( ) ;
GH . objsToBlit . clear ( ) ;
CMM . reset ( ) ;
// cleanup, mostly to remove false leaks from analyzer
if ( CCS )
{
CCS - > musich - > release ( ) ;
CCS - > soundh - > release ( ) ;
vstd : : clear_pointer ( CCS ) ;
}
CMessage : : dispose ( ) ;
vstd : : clear_pointer ( graphics ) ;
vstd : : clear_pointer ( VLC ) ;
vstd : : clear_pointer ( console ) ; // should be removed after everything else since used by logging
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 750 ) ) ; //???
2017-03-12 09:54:24 +02:00
if ( ! settings [ " session " ] [ " headless " ] . Bool ( ) )
2016-08-30 02:43:49 +02:00
{
cleanupRenderer ( ) ;
2018-07-25 00:36:48 +02:00
if ( nullptr ! = mainRenderer )
{
SDL_DestroyRenderer ( mainRenderer ) ;
mainRenderer = nullptr ;
}
if ( nullptr ! = mainWindow )
{
SDL_DestroyWindow ( mainWindow ) ;
mainWindow = nullptr ;
}
2013-12-07 21:26:15 +03:00
SDL_Quit ( ) ;
2016-08-30 02:43:49 +02:00
}
2013-06-17 18:45:55 +03:00
2013-12-07 21:26:15 +03:00
std : : cout < < " Ending... \n " ;
exit ( 0 ) ;
} ;
2018-01-05 19:21:07 +02:00
if ( CSH - > client & & LOCPLINT & & ask )
2013-12-07 21:26:15 +03:00
{
CCS - > curh - > changeGraphic ( ECursor : : ADVENTURE , 0 ) ;
2018-04-07 13:34:11 +02:00
LOCPLINT - > showYesNoDialog ( CGI - > generaltexth - > allTexts [ 69 ] , quitApplication , nullptr ) ;
2013-12-07 21:26:15 +03:00
}
else
{
quitApplication ( ) ;
}
2013-06-17 18:45:55 +03:00
}