1 /***************************************************************************
2  *   Copyright (C) 2009 by Andrey Afletdinov <fheroes2@gmail.com>          *
3  *                                                                         *
4  *   Part of the Free Heroes2 Engine:                                      *
5  *   http://sourceforge.net/projects/fheroes2                              *
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21  ***************************************************************************/
22 
23 #include <cstdlib>
24 #include <iostream>
25 #include <string>
26 
27 #include "agg.h"
28 #include "audio.h"
29 #include "bin_info.h"
30 #include "core.h"
31 #include "cursor.h"
32 #include "embedded_image.h"
33 #include "game.h"
34 #include "game_logo.h"
35 #include "game_video.h"
36 #include "image_palette.h"
37 #include "localevent.h"
38 #include "logging.h"
39 #include "screen.h"
40 #include "settings.h"
41 #include "system.h"
42 #ifdef WITH_DEBUG
43 #include "tools.h"
44 #endif
45 #include "ui_tool.h"
46 #include "zzlib.h"
47 
48 namespace
49 {
GetCaption()50     std::string GetCaption()
51     {
52         return std::string( "Free Heroes of Might and Magic II, version: " + Settings::GetVersion() );
53     }
54 
PrintHelp(const char * basename)55     int PrintHelp( const char * basename )
56     {
57         COUT( "Usage: " << basename << " [OPTIONS]" );
58 #ifdef WITH_DEBUG
59         COUT( "  -d <level>\tprint debug messages, see src/engine/logging.h for possible values of <level> argument" );
60 #endif
61         COUT( "  -h\t\tprint this help message and exit" );
62 
63         return EXIT_SUCCESS;
64     }
65 
ReadConfigs()66     void ReadConfigs()
67     {
68         const std::string configurationFileName( "fheroes2.cfg" );
69         const std::string confFile = Settings::GetLastFile( "", configurationFileName );
70 
71         Settings & conf = Settings::Get();
72         if ( System::IsFile( confFile ) && conf.Read( confFile ) ) {
73             LocalEvent::Get().SetControllerPointerSpeed( conf.controllerPointerSpeed() );
74         }
75         else {
76             conf.Save( configurationFileName );
77         }
78     }
79 
InitConfigDir()80     void InitConfigDir()
81     {
82         const std::string configDir = System::GetConfigDirectory( "fheroes2" );
83 
84         if ( !configDir.empty() && !System::IsDirectory( configDir ) ) {
85             System::MakeDirectory( configDir );
86         }
87     }
88 
InitDataDir()89     void InitDataDir()
90     {
91         const std::string dataDir = System::GetDataDirectory( "fheroes2" );
92 
93         if ( dataDir.empty() )
94             return;
95 
96         const std::string dataFiles = System::ConcatePath( dataDir, "files" );
97         const std::string dataFilesSave = System::ConcatePath( dataFiles, "save" );
98 
99         if ( !System::IsDirectory( dataDir ) )
100             System::MakeDirectory( dataDir );
101 
102         if ( System::IsDirectory( dataDir, true ) && !System::IsDirectory( dataFiles ) )
103             System::MakeDirectory( dataFiles );
104 
105         if ( System::IsDirectory( dataFiles, true ) && !System::IsDirectory( dataFilesSave ) )
106             System::MakeDirectory( dataFilesSave );
107     }
108 
109     class DisplayInitializer
110     {
111     public:
DisplayInitializer()112         DisplayInitializer()
113         {
114             const Settings & conf = Settings::Get();
115 
116             fheroes2::engine().setVSync( conf.isVSyncEnabled() );
117 
118             fheroes2::Display & display = fheroes2::Display::instance();
119             if ( conf.FullScreen() != fheroes2::engine().isFullScreen() )
120                 fheroes2::engine().toggleFullScreen();
121 
122             display.resize( conf.VideoMode().width, conf.VideoMode().height );
123             display.fill( 0 ); // start from a black screen
124 
125             fheroes2::engine().setTitle( GetCaption() );
126 
127             SDL_ShowCursor( SDL_DISABLE ); // hide system cursor
128 
129             // Initialize local event processing.
130             LocalEvent::Get().RegisterCycling( fheroes2::PreRenderSystemInfo, fheroes2::PostRenderSystemInfo );
131 
132             // Update mouse cursor when switching between software emulation and OS mouse modes.
133             fheroes2::cursor().registerUpdater( Cursor::Refresh );
134 
135             const fheroes2::Image & appIcon = CreateImageFromZlib( 32, 32, iconImage, sizeof( iconImage ), true );
136             fheroes2::engine().setIcon( appIcon );
137         }
138 
139         DisplayInitializer( const DisplayInitializer & ) = delete;
140         DisplayInitializer & operator=( const DisplayInitializer & ) = delete;
141 
~DisplayInitializer()142         ~DisplayInitializer()
143         {
144             fheroes2::Display::instance().release();
145         }
146     };
147 }
148 
149 #if defined( _MSC_VER )
150 #undef main
151 #endif
152 
main(int argc,char ** argv)153 int main( int argc, char ** argv )
154 {
155     try {
156         const fheroes2::HardwareInitializer hardwareInitializer;
157         Logging::InitLog();
158 
159         DEBUG_LOG( DBG_ALL, DBG_INFO, GetCaption() );
160 
161         Settings & conf = Settings::Get();
162         conf.SetProgramPath( argv[0] );
163 
164         InitConfigDir();
165         InitDataDir();
166         ReadConfigs();
167 
168         // getopt
169         {
170             int opt;
171             while ( ( opt = System::GetCommandOptions( argc, argv, "hd:" ) ) != -1 )
172                 switch ( opt ) {
173 #ifdef WITH_DEBUG
174                 case 'd':
175                     conf.SetDebug( System::GetOptionsArgument() ? GetInt( System::GetOptionsArgument() ) : 0 );
176                     break;
177 #endif
178                 case '?':
179                 case 'h':
180                     return PrintHelp( argv[0] );
181 
182                 default:
183                     break;
184                 }
185         }
186 
187         std::set<fheroes2::SystemInitializationComponent> coreComponents{ fheroes2::SystemInitializationComponent::Audio,
188                                                                           fheroes2::SystemInitializationComponent::Video };
189 
190 #if defined( FHEROES2_VITA ) || defined( __SWITCH__ )
191         coreComponents.emplace( fheroes2::SystemInitializationComponent::GameController );
192 #endif
193 
194         const fheroes2::CoreInitializer coreInitializer( coreComponents );
195 
196         if ( Audio::isValid() ) {
197             Mixer::SetChannels( 16 );
198             Mixer::Volume( -1, Mixer::MaxVolume() * conf.SoundVolume() / 10 );
199 
200             Music::Volume( Mixer::MaxVolume() * conf.MusicVolume() / 10 );
201             Music::SetFadeIn( 900 );
202         }
203 
204         DEBUG_LOG( DBG_GAME, DBG_INFO, conf.String() );
205 
206         const DisplayInitializer displayInitializer;
207 
208         const AGG::AGGInitializer aggInitializer;
209 
210         // Load palette.
211         fheroes2::setGamePalette( AGG::ReadChunk( "KB.PAL" ) );
212 
213         // load BIN data
214         Bin_Info::InitBinInfo();
215 
216         // init game data
217         Game::Init();
218 
219         conf.setGameLanguage( conf.getGameLanguage() );
220 
221         if ( conf.isShowIntro() ) {
222             fheroes2::showTeamInfo();
223 
224             Video::ShowVideo( "H2XINTRO.SMK", Video::VideoAction::PLAY_TILL_VIDEO_END );
225         }
226 
227         // init cursor
228         const CursorRestorer cursorRestorer( true, Cursor::POINTER );
229 
230         Game::mainGameLoop( conf.isFirstGameRun() );
231     }
232     catch ( const std::exception & ex ) {
233         ERROR_LOG( "Exception '" << ex.what() << "' occured during application runtime." );
234         return EXIT_FAILURE;
235     }
236 
237     return EXIT_SUCCESS;
238 }
239