Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/fheroes2/agg/agg_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ namespace
ICN::BUTTON_TOGGLE_ALL_ON_GOOD,
ICN::BUTTON_TOGGLE_ALL_OFF_GOOD,
ICN::BUTTON_TOGGLE_ALL_ON_EVIL,
ICN::BUTTON_TOGGLE_ALL_OFF_EVIL };
ICN::BUTTON_TOGGLE_ALL_OFF_EVIL,
ICN::ARMY_ESTIMATION_ICON };

bool isLanguageDependentIcnId( const int id )
{
Expand Down Expand Up @@ -1872,6 +1873,28 @@ namespace
( _icnVsSprite[id][1].height() - icon.height() ) / 2 + 1, icon.width(), icon.height() );
break;
}
case ICN::ARMY_ESTIMATION_ICON: {
_icnVsSprite[id].resize( 2 );

fheroes2::Sprite & canonicalBackground = _icnVsSprite[id][0];
canonicalBackground = fheroes2::AGG::GetICN( ICN::EMPTY_OPTION_ICON_BACKGROUND, 0 );

const fheroes2::Sprite & creature = fheroes2::AGG::GetICN( ICN::MONS32, 34 );
const int32_t iconBackgroundSize = canonicalBackground.width();
fheroes2::Blit( creature, 0, 0, canonicalBackground, ( iconBackgroundSize - creature.width() ) / 2, 8, creature.width(), creature.height() );

// We need to copy the image before drawing text on it.
fheroes2::Sprite & numericBackground = _icnVsSprite[id][1];
numericBackground = canonicalBackground;

const fheroes2::FontType font = fheroes2::FontType( fheroes2::FontSize::SMALL, fheroes2::FontColor::WHITE );
fheroes2::Text estimationMode( fheroes2::getSupportedText( gettext_noop( "army|Few" ), font ), font );
estimationMode.draw( ( iconBackgroundSize - estimationMode.width() ) / 2, iconBackgroundSize - 18, canonicalBackground );
estimationMode.set( "1-4", font );
estimationMode.draw( ( iconBackgroundSize - estimationMode.width() ) / 2, iconBackgroundSize - 18, numericBackground );

break;
}
default:
// You're calling this function for non-specified ICN id. Check your logic!
// Did you add a new image for one language without generating a default
Expand Down Expand Up @@ -4958,6 +4981,16 @@ namespace
}
break;
}
case ICN::EMPTY_OPTION_ICON_BACKGROUND: {
_icnVsSprite[id].resize( 1 );

fheroes2::Sprite & background = _icnVsSprite[id][0];
background.resize( 65, 65 );
fheroes2::Copy( fheroes2::AGG::GetICN( ICN::ESPANBKG, 0 ), 69, 47, background, 0, 0, 65, 65 );
background._disableTransformLayer();

break;
}
case ICN::GAME_OPTION_ICON: {
_icnVsSprite[id].resize( 2 );

Expand Down
2 changes: 2 additions & 0 deletions src/fheroes2/agg/icn.h
Original file line number Diff line number Diff line change
Expand Up @@ -1108,8 +1108,10 @@ namespace ICN
BUTTON_TOGGLE_ALL_ON_EVIL,
BUTTON_TOGGLE_ALL_OFF_EVIL,

EMPTY_OPTION_ICON_BACKGROUND,
GAME_OPTION_ICON,
RESOLUTION_ICON,
ARMY_ESTIMATION_ICON,

DIFFICULTY_ICON_EASY,
DIFFICULTY_ICON_NORMAL,
Expand Down
86 changes: 54 additions & 32 deletions src/fheroes2/army/army.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <numeric>
#include <set>
#include <sstream>
#include <unordered_map>
#include <utility>

#include "army_troop.h"
Expand Down Expand Up @@ -83,6 +84,12 @@ namespace
ARMY_LEGION = 1000
};

const std::unordered_map<ArmySize, std::string> troopSizeNumbers{
{ ArmySize::ARMY_FEW, "1-4" }, { ArmySize::ARMY_SEVERAL, "5-9" }, { ArmySize::ARMY_PACK, "10-19" },
{ ArmySize::ARMY_LOTS, "20-49" }, { ArmySize::ARMY_HORDE, "50-99" }, { ArmySize::ARMY_THRONG, "100-249" },
{ ArmySize::ARMY_SWARM, "250-499" }, { ArmySize::ARMY_ZOUNDS, "500-999" }, { ArmySize::ARMY_LEGION, "1000+" },
};

