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 "game.h"
24 #include "agg.h"
25 #include "agg_image.h"
26 #include "audio.h"
27 #include "campaign_savedata.h"
28 #include "cursor.h"
29 #include "dialog.h"
30 #include "dialog_game_settings.h"
31 #include "game_delays.h"
32 #include "game_mainmenu_ui.h"
33 #include "game_video.h"
34 #include "icn.h"
35 #include "mus.h"
36 #include "settings.h"
37 #include "smk_decoder.h"
38 #include "text.h"
39 #include "translations.h"
40 #include "ui_button.h"
41 #include "ui_tool.h"
42 #include "world.h"
43 
44 #include <array>
45 #include <cmath>
46 
47 namespace
48 {
49     const int32_t buttonYStep = 66;
50 
51     // Draw button panel and return the position for a button.
drawButtonPanel()52     fheroes2::Point drawButtonPanel()
53     {
54         const fheroes2::Sprite & back = fheroes2::AGG::GetICN( ICN::HEROES, 0 );
55         const fheroes2::Sprite & panel = fheroes2::AGG::GetICN( ICN::REDBACK, 0 );
56 
57         const uint32_t panelOffset = fheroes2::Display::DEFAULT_HEIGHT - panel.height();
58         const uint32_t panelXPos = back.width() - ( panel.width() + panelOffset );
59         fheroes2::Blit( panel, fheroes2::Display::instance(), panelXPos, panelOffset );
60 
61         const int32_t buttonMiddlePos = panelXPos + SHADOWWIDTH + ( panel.width() - SHADOWWIDTH ) / 2;
62 
63         const fheroes2::Sprite & buttonSample = fheroes2::AGG::GetICN( ICN::BTNNEWGM, 0 );
64         const int32_t buttonWidth = buttonSample.width();
65         const int32_t buttonXPos = buttonMiddlePos - buttonWidth / 2 - 3; // 3 is button shadow
66         const int32_t buttonYPos = 46;
67 
68         return fheroes2::Point( buttonXPos, buttonYPos );
69     }
70 
getVideo(const std::string & fileName)71     std::unique_ptr<SMKVideoSequence> getVideo( const std::string & fileName )
72     {
73         std::string videoPath;
74         if ( !Video::isVideoFile( fileName, videoPath ) ) {
75             return nullptr;
76         }
77 
78         std::unique_ptr<SMKVideoSequence> video( new SMKVideoSequence( videoPath ) );
79         if ( video->frameCount() < 1 ) {
80             return nullptr;
81         }
82 
83         return video;
84     }
85 }
86 
NewStandard()87 fheroes2::GameMode Game::NewStandard()
88 {
89     Settings & conf = Settings::Get();
90     if ( conf.isCampaignGameType() )
91         conf.SetCurrentFileInfo( Maps::FileInfo() );
92     conf.SetGameType( Game::TYPE_STANDARD );
93     conf.SetPreferablyCountPlayers( 0 );
94     return fheroes2::GameMode::SELECT_SCENARIO;
95 }
96 
NewBattleOnly()97 fheroes2::GameMode Game::NewBattleOnly()
98 {
99     Settings & conf = Settings::Get();
100     conf.SetGameType( Game::TYPE_BATTLEONLY );
101 
102     return fheroes2::GameMode::NEW_MULTI;
103 }
104 
NewHotSeat()105 fheroes2::GameMode Game::NewHotSeat()
106 {
107     Settings & conf = Settings::Get();
108     if ( conf.isCampaignGameType() )
109         conf.SetCurrentFileInfo( Maps::FileInfo() );
110 
111     if ( conf.IsGameType( Game::TYPE_BATTLEONLY ) ) {
112         conf.SetPreferablyCountPlayers( 2 );
113         world.NewMaps( 10, 10 );
114         return StartBattleOnly();
115     }
116     else {
117         conf.SetGameType( Game::TYPE_HOTSEAT );
118         const u32 select = SelectCountPlayers();
119         if ( select ) {
120             conf.SetPreferablyCountPlayers( select );
121             return fheroes2::GameMode::SELECT_SCENARIO;
122         }
123     }
124     return fheroes2::GameMode::MAIN_MENU;
125 }
126 
CampaignSelection()127 fheroes2::GameMode Game::CampaignSelection()
128 {
129     if ( !isPriceOfLoyaltyCampaignPresent() ) {
130         return fheroes2::GameMode::NEW_SUCCESSION_WARS_CAMPAIGN;
131     }
132 
133     fheroes2::drawMainMenuScreen();
134     const fheroes2::Point buttonPos = drawButtonPanel();
135 
136     fheroes2::Button buttonSuccessionWars( buttonPos.x, buttonPos.y, ICN::X_LOADCM, 0, 1 );
137     fheroes2::Button buttonPriceOfLoyalty( buttonPos.x, buttonPos.y + buttonYStep * 1, ICN::X_LOADCM, 2, 3 );
138     fheroes2::Button buttonCancelGame( buttonPos.x, buttonPos.y + buttonYStep * 5, ICN::BTNMP, 8, 9 );
139 
140     buttonSuccessionWars.draw();
141     buttonPriceOfLoyalty.draw();
142     buttonCancelGame.draw();
143 
144     fheroes2::Display::instance().render();
145 
146     LocalEvent & le = LocalEvent::Get();
147     while ( le.HandleEvents() ) {
148         le.MousePressLeft( buttonSuccessionWars.area() ) ? buttonSuccessionWars.drawOnPress() : buttonSuccessionWars.drawOnRelease();
149         le.MousePressLeft( buttonPriceOfLoyalty.area() ) ? buttonPriceOfLoyalty.drawOnPress() : buttonPriceOfLoyalty.drawOnRelease();
150         le.MousePressLeft( buttonCancelGame.area() ) ? buttonCancelGame.drawOnPress() : buttonCancelGame.drawOnRelease();
151 
152         if ( le.MouseClickLeft( buttonSuccessionWars.area() ) || le.KeyPress( KEY_o ) )
153             return fheroes2::GameMode::NEW_SUCCESSION_WARS_CAMPAIGN;
154         if ( le.MouseClickLeft( buttonPriceOfLoyalty.area() ) || le.KeyPress( KEY_e ) )
155             return fheroes2::GameMode::NEW_PRICE_OF_LOYALTY_CAMPAIGN;
156         if ( HotKeyPressEvent( EVENT_DEFAULT_EXIT ) || le.MouseClickLeft( buttonCancelGame.area() ) )
157             return fheroes2::GameMode::MAIN_MENU;
158 
159         if ( le.MousePressRight( buttonSuccessionWars.area() ) ) {
160             Dialog::Message( _( "Original Campaign" ), _( "Either Roland's or Archibald's campaign from the original Heroes of Might and Magic II." ), Font::BIG );
161         }
162         if ( le.MousePressRight( buttonPriceOfLoyalty.area() ) ) {
163             Dialog::Message( _( "Expansion Campaign" ), _( "One of the four new campaigns from the Price of Loyalty expansion set." ), Font::BIG );
164         }
165         if ( le.MousePressRight( buttonCancelGame.area() ) ) {
166             Dialog::Message( _( "Cancel" ), _( "Cancel back to the main menu." ), Font::BIG );
167         }
168     }
169 
170     return fheroes2::GameMode::QUIT_GAME;
171 }
172 
NewSuccessionWarsCampaign()173 fheroes2::GameMode Game::NewSuccessionWarsCampaign()
174 {
175     Settings::Get().SetGameType( Game::TYPE_CAMPAIGN );
176 
177     Mixer::Pause();
178     Music::Pause();
179 
180     fheroes2::Display & display = fheroes2::Display::instance();
181     const fheroes2::Point roiOffset( ( display.width() - display.DEFAULT_WIDTH ) / 2, ( display.height() - display.DEFAULT_HEIGHT ) / 2 );
182 
183     display.fill( 0 );
184 
185     const Text loadingScreen( "Loading video. Please wait...", Font::BIG );
186     loadingScreen.Blit( display.width() / 2 - loadingScreen.w() / 2, display.height() / 2 - loadingScreen.h() / 2 );
187     display.render();
188 
189     std::vector<fheroes2::Rect> campaignRoi;
190     campaignRoi.emplace_back( 382 + roiOffset.x, 58 + roiOffset.y, 222, 298 );
191     campaignRoi.emplace_back( 30 + roiOffset.x, 59 + roiOffset.y, 224, 297 );
192 
193     // Reset all sound and music before playing videos
194     AGG::ResetMixer();
195 
196     const CursorRestorer cursorRestorer( false, Cursor::POINTER );
197 
198     Video::ShowVideo( "INTRO.SMK", Video::VideoAction::PLAY_TILL_VIDEO_END );
199 
200     AGG::ResetMixer();
201     Video::ShowVideo( "CHOOSEW.SMK", Video::VideoAction::IGNORE_VIDEO );
202     const int chosenCampaign = Video::ShowVideo( "CHOOSE.SMK", Video::VideoAction::LOOP_VIDEO, campaignRoi );
203 
204     Campaign::CampaignSaveData & campaignSaveData = Campaign::CampaignSaveData::Get();
205     campaignSaveData.reset();
206     campaignSaveData.setCampaignID( chosenCampaign );
207     campaignSaveData.setCurrentScenarioID( 0 );
208 
209     AGG::PlayMusic( MUS::VICTORY, true, true );
210 
211     return fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO;
212 }
213 
NewPriceOfLoyaltyCampaign()214 fheroes2::GameMode Game::NewPriceOfLoyaltyCampaign()
215 {
216     // TODO: Properly choose the campaign instead of this hackish way
217     Campaign::CampaignSaveData & campaignSaveData = Campaign::CampaignSaveData::Get();
218     campaignSaveData.reset();
219     campaignSaveData.setCampaignID( Campaign::PRICE_OF_LOYALTY_CAMPAIGN );
220     campaignSaveData.setCurrentScenarioID( 0 );
221 
222     std::array<std::unique_ptr<SMKVideoSequence>, 4> videos{ getVideo( "IVYPOL.SMK" ), getVideo( "IVYVOY.SMK" ), getVideo( "IVYWIZ.SMK" ), getVideo( "IVYDES.SMK" ) };
223 
224     if ( !videos[0] ) {
225         // File doesn't exist. Fallback to PoL campaign.
226         return fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO;
227     }
228 
229     const fheroes2::ScreenPaletteRestorer screenRestorer;
230 
231     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
232 
233     std::vector<uint8_t> palette = videos[0]->getCurrentPalette();
234     screenRestorer.changePalette( palette.data() );
235 
236     Cursor::Get().setVideoPlaybackCursor();
237 
238     fheroes2::Display & display = fheroes2::Display::instance();
239     const fheroes2::Point roiOffset( ( display.width() - display.DEFAULT_WIDTH ) / 2, ( display.height() - display.DEFAULT_HEIGHT ) / 2 );
240 
241     display.fill( 0 );
242 
243     const fheroes2::Sprite & background = fheroes2::AGG::GetICN( ICN::X_IVY, 1 );
244     fheroes2::Blit( background, 0, 0, display, roiOffset.x, roiOffset.y, background.width(), background.height() );
245 
246     const fheroes2::Sprite & campaignChoice = fheroes2::AGG::GetICN( ICN::X_IVY, 0 );
247     fheroes2::Blit( campaignChoice, 0, 0, display, roiOffset.x + campaignChoice.x(), roiOffset.y + campaignChoice.y(), campaignChoice.width(), campaignChoice.height() );
248 
249     display.render();
250 
251     const std::array<fheroes2::Rect, 4> activeCampaignArea{ fheroes2::Rect( roiOffset.x + 192, roiOffset.y + 23, 248, 163 ),
252                                                             fheroes2::Rect( roiOffset.x + 19, roiOffset.y + 120, 166, 193 ),
253                                                             fheroes2::Rect( roiOffset.x + 450, roiOffset.y + 120, 166, 193 ),
254                                                             fheroes2::Rect( roiOffset.x + 192, roiOffset.y + 240, 248, 163 ) };
255 
256     const std::array<fheroes2::Rect, 4> renderCampaignArea{ fheroes2::Rect( roiOffset.x + 214, roiOffset.y + 47, 248, 163 ),
257                                                             fheroes2::Rect( roiOffset.x + 41, roiOffset.y + 140, 166, 193 ),
258                                                             fheroes2::Rect( roiOffset.x + 472, roiOffset.y + 131, 166, 193 ),
259                                                             fheroes2::Rect( roiOffset.x + 214, roiOffset.y + 273, 248, 163 ) };
260 
261     size_t highlightCampaignId = videos.size();
262 
263     fheroes2::GameMode gameChoice = fheroes2::GameMode::NEW_CAMPAIGN_SELECTION;
264     uint64_t customDelay = 0;
265 
266     LocalEvent & le = LocalEvent::Get();
267     while ( le.HandleEvents( highlightCampaignId < videos.size() ? Game::isCustomDelayNeeded( customDelay ) : true ) ) {
268         if ( le.MouseClickLeft( activeCampaignArea[0] ) ) {
269             campaignSaveData.setCampaignID( Campaign::PRICE_OF_LOYALTY_CAMPAIGN );
270             gameChoice = fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO;
271             break;
272         }
273         if ( le.MouseClickLeft( activeCampaignArea[1] ) ) {
274             campaignSaveData.setCampaignID( Campaign::VOYAGE_HOME_CAMPAIGN );
275             gameChoice = fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO;
276             break;
277         }
278         if ( le.MouseClickLeft( activeCampaignArea[2] ) ) {
279             campaignSaveData.setCampaignID( Campaign::WIZARDS_ISLE_CAMPAIGN );
280             gameChoice = fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO;
281             break;
282         }
283         if ( le.MouseClickLeft( activeCampaignArea[3] ) ) {
284             campaignSaveData.setCampaignID( Campaign::DESCENDANTS_CAMPAIGN );
285             gameChoice = fheroes2::GameMode::SELECT_CAMPAIGN_SCENARIO;
286             break;
287         }
288 
289         const size_t beforeCampaignId = highlightCampaignId;
290 
291         highlightCampaignId = videos.size();
292 
293         for ( size_t i = 0; i < activeCampaignArea.size(); ++i ) {
294             if ( le.MouseCursor( activeCampaignArea[i] ) && videos[i] ) {
295                 highlightCampaignId = i;
296                 customDelay = static_cast<uint64_t>( std::lround( 1000.0 / videos[highlightCampaignId]->fps() ) );
297                 break;
298             }
299         }
300 
301         if ( highlightCampaignId != beforeCampaignId ) {
302             fheroes2::Blit( background, 0, 0, display, roiOffset.x, roiOffset.y, background.width(), background.height() );
303             fheroes2::Blit( campaignChoice, 0, 0, display, roiOffset.x + campaignChoice.x(), roiOffset.y + campaignChoice.y(), campaignChoice.width(),
304                             campaignChoice.height() );
305             if ( highlightCampaignId >= videos.size() ) {
306                 display.render();
307             }
308         }
309 
310         if ( highlightCampaignId < videos.size() && Game::validateCustomAnimationDelay( customDelay ) ) {
311             fheroes2::Rect frameRoi( renderCampaignArea[highlightCampaignId].x, renderCampaignArea[highlightCampaignId].y, 0, 0 );
312             videos[highlightCampaignId]->getNextFrame( display, frameRoi.x, frameRoi.y, frameRoi.width, frameRoi.height, palette );
313 
314             fheroes2::Blit( background, frameRoi.x - roiOffset.x, frameRoi.y - roiOffset.y, display, frameRoi.x, frameRoi.y, frameRoi.width, frameRoi.height );
315 
316             display.render( frameRoi );
317 
318             if ( videos[highlightCampaignId]->frameCount() <= videos[highlightCampaignId]->getCurrentFrame() ) {
319                 videos[highlightCampaignId]->resetFrame();
320             }
321         }
322     }
323 
324     display.fill( 0 );
325 
326     return gameChoice;
327 }
328 
NewNetwork()329 fheroes2::GameMode Game::NewNetwork()
330 {
331     Settings & conf = Settings::Get();
332     conf.SetGameType( conf.GameType() | Game::TYPE_NETWORK );
333 
334     // setup cursor
335     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
336 
337     fheroes2::drawMainMenuScreen();
338     const fheroes2::Point buttonPos = drawButtonPanel();
339 
340     fheroes2::Button buttonHost( buttonPos.x, buttonPos.y, ICN::BTNNET, 0, 1 );
341     fheroes2::Button buttonGuest( buttonPos.x, buttonPos.y + buttonYStep, ICN::BTNNET, 2, 3 );
342     fheroes2::Button buttonCancelGame( buttonPos.x, buttonPos.y + buttonYStep * 2, ICN::BTNMP, 8, 9 );
343 
344     buttonHost.draw();
345     buttonGuest.draw();
346     buttonCancelGame.draw();
347 
348     fheroes2::Display::instance().render();
349 
350     LocalEvent & le = LocalEvent::Get();
351     while ( le.HandleEvents() ) {
352         le.MousePressLeft( buttonHost.area() ) ? buttonHost.drawOnPress() : buttonHost.drawOnRelease();
353         le.MousePressLeft( buttonGuest.area() ) ? buttonGuest.drawOnPress() : buttonGuest.drawOnRelease();
354         le.MousePressLeft( buttonCancelGame.area() ) ? buttonCancelGame.drawOnPress() : buttonCancelGame.drawOnRelease();
355 
356         if ( HotKeyPressEvent( EVENT_DEFAULT_EXIT ) || le.MouseClickLeft( buttonCancelGame.area() ) )
357             return fheroes2::GameMode::MAIN_MENU;
358 
359         // right info
360         if ( le.MousePressRight( buttonHost.area() ) )
361             Dialog::Message( _( "Host" ), _( "The host sets up the game options. There can only be one host per network game." ), Font::BIG );
362         if ( le.MousePressRight( buttonGuest.area() ) )
363             Dialog::Message( _( "Guest" ),
364                              _( "The guest waits for the host to set up the game, then is automatically added in. There can be multiple guests for TCP/IP games." ),
365                              Font::BIG );
366         if ( le.MousePressRight( buttonCancelGame.area() ) )
367             Dialog::Message( _( "Cancel" ), _( "Cancel back to the main menu." ), Font::BIG );
368     }
369 
370     return fheroes2::GameMode::MAIN_MENU;
371 }
372 
NewGame()373 fheroes2::GameMode Game::NewGame()
374 {
375     Mixer::Pause();
376     AGG::PlayMusic( MUS::MAINMENU, true, true );
377     Settings & conf = Settings::Get();
378 
379     // reset last save name
380     Game::SetLastSavename( "" );
381 
382     // setup cursor
383     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
384 
385     fheroes2::Display & display = fheroes2::Display::instance();
386 
387     // load game settings
388     conf.BinaryLoad();
389 
390     fheroes2::drawMainMenuScreen();
391     const fheroes2::Point buttonPos = drawButtonPanel();
392 
393     fheroes2::Button buttonStandartGame( buttonPos.x, buttonPos.y, ICN::BTNNEWGM, 0, 1 );
394     fheroes2::ButtonSprite buttonCampainGame( buttonPos.x, buttonPos.y + buttonYStep * 1, fheroes2::AGG::GetICN( ICN::BTNNEWGM, 2 ),
395                                               fheroes2::AGG::GetICN( ICN::BTNNEWGM, 3 ), fheroes2::AGG::GetICN( ICN::NEW_CAMPAIGN_DISABLED_BUTTON, 0 ) );
396     fheroes2::Button buttonMultiGame( buttonPos.x, buttonPos.y + buttonYStep * 2, ICN::BTNNEWGM, 4, 5 );
397     fheroes2::Button buttonBattleGame( buttonPos.x, buttonPos.y + buttonYStep * 3, ICN::BTNBATTLEONLY, 0, 1 );
398     fheroes2::Button buttonSettings( buttonPos.x, buttonPos.y + buttonYStep * 4, ICN::BTNDCCFG, 4, 5 );
399     fheroes2::Button buttonCancelGame( buttonPos.x, buttonPos.y + buttonYStep * 5, ICN::BTNNEWGM, 6, 7 );
400 
401     if ( !isSuccessionWarsCampaignPresent() ) {
402         buttonCampainGame.disable();
403     }
404 
405     buttonStandartGame.draw();
406     buttonCampainGame.draw();
407     buttonMultiGame.draw();
408     buttonBattleGame.draw();
409     buttonSettings.draw();
410     buttonCancelGame.draw();
411 
412     display.render();
413 
414     LocalEvent & le = LocalEvent::Get();
415 
416     while ( le.HandleEvents() ) {
417         le.MousePressLeft( buttonStandartGame.area() ) ? buttonStandartGame.drawOnPress() : buttonStandartGame.drawOnRelease();
418 
419         if ( buttonCampainGame.isEnabled() ) {
420             le.MousePressLeft( buttonCampainGame.area() ) ? buttonCampainGame.drawOnPress() : buttonCampainGame.drawOnRelease();
421         }
422         le.MousePressLeft( buttonMultiGame.area() ) ? buttonMultiGame.drawOnPress() : buttonMultiGame.drawOnRelease();
423         le.MousePressLeft( buttonBattleGame.area() ) ? buttonBattleGame.drawOnPress() : buttonBattleGame.drawOnRelease();
424         le.MousePressLeft( buttonSettings.area() ) ? buttonSettings.drawOnPress() : buttonSettings.drawOnRelease();
425         le.MousePressLeft( buttonCancelGame.area() ) ? buttonCancelGame.drawOnPress() : buttonCancelGame.drawOnRelease();
426 
427         if ( HotKeyPressEvent( EVENT_BUTTON_STANDARD ) || le.MouseClickLeft( buttonStandartGame.area() ) )
428             return fheroes2::GameMode::NEW_STANDARD;
429         if ( buttonCampainGame.isEnabled() && ( HotKeyPressEvent( EVENT_BUTTON_CAMPAIGN ) || le.MouseClickLeft( buttonCampainGame.area() ) ) )
430             return fheroes2::GameMode::NEW_CAMPAIGN_SELECTION;
431         if ( HotKeyPressEvent( EVENT_BUTTON_MULTI ) || le.MouseClickLeft( buttonMultiGame.area() ) )
432             return fheroes2::GameMode::NEW_MULTI;
433         if ( HotKeyPressEvent( EVENT_BUTTON_SETTINGS ) || le.MouseClickLeft( buttonSettings.area() ) ) {
434             fheroes2::openGameSettings();
435             return fheroes2::GameMode::MAIN_MENU;
436         }
437         if ( HotKeyPressEvent( EVENT_DEFAULT_EXIT ) || le.MouseClickLeft( buttonCancelGame.area() ) )
438             return fheroes2::GameMode::MAIN_MENU;
439 
440         if ( HotKeyPressEvent( EVENT_BUTTON_BATTLEONLY ) || le.MouseClickLeft( buttonBattleGame.area() ) )
441             return fheroes2::GameMode::NEW_BATTLE_ONLY;
442 
443         if ( le.MousePressRight( buttonStandartGame.area() ) )
444             Dialog::Message( _( "Standard Game" ), _( "A single player game playing out a single map." ), Font::BIG );
445         else if ( le.MousePressRight( buttonCampainGame.area() ) )
446             Dialog::Message( _( "Campaign Game" ), _( "A single player game playing through a series of maps." ), Font::BIG );
447         else if ( le.MousePressRight( buttonMultiGame.area() ) )
448             Dialog::Message( _( "Multi-Player Game" ), _( "A multi-player game, with several human players completing against each other on a single map." ), Font::BIG );
449         else if ( le.MousePressRight( buttonBattleGame.area() ) )
450             Dialog::Message( _( "Battle Only" ), _( "Setup and play a battle without loading any map." ), Font::BIG );
451         else if ( le.MousePressRight( buttonSettings.area() ) )
452             Dialog::Message( _( "Game Settings" ), _( "Change language, resolution and settings of the game." ), Font::BIG );
453         else if ( le.MousePressRight( buttonCancelGame.area() ) )
454             Dialog::Message( _( "Cancel" ), _( "Cancel back to the main menu." ), Font::BIG );
455     }
456 
457     return fheroes2::GameMode::QUIT_GAME;
458 }
459 
NewMulti()460 fheroes2::GameMode Game::NewMulti()
461 {
462     Settings & conf = Settings::Get();
463 
464     if ( !( conf.IsGameType( Game::TYPE_BATTLEONLY ) ) )
465         conf.SetGameType( Game::TYPE_STANDARD );
466 
467     // setup cursor
468     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
469 
470     fheroes2::drawMainMenuScreen();
471     const fheroes2::Point buttonPos = drawButtonPanel();
472 
473     fheroes2::Button buttonHotSeat( buttonPos.x, buttonPos.y, ICN::BTNMP, 0, 1 );
474     fheroes2::Button buttonNetwork( buttonPos.x, buttonPos.y + buttonYStep * 1, ICN::BTNMP, 2, 3 );
475     fheroes2::Button buttonCancelGame( buttonPos.x, buttonPos.y + buttonYStep * 5, ICN::BTNMP, 8, 9 );
476 
477     buttonHotSeat.draw();
478     buttonCancelGame.draw();
479     buttonNetwork.disable();
480 
481     fheroes2::Display::instance().render();
482 
483     LocalEvent & le = LocalEvent::Get();
484     // newgame loop
485     while ( le.HandleEvents() ) {
486         le.MousePressLeft( buttonHotSeat.area() ) ? buttonHotSeat.drawOnPress() : buttonHotSeat.drawOnRelease();
487         le.MousePressLeft( buttonCancelGame.area() ) ? buttonCancelGame.drawOnPress() : buttonCancelGame.drawOnRelease();
488 
489         if ( le.MouseClickLeft( buttonHotSeat.area() ) || HotKeyPressEvent( EVENT_BUTTON_HOTSEAT ) )
490             return fheroes2::GameMode::NEW_HOT_SEAT;
491         if ( HotKeyPressEvent( EVENT_DEFAULT_EXIT ) || le.MouseClickLeft( buttonCancelGame.area() ) )
492             return fheroes2::GameMode::MAIN_MENU;
493 
494         // right info
495         if ( le.MousePressRight( buttonHotSeat.area() ) )
496             Dialog::Message( _( "Hot Seat" ),
497                              _( "Play a Hot Seat game, where 2 to 4 players play around the same computer, switching into the 'Hot Seat' when it is their turn." ),
498                              Font::BIG );
499         if ( le.MousePressRight( buttonCancelGame.area() ) )
500             Dialog::Message( _( "Cancel" ), _( "Cancel back to the main menu." ), Font::BIG );
501     }
502 
503     return fheroes2::GameMode::QUIT_GAME;
504 }
505 
SelectCountPlayers(void)506 u32 Game::SelectCountPlayers( void )
507 {
508     // setup cursor
509     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
510 
511     fheroes2::drawMainMenuScreen();
512     const fheroes2::Point buttonPos = drawButtonPanel();
513 
514     fheroes2::Button button2Players( buttonPos.x, buttonPos.y, ICN::BTNHOTST, 0, 1 );
515     fheroes2::Button button3Players( buttonPos.x, buttonPos.y + buttonYStep * 1, ICN::BTNHOTST, 2, 3 );
516     fheroes2::Button button4Players( buttonPos.x, buttonPos.y + buttonYStep * 2, ICN::BTNHOTST, 4, 5 );
517     fheroes2::Button button5Players( buttonPos.x, buttonPos.y + buttonYStep * 3, ICN::BTNHOTST, 6, 7 );
518     fheroes2::Button button6Players( buttonPos.x, buttonPos.y + buttonYStep * 4, ICN::BTNHOTST, 8, 9 );
519     fheroes2::Button buttonCancel( buttonPos.x, buttonPos.y + buttonYStep * 5, ICN::BTNNEWGM, 6, 7 );
520 
521     button2Players.draw();
522     button3Players.draw();
523     button4Players.draw();
524     button5Players.draw();
525     button6Players.draw();
526     buttonCancel.draw();
527 
528     fheroes2::Display::instance().render();
529 
530     LocalEvent & le = LocalEvent::Get();
531     while ( le.HandleEvents() ) {
532         le.MousePressLeft( button2Players.area() ) ? button2Players.drawOnPress() : button2Players.drawOnRelease();
533         le.MousePressLeft( button3Players.area() ) ? button3Players.drawOnPress() : button3Players.drawOnRelease();
534         le.MousePressLeft( button4Players.area() ) ? button4Players.drawOnPress() : button4Players.drawOnRelease();
535         le.MousePressLeft( button5Players.area() ) ? button5Players.drawOnPress() : button5Players.drawOnRelease();
536         le.MousePressLeft( button6Players.area() ) ? button6Players.drawOnPress() : button6Players.drawOnRelease();
537 
538         le.MousePressLeft( buttonCancel.area() ) ? buttonCancel.drawOnPress() : buttonCancel.drawOnRelease();
539 
540         if ( le.MouseClickLeft( button2Players.area() ) || le.KeyPress( KEY_2 ) )
541             return 2;
542         if ( le.MouseClickLeft( button3Players.area() ) || le.KeyPress( KEY_3 ) )
543             return 3;
544         if ( le.MouseClickLeft( button4Players.area() ) || le.KeyPress( KEY_4 ) )
545             return 4;
546         if ( le.MouseClickLeft( button5Players.area() ) || le.KeyPress( KEY_5 ) )
547             return 5;
548         if ( le.MouseClickLeft( button6Players.area() ) || le.KeyPress( KEY_6 ) )
549             return 6;
550 
551         if ( HotKeyPressEvent( Game::EVENT_DEFAULT_EXIT ) || le.MouseClickLeft( buttonCancel.area() ) )
552             return 0;
553 
554         // right info
555         if ( le.MousePressRight( button2Players.area() ) )
556             Dialog::Message( _( "2 Players" ), _( "Play with 2 human players, and optionally, up to 4 additional computer players." ), Font::BIG );
557         if ( le.MousePressRight( button3Players.area() ) )
558             Dialog::Message( _( "3 Players" ), _( "Play with 3 human players, and optionally, up to 3 additional computer players." ), Font::BIG );
559         if ( le.MousePressRight( button4Players.area() ) )
560             Dialog::Message( _( "4 Players" ), _( "Play with 4 human players, and optionally, up to 2 additional computer players." ), Font::BIG );
561         if ( le.MousePressRight( button5Players.area() ) )
562             Dialog::Message( _( "5 Players" ), _( "Play with 5 human players, and optionally, up to 1 additional computer player." ), Font::BIG );
563         if ( le.MousePressRight( button6Players.area() ) )
564             Dialog::Message( _( "6 Players" ), _( "Play with 6 human players." ), Font::BIG );
565         if ( le.MousePressRight( buttonCancel.area() ) )
566             Dialog::Message( _( "Cancel" ), _( "Cancel back to the main menu." ), Font::BIG );
567     }
568 
569     return 0;
570 }
571