From 206d679878377f67a26c30a390de36f0f64916ea Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 1 Oct 2023 20:32:19 +0800 Subject: [PATCH 1/7] Add functionality to place monsters in the Editor relates to #6845 --- src/fheroes2/editor/editor_interface.cpp | 23 +++++++++++++-- src/fheroes2/editor/editor_interface.h | 8 +++++ .../editor/editor_interface_panel.cpp | 29 ++++++++++++++++++- src/fheroes2/editor/editor_interface_panel.h | 15 +++++++++- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/fheroes2/editor/editor_interface.cpp b/src/fheroes2/editor/editor_interface.cpp index 9c8147480f3..124fabef9a8 100644 --- a/src/fheroes2/editor/editor_interface.cpp +++ b/src/fheroes2/editor/editor_interface.cpp @@ -586,6 +586,20 @@ namespace Interface } } } + else if ( _editorPanel.isMonsterSettingMode() ) { + if ( tile.isWater() ) { + fheroes2::showStandardTextMessage( _( "Monster" ), _( "Monsters cannot be set on water." ), Dialog::OK ); + } + else if ( !Maps::isClearGround( tile ) ) { + fheroes2::showStandardTextMessage( _( "Monster" ), _( "Choose a tile which does not contain any objects." ), Dialog::OK ); + } + else { + const fheroes2::ActionCreator action( _historyManager ); + + Maps::setMonsterOnTile( tile, _editorPanel.getMonsterId(), 0 ); + _redraw |= mapUpdateFlags; + } + } } void EditorInterface::mouseCursorAreaPressRight( const int32_t tileIndex ) const @@ -623,8 +637,13 @@ namespace Interface } } - void EditorInterface::updateCursor( const int32_t /*tileIndex*/ ) + void EditorInterface::updateCursor( const int32_t tileIndex ) { - Cursor::Get().SetThemes( Cursor::POINTER ); + if ( _cursorUpdater ) { + _cursorUpdater( tileIndex ); + } + else { + Cursor::Get().SetThemes( Cursor::POINTER ); + } } } diff --git a/src/fheroes2/editor/editor_interface.h b/src/fheroes2/editor/editor_interface.h index 8a904dfb5d2..e7c17821a2a 100644 --- a/src/fheroes2/editor/editor_interface.h +++ b/src/fheroes2/editor/editor_interface.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include "editor_interface_panel.h" #include "game_mode.h" @@ -71,6 +72,11 @@ namespace Interface void updateCursor( const int32_t tileIndex ) override; + void setCursorUpdater( std::function cursorUpdater ) + { + _cursorUpdater = cursorUpdater; + } + private: EditorInterface() : _editorPanel( *this ) @@ -83,6 +89,8 @@ namespace Interface int32_t _selectedTile{ -1 }; int32_t _tileUnderCursor{ -1 }; + std::function _cursorUpdater; + fheroes2::HistoryManager _historyManager; }; } diff --git a/src/fheroes2/editor/editor_interface_panel.cpp b/src/fheroes2/editor/editor_interface_panel.cpp index 288afa4881e..066a54fc8f6 100644 --- a/src/fheroes2/editor/editor_interface_panel.cpp +++ b/src/fheroes2/editor/editor_interface_panel.cpp @@ -25,7 +25,9 @@ #include #include "agg_image.h" +#include "cursor.h" #include "dialog.h" +#include "dialog_selectitems.h" #include "dialog_system_options.h" #include "editor_interface.h" #include "ground.h" @@ -74,7 +76,7 @@ namespace Interface int32_t EditorPanel::getBrushSize() const { // Roads and streams are placed using only 1x1 brush. - if ( _selectedInstrument == Instrument::STREAM || _selectedInstrument == Instrument::ROAD ) { + if ( _selectedInstrument == Instrument::STREAM || _selectedInstrument == Instrument::ROAD || isMonsterSettingMode() ) { return 1; } @@ -301,6 +303,10 @@ namespace Interface if ( le.MousePressLeft( _instrumentButtonsRect[i] ) ) { if ( _instrumentButtons[i].drawOnPress() ) { _selectedInstrument = static_cast( i ); + + // Reset cursor updater since this UI element was clicked. + _interface.setCursorUpdater( {} ); + setRedraw(); } } @@ -399,6 +405,10 @@ namespace Interface for ( size_t i = 0; i < _objectButtonsRect.size(); ++i ) { if ( ( _selectedObject != i ) && le.MousePressLeft( _objectButtonsRect[i] ) ) { _selectedObject = static_cast( i ); + + // Reset cursor updater since this UI element was clicked. + _interface.setCursorUpdater( {} ); + setRedraw(); // There is no need to continue the loop as only one button can be pressed at one moment. @@ -432,6 +442,23 @@ namespace Interface else if ( le.MousePressRight( _objectButtonsRect[Brush::TREASURES] ) ) { fheroes2::showStandardTextMessage( _getObjectTypeName( Brush::TREASURES ), _( "Used to place\na resource or treasure." ), Dialog::ZERO ); } + else if ( le.MouseClickLeft( _objectButtonsRect[Brush::MONSTERS] ) ) { + _monsterId = Monster::UNKNOWN; + + const Monster monster = Dialog::selectMonster(); + if ( monster.GetID() != Monster::UNKNOWN ) { + _monsterId = monster.GetID(); + + _interface.setCursorUpdater( [monster = monster](const int32_t /*tileIndex*/ ) { + const fheroes2::Sprite & image = fheroes2::AGG::GetICN( ICN::MONS32, monster.GetSpriteIndex() ); + + Cursor::Get().setCustomImage( image, { -image.width() / 2, -image.height() / 2 } ); + } ); + + _interface.updateCursor( 0 ); + return res; + } + } } le.MousePressLeft( _rectMagnify ) ? _buttonMagnify.drawOnPress() : _buttonMagnify.drawOnRelease(); diff --git a/src/fheroes2/editor/editor_interface_panel.h b/src/fheroes2/editor/editor_interface_panel.h index 7150f43cc48..56527ecbdf8 100644 --- a/src/fheroes2/editor/editor_interface_panel.h +++ b/src/fheroes2/editor/editor_interface_panel.h @@ -26,6 +26,7 @@ #include "game_mode.h" #include "ground.h" #include "math_base.h" +#include "monster.h" #include "ui_button.h" namespace Interface @@ -66,10 +67,20 @@ namespace Interface return _selectedInstrument == Instrument::ERASE; } + bool isMonsterSettingMode() const + { + return ( _selectedInstrument == OBJECT ) && ( _selectedObject == MONSTERS ); + } + + int32_t getMonsterId() const + { + return _monsterId; + } + bool showAreaSelectRect() const { return _selectedInstrument == Instrument::TERRAIN || _selectedInstrument == Instrument::STREAM || _selectedInstrument == Instrument::ROAD - || _selectedInstrument == Instrument::ERASE; + || _selectedInstrument == Instrument::ERASE || isMonsterSettingMode(); } bool useMouseDragMovement() const @@ -184,5 +195,7 @@ namespace Interface uint8_t _selectedTerrain{ Brush::WATER }; uint8_t _selectedObject{ Brush::WATER }; uint8_t _selectedBrushSize{ BrushSize::MEDIUM }; + + int32_t _monsterId{ Monster::UNKNOWN }; }; } From bbc6baeb339d047f5d34b90ae32268fce704c326 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 1 Oct 2023 20:36:53 +0800 Subject: [PATCH 2/7] Address code style and clang-tidy issues --- src/fheroes2/editor/editor_interface.h | 2 +- src/fheroes2/editor/editor_interface_panel.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fheroes2/editor/editor_interface.h b/src/fheroes2/editor/editor_interface.h index e7c17821a2a..669058513b0 100644 --- a/src/fheroes2/editor/editor_interface.h +++ b/src/fheroes2/editor/editor_interface.h @@ -72,7 +72,7 @@ namespace Interface void updateCursor( const int32_t tileIndex ) override; - void setCursorUpdater( std::function cursorUpdater ) + void setCursorUpdater( const std::function & cursorUpdater ) { _cursorUpdater = cursorUpdater; } diff --git a/src/fheroes2/editor/editor_interface_panel.cpp b/src/fheroes2/editor/editor_interface_panel.cpp index 066a54fc8f6..6c96debadcb 100644 --- a/src/fheroes2/editor/editor_interface_panel.cpp +++ b/src/fheroes2/editor/editor_interface_panel.cpp @@ -449,11 +449,11 @@ namespace Interface if ( monster.GetID() != Monster::UNKNOWN ) { _monsterId = monster.GetID(); - _interface.setCursorUpdater( [monster = monster](const int32_t /*tileIndex*/ ) { + _interface.setCursorUpdater( [monster = monster]( const int32_t /*tileIndex*/ ) { const fheroes2::Sprite & image = fheroes2::AGG::GetICN( ICN::MONS32, monster.GetSpriteIndex() ); - Cursor::Get().setCustomImage( image, { -image.width() / 2, -image.height() / 2 } ); - } ); + Cursor::Get().setCustomImage( image, { -image.width() / 2, -image.height() / 2 } ); + } ); _interface.updateCursor( 0 ); return res; From cae543a010e53de0a0d073074f7fb743ec6b9ea6 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 1 Oct 2023 22:26:22 +0800 Subject: [PATCH 3/7] Address comments --- src/fheroes2/editor/editor_interface.cpp | 2 +- src/fheroes2/maps/maps_tiles_helper.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/fheroes2/editor/editor_interface.cpp b/src/fheroes2/editor/editor_interface.cpp index 124fabef9a8..7d022dfa3e8 100644 --- a/src/fheroes2/editor/editor_interface.cpp +++ b/src/fheroes2/editor/editor_interface.cpp @@ -593,7 +593,7 @@ namespace Interface else if ( !Maps::isClearGround( tile ) ) { fheroes2::showStandardTextMessage( _( "Monster" ), _( "Choose a tile which does not contain any objects." ), Dialog::OK ); } - else { + else if ( Monster{ _editorPanel.getMonsterId() }.isValid() ) { const fheroes2::ActionCreator action( _historyManager ); Maps::setMonsterOnTile( tile, _editorPanel.getMonsterId(), 0 ); diff --git a/src/fheroes2/maps/maps_tiles_helper.cpp b/src/fheroes2/maps/maps_tiles_helper.cpp index ab72ca9f28a..8e320ed40ce 100644 --- a/src/fheroes2/maps/maps_tiles_helper.cpp +++ b/src/fheroes2/maps/maps_tiles_helper.cpp @@ -2423,10 +2423,13 @@ namespace Maps { tile.SetObject( MP2::OBJ_MONSTER ); - // If there was another object sprite here (shadow for example) push it down to Addons, - // except when there is already MONS32.ICN here. - if ( tile.getObjectIcnType() != MP2::OBJ_ICN_TYPE_UNKNOWN && tile.getObjectIcnType() != MP2::OBJ_ICN_TYPE_MONS32 && tile.GetObjectSpriteIndex() != 255 ) { - // Push object sprite to Level 1 Addons preserving the Layer Type. + if ( tile.getObjectIcnType() == MP2::OBJ_ICN_TYPE_UNKNOWN ) { + // No object exists on this tile. Add one. + tile.setObjectUID( getNewObjectUID() ); + tile.setObjectIcnType( MP2::OBJ_ICN_TYPE_MONS32 ); + } + else if ( tile.getObjectIcnType() != MP2::OBJ_ICN_TYPE_MONS32 ) { + // If there is another object sprite here (shadow for example) push it down to add-ons. tile.pushBottomLayerAddon( TilesAddon( tile.getLayerType(), tile.GetObjectUID(), tile.getObjectIcnType(), tile.GetObjectSpriteIndex() ) ); // Set unique UID for placed monster. From bab9887ac6416e0e59751d95437bb8c216ebfebd Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 1 Oct 2023 22:36:37 +0800 Subject: [PATCH 4/7] Make IWYU happy --- src/fheroes2/editor/editor_interface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fheroes2/editor/editor_interface.cpp b/src/fheroes2/editor/editor_interface.cpp index 7d022dfa3e8..b343ee80337 100644 --- a/src/fheroes2/editor/editor_interface.cpp +++ b/src/fheroes2/editor/editor_interface.cpp @@ -48,6 +48,7 @@ #include "maps_tiles.h" #include "maps_tiles_helper.h" #include "math_base.h" +#include "monster.h" #include "mp2.h" #include "screen.h" #include "settings.h" From 3d8f59e984a9ddf6db52c3e53313334eb45a54a2 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Mon, 2 Oct 2023 07:55:37 +0800 Subject: [PATCH 5/7] Update src/fheroes2/editor/editor_interface.cpp Co-authored-by: Zenseii --- src/fheroes2/editor/editor_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fheroes2/editor/editor_interface.cpp b/src/fheroes2/editor/editor_interface.cpp index b343ee80337..d5e875fb6d3 100644 --- a/src/fheroes2/editor/editor_interface.cpp +++ b/src/fheroes2/editor/editor_interface.cpp @@ -589,7 +589,7 @@ namespace Interface } else if ( _editorPanel.isMonsterSettingMode() ) { if ( tile.isWater() ) { - fheroes2::showStandardTextMessage( _( "Monster" ), _( "Monsters cannot be set on water." ), Dialog::OK ); + fheroes2::showStandardTextMessage( _( "Monster" ), _( "Monsters cannot be placed on water." ), Dialog::OK ); } else if ( !Maps::isClearGround( tile ) ) { fheroes2::showStandardTextMessage( _( "Monster" ), _( "Choose a tile which does not contain any objects." ), Dialog::OK ); From 1d8af31b14bfa83a2605be8022361e034ec637cd Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Wed, 4 Oct 2023 21:40:19 +0800 Subject: [PATCH 6/7] Fix out of map cursor --- src/fheroes2/editor/editor_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fheroes2/editor/editor_interface.cpp b/src/fheroes2/editor/editor_interface.cpp index d5e875fb6d3..7820c54a67f 100644 --- a/src/fheroes2/editor/editor_interface.cpp +++ b/src/fheroes2/editor/editor_interface.cpp @@ -640,7 +640,7 @@ namespace Interface void EditorInterface::updateCursor( const int32_t tileIndex ) { - if ( _cursorUpdater ) { + if ( _cursorUpdater && tileIndex >= 0 ) { _cursorUpdater( tileIndex ); } else { From cce3452b9f91a0b7f22b17971de05fb3ec329aea Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Thu, 5 Oct 2023 20:33:42 +0800 Subject: [PATCH 7/7] Fix cursor --- src/fheroes2/gui/cursor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fheroes2/gui/cursor.cpp b/src/fheroes2/gui/cursor.cpp index c7a5b9e6ab2..b911ec4eb37 100644 --- a/src/fheroes2/gui/cursor.cpp +++ b/src/fheroes2/gui/cursor.cpp @@ -87,7 +87,7 @@ void Cursor::setCustomImage( const fheroes2::Image & image, const fheroes2::Poin { theme = NONE; - fheroes2::cursor().update( image, 0, 0 ); + fheroes2::cursor().update( image, -offset.x, -offset.y ); // Immediately apply new mouse offset. const fheroes2::Point & currentPos = LocalEvent::Get().GetMouseCursor();