ArmySize getArmySize( const uint32_t count )
{
const ArmySize countAsEnum = static_cast<ArmySize>( count );
Expand Down Expand Up @@ -148,39 +155,48 @@ namespace
std::string Army::TroopSizeString( const Troop & troop )
{
std::string str;
const ArmySize armySize = getArmySize( troop.GetCount() );

switch ( getArmySize( troop.GetCount() ) ) {
case ArmySize::ARMY_FEW:
str = _( "A few\n%{monster}" );
break;
case ArmySize::ARMY_SEVERAL:
str = _( "Several\n%{monster}" );
break;
case ArmySize::ARMY_PACK:
str = _( "A pack of\n%{monster}" );
break;
case ArmySize::ARMY_LOTS:
str = _( "Lots of\n%{monster}" );
break;
case ArmySize::ARMY_HORDE:
str = _( "A horde of\n%{monster}" );
break;
case ArmySize::ARMY_THRONG:
str = _( "A throng of\n%{monster}" );
break;
case ArmySize::ARMY_SWARM:
str = _( "A swarm of\n%{monster}" );
break;
case ArmySize::ARMY_ZOUNDS:
str = _( "Zounds...\n%{monster}" );
break;
case ArmySize::ARMY_LEGION:
str = _( "A legion of\n%{monster}" );
break;
default:
// Are you passing the correct value?
assert( 0 );
break;
// Numeric estimates
if ( Settings::Get().isArmyEstimationViewNumeric() ) {
str = _( "%{monster}\n%{range}" );
StringReplace( str, "%{range}", troopSizeNumbers.at( armySize ) );
}
// Verbal estimates
else {
switch ( armySize ) {
case ArmySize::ARMY_FEW:
str = _( "A few\n%{monster}" );
break;
case ArmySize::ARMY_SEVERAL:
str = _( "Several\n%{monster}" );
break;
case ArmySize::ARMY_PACK:
str = _( "A pack of\n%{monster}" );
break;
case ArmySize::ARMY_LOTS:
str = _( "Lots of\n%{monster}" );
break;
case ArmySize::ARMY_HORDE:
str = _( "A horde of\n%{monster}" );
break;
case ArmySize::ARMY_THRONG:
str = _( "A throng of\n%{monster}" );
break;
case ArmySize::ARMY_SWARM:
str = _( "A swarm of\n%{monster}" );
break;
case ArmySize::ARMY_ZOUNDS:
str = _( "Zounds...\n%{monster}" );
break;
case ArmySize::ARMY_LEGION:
str = _( "A legion of\n%{monster}" );
break;
default:
// Are you passing the correct value?
assert( 0 );
break;
}
}

StringReplaceWithLowercase( str, "%{monster}", troop.GetMultiName() );
Expand All @@ -189,6 +205,12 @@ std::string Army::TroopSizeString( const Troop & troop )

std::string Army::SizeString( uint32_t size )
{
// Numeric estimates
if ( Settings::Get().isArmyEstimationViewNumeric() ) {
return troopSizeNumbers.at( getArmySize( size ) );
}

// Verbal estimates
switch ( getArmySize( size ) ) {
case ArmySize::ARMY_FEW:
return _( "army|Few" );
Expand Down
3 changes: 1 addition & 2 deletions src/fheroes2/dialog/dialog_graphics_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ namespace
{
const bool isSystemInfoDisplayed = Settings::Get().isSystemInfoEnabled();

fheroes2::Sprite image = fheroes2::Crop( fheroes2::AGG::GetICN( ICN::ESPANBKG, 0 ), 69, 47, 65, 65 );
image.setPosition( 0, 0 );
fheroes2::Sprite image = fheroes2::AGG::GetICN( ICN::EMPTY_OPTION_ICON_BACKGROUND, 0 );
fheroes2::Text info;
if ( isSystemInfoDisplayed ) {
info.set( _( "FPS" ), fheroes2::FontType( fheroes2::FontSize::NORMAL, fheroes2::FontColor::YELLOW ) );
Expand Down
79 changes: 50 additions & 29 deletions src/fheroes2/dialog/dialog_interface_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
#include "settings.h"
#include "translations.h"
#include "ui_button.h"
#include "ui_constants.h"
#include "ui_dialog.h"
#include "ui_option_item.h"
#include "ui_window.h"

namespace
{
Expand All @@ -47,17 +47,20 @@ namespace
InterfaceType,
InterfacePresence,
CursorType,
ArmyEstimationMode,
Exit
};

const fheroes2::Size offsetBetweenOptions{ 118, 110 };
const fheroes2::Point optionOffset{ 69, 47 };
const fheroes2::Size offsetBetweenOptions{ 92, 110 };
const fheroes2::Point optionOffset{ 20, 31 };
const int32_t optionWindowSize{ 65 };

const fheroes2::Rect interfaceTypeRoi{ optionOffset.x, optionOffset.y, optionWindowSize, optionWindowSize };
const fheroes2::Rect interfacePresenceRoi{ optionOffset.x + offsetBetweenOptions.width, optionOffset.y, optionWindowSize, optionWindowSize };
const fheroes2::Rect cursorTypeRoi{ optionOffset.x, optionOffset.y + offsetBetweenOptions.height, optionWindowSize, optionWindowSize };
const fheroes2::Rect scrollSpeedRoi{ optionOffset.x + offsetBetweenOptions.width, optionOffset.y + offsetBetweenOptions.height, optionWindowSize, optionWindowSize };
const fheroes2::Rect armyEstimationModeRoi{ optionOffset.x + offsetBetweenOptions.width * 2, optionOffset.y, optionWindowSize, optionWindowSize };
const fheroes2::Rect cursorTypeRoi{ optionOffset.x + 43, optionOffset.y + offsetBetweenOptions.height, optionWindowSize, optionWindowSize };
const fheroes2::Rect scrollSpeedRoi{ optionOffset.x + 43 + offsetBetweenOptions.width, optionOffset.y + offsetBetweenOptions.height, optionWindowSize,
optionWindowSize };

void drawInterfacePresence( const fheroes2::Rect & optionRoi )
{
Expand All @@ -76,48 +79,51 @@ namespace
value = _( "Show" );
}

fheroes2::drawOption( optionRoi, interfaceStateIcon, _( "Interface" ), std::move( value ), fheroes2::UiOptionTextWidth::TWO_ELEMENTS_ROW );
fheroes2::drawOption( optionRoi, interfaceStateIcon, _( "Interface" ), std::move( value ), fheroes2::UiOptionTextWidth::THREE_ELEMENTS_ROW );
}

SelectedWindow showConfigurationWindow( bool & saveConfiguration )
void drawArmyNumberEstimationOption( const fheroes2::Rect & optionRoi )
{
fheroes2::Display & display = fheroes2::Display::instance();
const bool isArmyEstimationNumeric = Settings ::Get().isArmyEstimationViewNumeric();

Settings & conf = Settings::Get();
const bool isEvilInterface = conf.isEvilInterfaceEnabled();
const fheroes2::Sprite & dialog = fheroes2::AGG::GetICN( ( isEvilInterface ? ICN::ESPANBKG_EVIL : ICN::ESPANBKG ), 0 );
const fheroes2::Sprite & dialogShadow = fheroes2::AGG::GetICN( ( isEvilInterface ? ICN::CSPANBKE : ICN::CSPANBKG ), 1 );
fheroes2::drawOption( optionRoi, fheroes2::AGG::GetICN( ICN::ARMY_ESTIMATION_ICON, isArmyEstimationNumeric ? 1 : 0 ), _( "Army Estimation" ),
isArmyEstimationNumeric ? _( "Numeric" ) : _( "Canonical" ), fheroes2::UiOptionTextWidth::THREE_ELEMENTS_ROW );
}

const fheroes2::Point dialogOffset( ( display.width() - dialog.width() ) / 2, ( display.height() - dialog.height() ) / 2 );
const fheroes2::Point shadowOffset( dialogOffset.x - fheroes2::borderWidthPx, dialogOffset.y );
SelectedWindow showConfigurationWindow( bool & saveConfiguration )
{
fheroes2::Display & display = fheroes2::Display::instance();

const fheroes2::ImageRestorer restorer( display, shadowOffset.x, shadowOffset.y, dialog.width() + fheroes2::borderWidthPx,
dialog.height() + fheroes2::borderWidthPx );
const fheroes2::Rect windowRoi{ dialogOffset.x, dialogOffset.y, dialog.width(), dialog.height() };
fheroes2::StandardWindow background( 289, 272, true, display );

fheroes2::Blit( dialogShadow, display, windowRoi.x - fheroes2::borderWidthPx, windowRoi.y + fheroes2::borderWidthPx );
fheroes2::Blit( dialog, display, windowRoi.x, windowRoi.y );
const fheroes2::Rect windowRoi = background.activeArea();

fheroes2::ImageRestorer emptyDialogRestorer( display, windowRoi.x, windowRoi.y, windowRoi.width, windowRoi.height );

const fheroes2::Rect windowInterfaceTypeRoi( interfaceTypeRoi + windowRoi.getPosition() );
const fheroes2::Rect windowInterfacePresenceRoi( interfacePresenceRoi + windowRoi.getPosition() );
const fheroes2::Rect windowCursorTypeRoi( cursorTypeRoi + windowRoi.getPosition() );
const fheroes2::Rect windowScrollSpeedRoi( scrollSpeedRoi + windowRoi.getPosition() );
const fheroes2::Rect windowArmyEstimationModeRoi( armyEstimationModeRoi + windowRoi.getPosition() );

const auto drawOptions = [&conf, &windowInterfaceTypeRoi, &windowInterfacePresenceRoi, &windowCursorTypeRoi, &windowScrollSpeedRoi]() {
drawInterfaceType( windowInterfaceTypeRoi, conf.getInterfaceType() );
drawInterfacePresence( windowInterfacePresenceRoi );
drawCursorType( windowCursorTypeRoi, conf.isMonochromeCursorEnabled() );
drawScrollSpeed( windowScrollSpeedRoi, conf.ScrollSpeed() );
};
Settings & conf = Settings::Get();

const auto drawOptions
= [&conf, &windowInterfaceTypeRoi, &windowInterfacePresenceRoi, &windowCursorTypeRoi, &windowScrollSpeedRoi, &windowArmyEstimationModeRoi]() {
drawInterfaceType( windowInterfaceTypeRoi, conf.getInterfaceType() );
drawInterfacePresence( windowInterfacePresenceRoi );
drawCursorType( windowCursorTypeRoi, conf.isMonochromeCursorEnabled() );
drawScrollSpeed( windowScrollSpeedRoi, conf.ScrollSpeed() );
drawArmyNumberEstimationOption( windowArmyEstimationModeRoi );
};

drawOptions();

const fheroes2::Point buttonOffset( 112 + windowRoi.x, 252 + windowRoi.y );
fheroes2::Button buttonOk( buttonOffset.x, buttonOffset.y, isEvilInterface ? ICN::BUTTON_SMALL_OKAY_EVIL : ICN::BUTTON_SMALL_OKAY_GOOD, 0, 1 );
const bool isEvilInterface = conf.isEvilInterfaceEnabled();

buttonOk.draw();
fheroes2::Button buttonOk;
const int buttonOkIcnId = isEvilInterface ? ICN::BUTTON_SMALL_OKAY_EVIL : ICN::BUTTON_SMALL_OKAY_GOOD;
background.renderButton( buttonOk, buttonOkIcnId, 0, 1, { 0, 5 }, fheroes2::StandardWindow::Padding::BOTTOM_CENTER );

const auto refreshWindow = [&drawOptions, &emptyDialogRestorer, &buttonOk, &display]() {
emptyDialogRestorer.restore();
Expand Down Expand Up @@ -146,6 +152,9 @@ namespace
if ( le.MouseClickLeft( windowCursorTypeRoi ) ) {
return SelectedWindow::CursorType;
}
if ( le.MouseClickLeft( windowArmyEstimationModeRoi ) ) {
return SelectedWindow::ArmyEstimationMode;
}

if ( le.MouseClickLeft( windowScrollSpeedRoi ) ) {
saveConfiguration = true;
Expand Down Expand Up @@ -178,9 +187,15 @@ namespace
else if ( le.isMouseRightButtonPressedInArea( windowCursorTypeRoi ) ) {
fheroes2::showStandardTextMessage( _( "Mouse Cursor" ), _( "Toggle colored cursor on or off. This is only an aesthetic choice." ), 0 );
}
if ( le.isMouseRightButtonPressedInArea( windowScrollSpeedRoi ) ) {
else if ( le.isMouseRightButtonPressedInArea( windowScrollSpeedRoi ) ) {
fheroes2::showStandardTextMessage( _( "Scroll Speed" ), _( "Sets the speed at which you scroll the window." ), 0 );
}
else if ( le.isMouseRightButtonPressedInArea( windowArmyEstimationModeRoi ) ) {
fheroes2::showStandardTextMessage(
_( "Army Estimation" ),
_( "Toggle how army sizes are displayed when right-clicking armies on the adventure map. \n\nCanonical: Army sizes are shown as descriptive text (e.g. \"Few\").\n\nNumeric: Army sizes are shown as numeric ranges (e.g. \"1-4\")." ),
0 );
}
else if ( le.isMouseRightButtonPressedInArea( buttonOk.area() ) ) {
fheroes2::showStandardTextMessage( _( "Okay" ), _( "Exit this menu." ), 0 );
}
Expand Down Expand Up @@ -242,6 +257,12 @@ namespace fheroes2
conf.setMonochromeCursor( !conf.isMonochromeCursorEnabled() );
saveConfiguration = true;

windowType = SelectedWindow::Configuration;
break;
case SelectedWindow::ArmyEstimationMode:
conf.setNumericArmyEstimationView( !conf.isArmyEstimationViewNumeric() );
saveConfiguration = true;

windowType = SelectedWindow::Configuration;
break;
default:
Expand Down
Loading
Loading