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_image.h"
24 #include "cursor.h"
25 #include "dialog.h"
26 #include "game.h"
27 #include "game_delays.h"
28 #include "game_interface.h"
29 #include "icn.h"
30 #include "maps.h"
31 #include "settings.h"
32 #include "ui_tool.h"
33 #include "world.h"
34 
Basic()35 Interface::Basic::Basic()
36     : gameArea( *this )
37     , radar( *this )
38     , iconsPanel( *this )
39     , buttonsArea( *this )
40     , statusWindow( *this )
41     , controlPanel( *this )
42     , redraw( 0 )
43 {
44     Reset();
45 }
46 
Reset()47 void Interface::Basic::Reset()
48 {
49     const fheroes2::Display & display = fheroes2::Display::instance();
50     const Settings & conf = Settings::Get();
51 
52     SetHideInterface( conf.ExtGameHideInterface() );
53 
54     scrollLeft = fheroes2::Rect( 0, 0, BORDERWIDTH, display.height() );
55     scrollRight = fheroes2::Rect( display.width() - BORDERWIDTH, 0, BORDERWIDTH, display.height() );
56     scrollTop = fheroes2::Rect( 0, 0, display.width(), BORDERWIDTH );
57     scrollBottom = fheroes2::Rect( 0, display.height() - BORDERWIDTH, display.width(), BORDERWIDTH );
58 }
59 
GetGameArea(void)60 Interface::GameArea & Interface::Basic::GetGameArea( void )
61 {
62     return gameArea;
63 }
64 
GetRadar(void)65 Interface::Radar & Interface::Basic::GetRadar( void )
66 {
67     return radar;
68 }
69 
GetIconsPanel(void)70 Interface::IconsPanel & Interface::Basic::GetIconsPanel( void )
71 {
72     return iconsPanel;
73 }
74 
GetButtonsArea(void)75 Interface::ButtonsArea & Interface::Basic::GetButtonsArea( void )
76 {
77     return buttonsArea;
78 }
79 
GetStatusWindow(void)80 Interface::StatusWindow & Interface::Basic::GetStatusWindow( void )
81 {
82     return statusWindow;
83 }
84 
GetControlPanel(void)85 Interface::ControlPanel & Interface::Basic::GetControlPanel( void )
86 {
87     return controlPanel;
88 }
89 
SetHideInterface(bool f)90 void Interface::Basic::SetHideInterface( bool f )
91 {
92     const fheroes2::Display & display = fheroes2::Display::instance();
93     Settings & conf = Settings::Get();
94     const u32 px = display.width() - BORDERWIDTH - RADARWIDTH;
95 
96     conf.SetHideInterface( f );
97 
98     if ( f ) {
99         conf.SetShowPanel( true );
100 
101         fheroes2::Point pos_radr = conf.PosRadar();
102         fheroes2::Point pos_bttn = conf.PosButtons();
103         fheroes2::Point pos_icon = conf.PosIcons();
104         fheroes2::Point pos_stat = conf.PosStatus();
105 
106         if ( 0 == pos_radr.x && 0 == pos_radr.y )
107             pos_radr = fheroes2::Point( BORDERWIDTH, BORDERWIDTH );
108         if ( 0 == pos_icon.x && 0 == pos_icon.y )
109             pos_icon = fheroes2::Point( px - BORDERWIDTH, radar.GetArea().y + radar.GetArea().height );
110         if ( 0 == pos_bttn.x && 0 == pos_bttn.y )
111             pos_bttn = fheroes2::Point( px - BORDERWIDTH, iconsPanel.GetArea().y + iconsPanel.GetArea().height );
112         if ( 0 == pos_stat.x && 0 == pos_stat.y )
113             pos_stat = fheroes2::Point( px - BORDERWIDTH, buttonsArea.GetArea().y + buttonsArea.GetArea().height );
114 
115         controlPanel.SetPos( display.width() - controlPanel.GetArea().width - BORDERWIDTH, 0 );
116         radar.SetPos( pos_radr.x, pos_radr.y );
117         iconsPanel.SetPos( pos_icon.x, pos_icon.y );
118         buttonsArea.SetPos( pos_bttn.x, pos_bttn.y );
119         statusWindow.SetPos( pos_stat.x, pos_stat.y );
120     }
121     else {
122         radar.SetPos( px, BORDERWIDTH );
123         iconsPanel.SetPos( px, radar.GetArea().y + radar.GetArea().height + BORDERWIDTH );
124 
125         buttonsArea.SetPos( px, iconsPanel.GetArea().y + iconsPanel.GetArea().height + BORDERWIDTH );
126         statusWindow.SetPos( px, buttonsArea.GetArea().y + buttonsArea.GetArea().height );
127     }
128 
129     gameArea.generate( { display.width(), display.height() }, conf.ExtGameHideInterface() );
130 }
131 
Get(void)132 Interface::Basic & Interface::Basic::Get( void )
133 {
134     static Basic basic;
135     return basic;
136 }
137 
GetScrollLeft(void) const138 const fheroes2::Rect & Interface::Basic::GetScrollLeft( void ) const
139 {
140     return scrollLeft;
141 }
142 
GetScrollRight(void) const143 const fheroes2::Rect & Interface::Basic::GetScrollRight( void ) const
144 {
145     return scrollRight;
146 }
147 
GetScrollTop(void) const148 const fheroes2::Rect & Interface::Basic::GetScrollTop( void ) const
149 {
150     return scrollTop;
151 }
152 
GetScrollBottom(void) const153 const fheroes2::Rect & Interface::Basic::GetScrollBottom( void ) const
154 {
155     return scrollBottom;
156 }
157 
NeedRedraw(void) const158 bool Interface::Basic::NeedRedraw( void ) const
159 {
160     return redraw != 0;
161 }
162 
SetRedraw(int f)163 void Interface::Basic::SetRedraw( int f )
164 {
165     redraw |= f;
166 }
167 
GetRedrawMask() const168 int Interface::Basic::GetRedrawMask() const
169 {
170     return redraw;
171 }
172 
Redraw(int force)173 void Interface::Basic::Redraw( int force )
174 {
175     const Settings & conf = Settings::Get();
176 
177     const int combinedRedraw = redraw | force;
178     const bool hideInterface = conf.ExtGameHideInterface();
179 
180     if ( combinedRedraw & REDRAW_GAMEAREA )
181         gameArea.Redraw( fheroes2::Display::instance(), LEVEL_ALL );
182 
183     if ( ( hideInterface && conf.ShowRadar() ) || ( combinedRedraw & REDRAW_RADAR ) )
184         radar.Redraw();
185 
186     if ( ( hideInterface && conf.ShowIcons() ) || ( combinedRedraw & REDRAW_ICONS ) )
187         iconsPanel.Redraw();
188     else if ( combinedRedraw & REDRAW_HEROES )
189         iconsPanel.RedrawIcons( ICON_HEROES );
190     else if ( combinedRedraw & REDRAW_CASTLES )
191         iconsPanel.RedrawIcons( ICON_CASTLES );
192 
193     if ( ( hideInterface && conf.ShowButtons() ) || ( combinedRedraw & REDRAW_BUTTONS ) )
194         buttonsArea.Redraw();
195 
196     if ( ( hideInterface && conf.ShowStatus() ) || ( combinedRedraw & REDRAW_STATUS ) )
197         statusWindow.Redraw();
198 
199     if ( hideInterface && conf.ShowControlPanel() && ( redraw & REDRAW_GAMEAREA ) )
200         controlPanel.Redraw();
201 
202     if ( combinedRedraw & REDRAW_BORDER )
203         GameBorderRedraw( false );
204 
205     redraw = 0;
206 }
207 
GetDimensionDoorDestination(const int32_t from,const int32_t distance,const bool water)208 int32_t Interface::Basic::GetDimensionDoorDestination( const int32_t from, const int32_t distance, const bool water )
209 {
210     fheroes2::Display & display = fheroes2::Display::instance();
211 
212     const fheroes2::Rect & radarArea = Interface::Basic::Get().GetRadar().GetArea();
213     const Settings & conf = Settings::Get();
214     const bool isEvilInterface = conf.ExtGameEvilInterface();
215     const bool isNoInterface = conf.ExtGameHideInterface();
216 
217     fheroes2::ImageRestorer back( display, radarArea.x, radarArea.y, radarArea.width, radarArea.height );
218 
219     const fheroes2::Sprite & viewDoor = fheroes2::AGG::GetICN( ( isEvilInterface ? ICN::EVIWDDOR : ICN::VIEWDDOR ), 0 );
220     fheroes2::Blit( viewDoor, 0, 0, display, radarArea.x, radarArea.y, radarArea.width, radarArea.height );
221 
222     const fheroes2::Rect & visibleArea = gameArea.GetROI();
223     const bool isFadingEnabled = ( gameArea.GetROI().width > TILEWIDTH * distance ) || ( gameArea.GetROI().height > TILEWIDTH * distance );
224 
225     // We need to add an extra one cell as a hero stands exactly in the middle of a cell
226     const fheroes2::Point heroPos( gameArea.GetRelativeTilePosition( Maps::GetPoint( from ) ) );
227     const fheroes2::Point heroPosOffset( heroPos.x - TILEWIDTH * ( distance / 2 ), heroPos.y - TILEWIDTH * ( distance / 2 ) );
228     const fheroes2::Rect spellROI( heroPosOffset.x, heroPosOffset.y, TILEWIDTH * ( distance + 1 ), TILEWIDTH * ( distance + 1 ) );
229 
230     if ( isFadingEnabled ) {
231         fheroes2::InvertedFadeWithPalette( display, visibleArea, spellROI, 5, 300, 9 );
232     }
233 
234     // setup cursor
235     const CursorRestorer cursorRestorer( true, Cursor::POINTER );
236     Cursor & cursor = Cursor::Get();
237 
238     LocalEvent & le = LocalEvent::Get();
239     int32_t returnValue = -1;
240 
241     const fheroes2::Point exitButtonPos( radarArea.x + 32, radarArea.y + radarArea.height - 37 );
242     fheroes2::Button buttonExit( exitButtonPos.x, exitButtonPos.y, ( isEvilInterface ? ICN::LGNDXTRE : ICN::LGNDXTRA ), 4, 5 );
243     buttonExit.draw();
244 
245     while ( le.HandleEvents() ) {
246         const fheroes2::Point & mp = le.GetMouseCursor();
247 
248         if ( radarArea & mp ) {
249             cursor.SetThemes( Cursor::POINTER );
250 
251             le.MousePressLeft( buttonExit.area() ) ? buttonExit.drawOnPress() : buttonExit.drawOnRelease();
252             if ( le.MouseClickLeft( buttonExit.area() ) || HotKeyCloseWindow )
253                 break;
254         }
255         else if ( visibleArea & mp ) {
256             const int32_t dst = gameArea.GetValidTileIdFromPoint( mp );
257 
258             bool valid = ( dst >= 0 );
259 
260             if ( valid ) {
261                 const Maps::Tiles & tile = world.GetTiles( dst );
262 
263                 const MP2::MapObjectType objectType = tile.GetObject( true );
264                 const bool isActionObject = MP2::isActionObject( objectType );
265 
266                 valid = ( ( spellROI & mp ) && !isActionObject && ( tile.GetPassable() & Direction::CENTER ) != 0 && water == tile.isWater() );
267             }
268 
269             cursor.SetThemes( valid ? ( water ? static_cast<int>( Cursor::CURSOR_HERO_BOAT ) : static_cast<int>( Cursor::CURSOR_HERO_MOVE ) )
270                                     : static_cast<int>( Cursor::WAR_NONE ) );
271 
272             if ( dst >= 0 && le.MousePressRight() ) {
273                 const Maps::Tiles & tile = world.GetTiles( dst );
274                 Dialog::QuickInfo( tile );
275             }
276             else if ( le.MouseClickLeft() && valid ) {
277                 returnValue = dst;
278                 break;
279             }
280         }
281         else {
282             cursor.SetThemes( Cursor::POINTER );
283         }
284 
285         if ( Game::validateAnimationDelay( Game::MAPS_DELAY ) ) {
286             uint32_t & frame = Game::MapsAnimationFrame();
287             ++frame;
288             gameArea.SetRedraw();
289             Redraw();
290 
291             if ( isFadingEnabled ) {
292                 InvertedShadow( display, visibleArea, spellROI, 5, 9 );
293 
294                 if ( isNoInterface ) {
295                     fheroes2::Blit( viewDoor, 0, 0, display, radarArea.x, radarArea.y, radarArea.width, radarArea.height );
296                     buttonExit.draw();
297                 }
298             }
299 
300             display.render();
301         }
302     }
303 
304     if ( isFadingEnabled ) {
305         gameArea.SetRedraw();
306         Redraw();
307         display.render();
308     }
309 
310     back.restore();
311     display.render();
312 
313     return returnValue;
314 }
315