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 "agg.h"
24 #include "agg_image.h"
25 #include "audio.h"
26 #include "cursor.h"
27 #include "dialog.h"
28 #include "dialog_game_settings.h"
29 #include "dialog_language_selection.h"
30 #include "dialog_resolution.h"
31 #include "game.h"
32 #include "game_delays.h"
33 #include "game_interface.h"
34 #include "game_mainmenu_ui.h"
35 #include "icn.h"
36 #include "image.h"
37 #include "localevent.h"
38 #include "mus.h"
39 #include "settings.h"
40 #include "text.h"
41 #include "translations.h"
42 #include "ui_button.h"
43 #include "ui_dialog.h"
44 #include "ui_text.h"
45 
46 namespace
47 {
48     struct ButtonInfo
49     {
50         u32 frame;
51         fheroes2::Button & button;
52         bool isOver;
53         bool wasOver;
54     };
55 
56     enum
57     {
58         NEWGAME_DEFAULT = 1,
59         LOADGAME_DEFAULT = 5,
60         HIGHSCORES_DEFAULT = 9,
61         CREDITS_DEFAULT = 13,
62         QUIT_DEFAULT = 17
63     };
64 }
65 
mainGameLoop(bool isFirstGameRun)66 void Game::mainGameLoop( bool isFirstGameRun )
67 {
68     fheroes2::GameMode result = fheroes2::GameMode::MAIN_MENU;
69 
70     while ( result != fheroes2::GameMode::QUIT_GAME ) {
71         switch ( result ) {
72         case fheroes2::GameMode::MAIN_MENU:
73             result = Game::MainMenu( isFirstGameRun );
74             isFirstGameRun = false;
75             break;
76         case fheroes2::GameMode::NEW_GAME:
77             result = Game::NewGame();
78             break;
79         case fheroes2::GameMode::LOAD_GAME:
80             result = Game::LoadGame();
81             break;
82         case fheroes2::GameMode::HIGHSCORES:
83             result = Game::HighScores();
84             break;
85         case fheroes2::GameMode::CREDITS:
86             result = Game::Credits();
87             break;
88         case fheroes2::GameMode::NEW_STANDARD:
89             result = Game::NewStandard();
90             break;
91         case fheroes2::GameMode::NEW_CAMPAIGN_SELECTION:
92             result = Game::CampaignSelection();
93             break;
94         case fheroes2::GameMode::NEW_SUCCESSION_WARS_CAMPAIGN:
95             result = Game::NewSuccessionWarsCampaign();
96             break;
97         case fheroes2::GameMode::NEW_PRICE_OF_LOYALTY_CAMPAIGN:
98             result = Game::NewPriceOfLoyaltyCampaign();
99             break;
100         case fheroes2::GameMode::NEW_MULTI:
101             result = Game::NewMulti();
102             break;
103         case fheroes2::GameMode::NEW_HOT_SEAT:
104             result = Game::NewHotSeat();
105             break;
106         case fheroes2::GameMode::NEW_BATTLE_ONLY:
107             result = Game::NewBattleOnly();
108             break;
109         case fheroes2::GameMode::LOAD_STANDARD:
110             result = Game::LoadStandard();
111             break;
112         case fheroes2::GameMode::LOAD_CAMPAIN:
113             result = Game::LoadCampaign();
114             break;
115         case fheroes2::GameMode::LOAD_MULTI:
116             result = Game::LoadMulti();
117             break;
118         case fheroes2::GameMode::LOAD_HOT_SEAT:
119             result = Game::LoadHotseat();
120             break;
121         case fheroes2::GameMode::SCENARIO_INFO:
122             result = Game::ScenarioInfo();
123             break;
124         case fheroes2::GameMode::SELECT_SCENARIO:
125             result = Game::SelectScenario();
126             break;
127         case fheroes2::GameMode::START_GAME:
128             result = Game::StartGame();
129             break;
130         case fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO:
131             result = Game::SelectCampaignScenario( fheroes2::GameMode::MAIN_MENU, false );
132             break;
133         case fheroes2::GameMode::COMPLETE_CAMPAIGN_SCENARIO:
134             result = Game::CompleteCampaignScenario( false );
135             break;
136         case fheroes2::GameMode::COMPLETE_CAMPAIGN_SCENARIO_FROM_LOAD_FILE:
137             result = Game::CompleteCampaignScenario( true );
138             if ( result == fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO ) {
139                 result = Game::SelectCampaignScenario( fheroes2::GameMode::LOAD_CAMPAIN, false );
140             }
141             break;
142 
143         default:
144             break;
145         }
146     }
147 }
148 
MainMenu(bool isFirstGameRun)149 fheroes2::GameMode Game::MainMenu( bool isFirstGameRun )
150 {
151     Mixer::Pause();
152     AGG::PlayMusic( MUS::MAINMENU, true, true );
153 
154     Settings & conf = Settings::Get();
155 
156     conf.SetGameType( TYPE_MENU );
157 
158     // setup cursor
159     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
160 
161     fheroes2::Display & display = fheroes2::Display::instance();
162 
163     // image background
164     fheroes2::drawMainMenuScreen();
165     if ( isFirstGameRun ) {
166         fheroes2::SupportedLanguage currentLanguage = fheroes2::getLanguageFromAbbreviation( conf.getGameLanguage() );
167         const std::vector<fheroes2::SupportedLanguage> supportedLanguages = fheroes2::getSupportedLanguages();
168 
169         if ( supportedLanguages.size() > 1 ) {
170             currentLanguage = fheroes2::selectLanguage( supportedLanguages, currentLanguage );
171             conf.setGameLanguage( fheroes2::getLanguageAbbreviation( currentLanguage ) );
172         }
173 
174         Dialog::Message( _( "Greetings!" ), _( "Welcome to Free Heroes of Might and Magic II! Before starting the game please choose game resolution." ), Font::BIG,
175                          Dialog::OK );
176 
177         bool isResolutionChanged = Dialog::SelectResolution();
178         if ( isResolutionChanged ) {
179             fheroes2::drawMainMenuScreen();
180         }
181 
182         fheroes2::Text header( _( "Please Remember" ), { fheroes2::FontSize::NORMAL, fheroes2::FontColor::YELLOW } );
183 
184         fheroes2::MultiFontText body;
185         body.add( { _( "You can always change game resolution by clicking on the " ), { fheroes2::FontSize::NORMAL, fheroes2::FontColor::WHITE } } );
186         body.add( { _( "door" ), { fheroes2::FontSize::NORMAL, fheroes2::FontColor::YELLOW } } );
187         body.add( { _( " on the left side of main menu.\n\nTo switch between windowed and full screen modes\npress " ),
188                     { fheroes2::FontSize::NORMAL, fheroes2::FontColor::WHITE } } );
189         body.add( { _( "F4" ), { fheroes2::FontSize::NORMAL, fheroes2::FontColor::YELLOW } } );
190         body.add( { _( " key on the keyboard.\n\nEnjoy the game!" ), { fheroes2::FontSize::NORMAL, fheroes2::FontColor::WHITE } } );
191 
192         fheroes2::showMessage( header, body, Dialog::OK );
193 
194         conf.resetFirstGameRun();
195         conf.Save( "fheroes2.cfg" );
196     }
197 
198     LocalEvent & le = LocalEvent::Get();
199 
200     fheroes2::Button buttonNewGame( 0, 0, ICN::BTNSHNGL, NEWGAME_DEFAULT, NEWGAME_DEFAULT + 2 );
201     fheroes2::Button buttonLoadGame( 0, 0, ICN::BTNSHNGL, LOADGAME_DEFAULT, LOADGAME_DEFAULT + 2 );
202     fheroes2::Button buttonHighScores( 0, 0, ICN::BTNSHNGL, HIGHSCORES_DEFAULT, HIGHSCORES_DEFAULT + 2 );
203     fheroes2::Button buttonCredits( 0, 0, ICN::BTNSHNGL, CREDITS_DEFAULT, CREDITS_DEFAULT + 2 );
204     fheroes2::Button buttonQuit( 0, 0, ICN::BTNSHNGL, QUIT_DEFAULT, QUIT_DEFAULT + 2 );
205 
206     const fheroes2::Sprite & lantern10 = fheroes2::AGG::GetICN( ICN::SHNGANIM, 0 );
207     fheroes2::Blit( lantern10, display, lantern10.x(), lantern10.y() );
208 
209     const fheroes2::Sprite & lantern11 = fheroes2::AGG::GetICN( ICN::SHNGANIM, ICN::AnimationFrame( ICN::SHNGANIM, 0, 0 ) );
210     fheroes2::Blit( lantern11, display, lantern11.x(), lantern11.y() );
211 
212     buttonNewGame.draw();
213     buttonLoadGame.draw();
214     buttonHighScores.draw();
215     buttonCredits.draw();
216     buttonQuit.draw();
217 
218     display.render();
219 
220     const double scaleX = static_cast<double>( display.width() ) / fheroes2::Display::DEFAULT_WIDTH;
221     const double scaleY = static_cast<double>( display.height() ) / fheroes2::Display::DEFAULT_HEIGHT;
222     const fheroes2::Rect settingsArea( static_cast<int32_t>( 63 * scaleX ), static_cast<int32_t>( 202 * scaleY ), static_cast<int32_t>( 90 * scaleX ),
223                                        static_cast<int32_t>( 160 * scaleY ) );
224 
225     u32 lantern_frame = 0;
226 
227     std::vector<ButtonInfo> buttons{ { NEWGAME_DEFAULT, buttonNewGame, false, false },
228                                      { LOADGAME_DEFAULT, buttonLoadGame, false, false },
229                                      { HIGHSCORES_DEFAULT, buttonHighScores, false, false },
230                                      { CREDITS_DEFAULT, buttonCredits, false, false },
231                                      { QUIT_DEFAULT, buttonQuit, false, false } };
232 
233     for ( size_t i = 0; le.MouseMotion() && i < buttons.size(); ++i ) {
234         const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::BTNSHNGL, buttons[i].frame );
235         fheroes2::Blit( sprite, display, sprite.x(), sprite.y() );
236     }
237 
238     fheroes2::Sprite highlightDoor = fheroes2::AGG::GetICN( ICN::SHNGANIM, 18 );
239     fheroes2::ApplyPalette( highlightDoor, 8 );
240 
241     // mainmenu loop
242     while ( true ) {
243         if ( !le.HandleEvents( true, true ) ) {
244             if ( Interface::Basic::EventExit() == fheroes2::GameMode::QUIT_GAME ) {
245                 // if ( conf.ExtGameUseFade() )
246                 //    display.Fade();
247                 break;
248             }
249             else {
250                 continue;
251             }
252         }
253 
254         bool redrawScreen = false;
255 
256         for ( size_t i = 0; i < buttons.size(); ++i ) {
257             buttons[i].wasOver = buttons[i].isOver;
258 
259             if ( le.MousePressLeft( buttons[i].button.area() ) ) {
260                 buttons[i].button.drawOnPress();
261             }
262             else {
263                 buttons[i].button.drawOnRelease();
264             }
265 
266             buttons[i].isOver = le.MouseCursor( buttons[i].button.area() );
267 
268             if ( buttons[i].isOver != buttons[i].wasOver ) {
269                 u32 frame = buttons[i].frame;
270 
271                 if ( buttons[i].isOver && !buttons[i].wasOver )
272                     ++frame;
273 
274                 if ( !redrawScreen ) {
275                     redrawScreen = true;
276                 }
277                 const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::BTNSHNGL, frame );
278                 fheroes2::Blit( sprite, display, sprite.x(), sprite.y() );
279             }
280         }
281 
282         if ( redrawScreen ) {
283             display.render();
284         }
285 
286         if ( HotKeyPressEvent( EVENT_BUTTON_NEWGAME ) || le.MouseClickLeft( buttonNewGame.area() ) )
287             return fheroes2::GameMode::NEW_GAME;
288         else if ( HotKeyPressEvent( EVENT_BUTTON_LOADGAME ) || le.MouseClickLeft( buttonLoadGame.area() ) )
289             return fheroes2::GameMode::LOAD_GAME;
290         else if ( HotKeyPressEvent( EVENT_BUTTON_HIGHSCORES ) || le.MouseClickLeft( buttonHighScores.area() ) )
291             return fheroes2::GameMode::HIGHSCORES;
292         else if ( HotKeyPressEvent( EVENT_BUTTON_CREDITS ) || le.MouseClickLeft( buttonCredits.area() ) )
293             return fheroes2::GameMode::CREDITS;
294         else if ( HotKeyPressEvent( EVENT_DEFAULT_EXIT ) || le.MouseClickLeft( buttonQuit.area() ) ) {
295             if ( Interface::Basic::EventExit() == fheroes2::GameMode::QUIT_GAME ) {
296                 // if ( conf.ExtGameUseFade() )
297                 //     display.Fade();
298                 return fheroes2::GameMode::QUIT_GAME;
299             }
300         }
301         else if ( HotKeyPressEvent( EVENT_BUTTON_SETTINGS ) || le.MouseClickLeft( settingsArea ) ) {
302             fheroes2::openGameSettings();
303 
304             // force interface to reset area and positions
305             Interface::Basic::Get().Reset();
306             return fheroes2::GameMode::MAIN_MENU;
307         }
308 
309         // right info
310         if ( le.MousePressRight( buttonQuit.area() ) )
311             Dialog::Message( _( "Quit" ), _( "Quit Heroes of Might and Magic and return to the operating system." ), Font::BIG );
312         else if ( le.MousePressRight( buttonLoadGame.area() ) )
313             Dialog::Message( _( "Load Game" ), _( "Load a previously saved game." ), Font::BIG );
314         else if ( le.MousePressRight( buttonCredits.area() ) )
315             Dialog::Message( _( "Credits" ), _( "View the credits screen." ), Font::BIG );
316         else if ( le.MousePressRight( buttonHighScores.area() ) )
317             Dialog::Message( _( "High Scores" ), _( "View the high scores screen." ), Font::BIG );
318         else if ( le.MousePressRight( buttonNewGame.area() ) )
319             Dialog::Message( _( "New Game" ), _( "Start a single or multi-player game." ), Font::BIG );
320         else if ( le.MousePressRight( settingsArea ) )
321             Dialog::Message( _( "Game Settings" ), _( "Change language, resolution and settings of the game." ), Font::BIG );
322 
323         if ( validateAnimationDelay( MAIN_MENU_DELAY ) ) {
324             const fheroes2::Sprite & lantern12 = fheroes2::AGG::GetICN( ICN::SHNGANIM, ICN::AnimationFrame( ICN::SHNGANIM, 0, lantern_frame ) );
325             ++lantern_frame;
326             fheroes2::Blit( lantern12, display, lantern12.x(), lantern12.y() );
327             if ( le.MouseCursor( settingsArea ) ) {
328                 const int32_t offsetY = static_cast<int32_t>( 55 * scaleY );
329                 fheroes2::Blit( highlightDoor, 0, offsetY, display, highlightDoor.x(), highlightDoor.y() + offsetY, highlightDoor.width(), highlightDoor.height() );
330             }
331 
332             display.render();
333         }
334     }
335 
336     return fheroes2::GameMode::QUIT_GAME;
337 }
338