2023-11-05 00:53:37 +02:00
/*
2023-12-04 23:21:49 +02:00
* TradePanels . cpp , part of VCMI engine
2023-11-05 00:53:37 +02:00
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# include "StdInc.h"
2023-12-04 23:21:49 +02:00
# include "TradePanels.h"
2023-11-05 00:53:37 +02:00
2023-12-04 23:21:49 +02:00
# include "../../gui/CGuiHandler.h"
# include "../../render/Canvas.h"
# include "../../widgets/TextControls.h"
# include "../../windows/InfoWindows.h"
2023-11-28 17:01:53 +02:00
2023-12-04 23:21:49 +02:00
# include "../../CGameInfo.h"
# include "../../CPlayerInterface.h"
2023-11-05 00:53:37 +02:00
2023-12-04 23:21:49 +02:00
# include "../../../CCallback.h"
2024-07-20 14:55:17 +02:00
# include "../../../lib/texts/CGeneralTextHandler.h"
2023-12-04 23:21:49 +02:00
# include "../../../lib/mapObjects/CGHeroInstance.h"
2023-11-05 00:53:37 +02:00
2024-02-27 13:39:50 +02:00
CTradeableItem : : CTradeableItem ( const Rect & area , EType Type , int ID , int Serial )
2024-02-29 22:33:12 +02:00
: SelectableSlot ( area , Point ( 1 , 1 ) )
2023-11-05 00:53:37 +02:00
, type ( EType ( - 1 ) ) // set to invalid, will be corrected in setType
, id ( ID )
, serial ( Serial )
{
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2024-01-10 18:01:34 +02:00
addUsedEvents ( LCLICK ) ;
addUsedEvents ( HOVER ) ;
addUsedEvents ( SHOW_POPUP ) ;
2023-12-04 23:21:49 +02:00
2024-02-27 13:39:50 +02:00
subtitle = std : : make_shared < CLabel > ( 0 , 0 , FONT_SMALL , ETextAlignment : : CENTER , Colors : : WHITE ) ;
2023-11-05 00:53:37 +02:00
setType ( Type ) ;
2024-01-10 18:01:34 +02:00
this - > pos . w = area . w ;
this - > pos . h = area . h ;
2023-11-05 00:53:37 +02:00
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : setType ( EType newType )
2023-11-05 00:53:37 +02:00
{
if ( type ! = newType )
{
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2023-11-05 00:53:37 +02:00
type = newType ;
if ( getIndex ( ) < 0 )
{
image = std : : make_shared < CAnimImage > ( getFilename ( ) , 0 ) ;
image - > disable ( ) ;
}
else
{
image = std : : make_shared < CAnimImage > ( getFilename ( ) , getIndex ( ) ) ;
}
2024-02-27 13:39:50 +02:00
switch ( type )
{
case EType : : RESOURCE :
subtitle - > moveTo ( pos . topLeft ( ) + Point ( 35 , 55 ) ) ;
image - > moveTo ( pos . topLeft ( ) + Point ( 19 , 8 ) ) ;
break ;
case EType : : CREATURE_PLACEHOLDER :
case EType : : CREATURE :
subtitle - > moveTo ( pos . topLeft ( ) + Point ( 30 , 77 ) ) ;
break ;
case EType : : PLAYER :
subtitle - > moveTo ( pos . topLeft ( ) + Point ( 31 , 76 ) ) ;
break ;
case EType : : ARTIFACT_PLACEHOLDER :
case EType : : ARTIFACT_INSTANCE :
2024-02-29 22:33:12 +02:00
image - > moveTo ( pos . topLeft ( ) + Point ( 0 , 1 ) ) ;
2024-03-19 13:53:23 +02:00
subtitle - > moveTo ( pos . topLeft ( ) + Point ( 21 , 56 ) ) ;
2024-02-27 13:39:50 +02:00
break ;
case EType : : ARTIFACT_TYPE :
subtitle - > moveTo ( pos . topLeft ( ) + Point ( 35 , 57 ) ) ;
image - > moveTo ( pos . topLeft ( ) + Point ( 13 , 0 ) ) ;
break ;
}
2023-11-05 00:53:37 +02:00
}
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : setID ( int newID )
2023-11-05 00:53:37 +02:00
{
if ( id ! = newID )
{
id = newID ;
if ( image )
{
int index = getIndex ( ) ;
if ( index < 0 )
image - > disable ( ) ;
else
{
image - > enable ( ) ;
image - > setFrame ( index ) ;
}
}
}
}
2024-03-19 13:53:23 +02:00
void CTradeableItem : : clear ( )
{
setID ( - 1 ) ;
image - > setFrame ( 0 ) ;
image - > disable ( ) ;
subtitle - > clear ( ) ;
}
2023-11-19 02:05:10 +02:00
AnimationPath CTradeableItem : : getFilename ( )
2023-11-05 00:53:37 +02:00
{
switch ( type )
{
2023-12-04 23:21:49 +02:00
case EType : : RESOURCE :
2023-11-05 00:53:37 +02:00
return AnimationPath : : builtin ( " RESOURCE " ) ;
2023-12-04 23:21:49 +02:00
case EType : : PLAYER :
2023-11-05 00:53:37 +02:00
return AnimationPath : : builtin ( " CREST58 " ) ;
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_TYPE :
case EType : : ARTIFACT_PLACEHOLDER :
case EType : : ARTIFACT_INSTANCE :
2023-11-05 00:53:37 +02:00
return AnimationPath : : builtin ( " artifact " ) ;
2023-12-04 23:21:49 +02:00
case EType : : CREATURE :
2023-11-05 00:53:37 +02:00
return AnimationPath : : builtin ( " TWCRPORT " ) ;
default :
return { } ;
}
}
2023-11-19 02:05:10 +02:00
int CTradeableItem : : getIndex ( )
2023-11-05 00:53:37 +02:00
{
if ( id < 0 )
return - 1 ;
switch ( type )
{
2023-12-04 23:21:49 +02:00
case EType : : RESOURCE :
case EType : : PLAYER :
2023-11-05 00:53:37 +02:00
return id ;
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_TYPE :
case EType : : ARTIFACT_INSTANCE :
case EType : : ARTIFACT_PLACEHOLDER :
2023-11-05 00:53:37 +02:00
return CGI - > artifacts ( ) - > getByIndex ( id ) - > getIconIndex ( ) ;
2023-12-04 23:21:49 +02:00
case EType : : CREATURE :
2023-11-05 00:53:37 +02:00
return CGI - > creatures ( ) - > getByIndex ( id ) - > getIconIndex ( ) ;
default :
return - 1 ;
}
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : clickPressed ( const Point & cursorPosition )
2023-11-05 00:53:37 +02:00
{
if ( clickPressedCallback )
clickPressedCallback ( shared_from_this ( ) ) ;
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : hover ( bool on )
2023-11-05 00:53:37 +02:00
{
2024-03-20 13:28:19 +02:00
if ( ! on | | id = = - 1 )
2023-11-05 00:53:37 +02:00
{
GH . statusbar ( ) - > clear ( ) ;
return ;
}
switch ( type )
{
2023-12-04 23:21:49 +02:00
case EType : : CREATURE :
case EType : : CREATURE_PLACEHOLDER :
2023-11-05 00:53:37 +02:00
GH . statusbar ( ) - > write ( boost : : str ( boost : : format ( CGI - > generaltexth - > allTexts [ 481 ] ) % CGI - > creh - > objects [ id ] - > getNamePluralTranslated ( ) ) ) ;
break ;
2024-02-21 20:48:14 +02:00
case EType : : ARTIFACT_TYPE :
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_PLACEHOLDER :
2023-11-05 00:53:37 +02:00
if ( id < 0 )
GH . statusbar ( ) - > write ( CGI - > generaltexth - > zelp [ 582 ] . first ) ;
else
GH . statusbar ( ) - > write ( CGI - > artifacts ( ) - > getByIndex ( id ) - > getNameTranslated ( ) ) ;
break ;
2024-02-21 20:48:14 +02:00
case EType : : RESOURCE :
GH . statusbar ( ) - > write ( CGI - > generaltexth - > restypes [ id ] ) ;
break ;
case EType : : PLAYER :
GH . statusbar ( ) - > write ( CGI - > generaltexth - > capColors [ id ] ) ;
break ;
2023-11-05 00:53:37 +02:00
}
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : showPopupWindow ( const Point & cursorPosition )
2023-11-05 00:53:37 +02:00
{
switch ( type )
{
2023-12-04 23:21:49 +02:00
case EType : : CREATURE :
case EType : : CREATURE_PLACEHOLDER :
2023-11-05 00:53:37 +02:00
break ;
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_TYPE :
case EType : : ARTIFACT_PLACEHOLDER :
2023-11-05 00:53:37 +02:00
//TODO: it's would be better for market to contain actual CArtifactInstance and not just ids of certain artifact type so we can use getEffectiveDescription.
if ( id > = 0 )
CRClickPopup : : createAndPush ( CGI - > artifacts ( ) - > getByIndex ( id ) - > getDescriptionTranslated ( ) ) ;
break ;
}
}
2024-03-02 20:30:29 +02:00
void TradePanelBase : : update ( )
2023-11-20 00:37:43 +02:00
{
2024-02-22 22:49:30 +02:00
if ( deleteSlotsCheck )
slots . erase ( std : : remove_if ( slots . begin ( ) , slots . end ( ) , deleteSlotsCheck ) , slots . end ( ) ) ;
2023-11-20 00:37:43 +02:00
if ( updateSlotsCallback )
updateSlotsCallback ( ) ;
}
2023-12-04 23:21:49 +02:00
void TradePanelBase : : deselect ( )
2023-11-20 00:37:43 +02:00
{
2023-12-04 23:21:49 +02:00
for ( const auto & slot : slots )
2024-01-10 18:01:34 +02:00
slot - > selectSlot ( false ) ;
2023-11-20 00:37:43 +02:00
}
2023-12-04 23:21:49 +02:00
void TradePanelBase : : clearSubtitles ( )
2023-11-20 00:37:43 +02:00
{
2023-12-04 23:21:49 +02:00
for ( const auto & slot : slots )
2024-02-27 13:39:50 +02:00
slot - > subtitle - > clear ( ) ;
2023-11-20 00:37:43 +02:00
}
2023-12-04 23:21:49 +02:00
void TradePanelBase : : updateOffer ( CTradeableItem & slot , int cost , int qty )
2023-11-20 00:37:43 +02:00
{
2024-02-27 13:39:50 +02:00
std : : string subtitle = std : : to_string ( qty ) ;
2023-11-20 00:37:43 +02:00
if ( cost ! = 1 )
2023-12-04 23:21:49 +02:00
{
2024-02-27 13:39:50 +02:00
subtitle . append ( " / " ) ;
subtitle . append ( std : : to_string ( cost ) ) ;
2023-12-04 23:21:49 +02:00
}
2024-02-27 13:39:50 +02:00
slot . subtitle - > setText ( subtitle ) ;
2023-11-20 00:37:43 +02:00
}
2024-03-19 13:53:23 +02:00
void TradePanelBase : : setShowcaseSubtitle ( const std : : string & text )
2024-02-03 22:59:05 +02:00
{
2024-03-19 13:53:23 +02:00
showcaseSlot - > subtitle - > setText ( text ) ;
2024-02-03 22:59:05 +02:00
}
2024-03-19 13:53:23 +02:00
int TradePanelBase : : getSelectedItemId ( ) const
2024-02-27 13:39:50 +02:00
{
2024-03-19 13:53:23 +02:00
if ( highlightedSlot )
return highlightedSlot - > id ;
else
return - 1 ;
2024-02-27 13:39:50 +02:00
}
2024-03-19 13:53:23 +02:00
void TradePanelBase : : onSlotClickPressed ( const std : : shared_ptr < CTradeableItem > & newSlot )
2024-02-27 13:39:50 +02:00
{
2024-03-19 13:53:23 +02:00
assert ( vstd : : contains ( slots , newSlot ) ) ;
if ( newSlot = = highlightedSlot )
return ;
if ( highlightedSlot )
highlightedSlot - > selectSlot ( false ) ;
highlightedSlot = newSlot ;
newSlot - > selectSlot ( true ) ;
2024-02-27 13:39:50 +02:00
}
2024-03-20 13:28:19 +02:00
bool TradePanelBase : : isHighlighted ( ) const
{
return getSelectedItemId ( ) ! = - 1 ;
}
2024-02-27 13:39:50 +02:00
ResourcesPanel : : ResourcesPanel ( const CTradeableItem : : ClickPressedFunctor & clickPressedCallback ,
const UpdateSlotsFunctor & updateSubtitles )
2023-11-19 02:05:10 +02:00
{
assert ( resourcesForTrade . size ( ) = = slotsPos . size ( ) ) ;
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2023-11-19 02:05:10 +02:00
for ( const auto & res : resourcesForTrade )
{
2024-02-27 13:39:50 +02:00
auto slot = slots . emplace_back ( std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ res . num ] , slotDimension ) , EType : : RESOURCE , res . num , res . num ) ) ;
2023-12-03 17:08:30 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-11-19 02:05:10 +02:00
}
2023-11-20 00:37:43 +02:00
updateSlotsCallback = updateSubtitles ;
2024-03-19 13:53:23 +02:00
showcaseSlot = std : : make_shared < CTradeableItem > ( Rect ( selectedPos , slotDimension ) , EType : : RESOURCE , 0 , 0 ) ;
2023-11-19 02:05:10 +02:00
}
2024-02-27 13:39:50 +02:00
ArtifactsPanel : : ArtifactsPanel ( const CTradeableItem : : ClickPressedFunctor & clickPressedCallback ,
const UpdateSlotsFunctor & updateSubtitles , const std : : vector < TradeItemBuy > & arts )
2023-11-19 02:05:10 +02:00
{
2023-12-03 17:08:30 +02:00
assert ( slotsForTrade = = slotsPos . size ( ) ) ;
assert ( slotsForTrade = = arts . size ( ) ) ;
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2023-11-19 02:05:10 +02:00
2023-12-03 17:08:30 +02:00
for ( auto slotIdx = 0 ; slotIdx < slotsForTrade ; slotIdx + + )
2023-11-20 00:37:43 +02:00
{
2023-12-03 17:08:30 +02:00
auto artType = arts [ slotIdx ] . getNum ( ) ;
if ( artType ! = ArtifactID : : NONE )
{
2024-01-10 18:01:34 +02:00
auto slot = slots . emplace_back ( std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ slotIdx ] , slotDimension ) ,
2024-02-27 13:39:50 +02:00
EType : : ARTIFACT_TYPE , artType , slotIdx ) ) ;
2023-12-03 17:08:30 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-12-03 17:08:30 +02:00
}
2023-11-20 00:37:43 +02:00
}
updateSlotsCallback = updateSubtitles ;
2024-03-19 13:53:23 +02:00
showcaseSlot = std : : make_shared < CTradeableItem > ( Rect ( selectedPos , slotDimension ) , EType : : ARTIFACT_TYPE , 0 , 0 ) ;
showcaseSlot - > subtitle - > moveBy ( Point ( 0 , 1 ) ) ;
2023-11-19 19:49:59 +02:00
}
2024-02-27 13:39:50 +02:00
PlayersPanel : : PlayersPanel ( const CTradeableItem : : ClickPressedFunctor & clickPressedCallback )
2023-11-28 17:01:53 +02:00
{
2023-12-04 23:21:49 +02:00
assert ( PlayerColor : : PLAYER_LIMIT_I < = slotsPos . size ( ) + 1 ) ;
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2023-11-28 17:01:53 +02:00
std : : vector < PlayerColor > players ;
for ( auto player = PlayerColor ( 0 ) ; player < PlayerColor : : PLAYER_LIMIT_I ; player + + )
{
if ( player ! = LOCPLINT - > playerID & & LOCPLINT - > cb - > getPlayerStatus ( player ) = = EPlayerStatus : : INGAME )
players . emplace_back ( player ) ;
}
slots . resize ( players . size ( ) ) ;
int slotNum = 0 ;
for ( auto & slot : slots )
{
2024-02-27 13:39:50 +02:00
slot = std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ slotNum ] , slotDimension ) , EType : : PLAYER , players [ slotNum ] . num , slotNum ) ;
2023-11-28 17:01:53 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2024-02-27 13:39:50 +02:00
slot - > subtitle - > setText ( CGI - > generaltexth - > capColors [ players [ slotNum ] . num ] ) ;
2023-12-04 23:21:49 +02:00
slotNum + + ;
2023-11-28 17:01:53 +02:00
}
2024-03-19 13:53:23 +02:00
showcaseSlot = std : : make_shared < CTradeableItem > ( Rect ( selectedPos , slotDimension ) , EType : : PLAYER , 0 , 0 ) ;
2023-11-28 17:01:53 +02:00
}
2024-02-27 13:39:50 +02:00
CreaturesPanel : : CreaturesPanel ( const CTradeableItem : : ClickPressedFunctor & clickPressedCallback , const slotsData & initialSlots )
2023-12-03 17:08:30 +02:00
{
assert ( initialSlots . size ( ) < = GameConstants : : ARMY_SIZE ) ;
assert ( slotsPos . size ( ) < = GameConstants : : ARMY_SIZE ) ;
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2023-12-03 17:08:30 +02:00
2023-12-04 23:21:49 +02:00
for ( const auto & [ creatureId , slotId , creaturesNum ] : initialSlots )
2023-12-03 17:08:30 +02:00
{
2024-01-10 18:01:34 +02:00
auto slot = slots . emplace_back ( std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ slotId . num ] , slotDimension ) ,
2024-02-27 13:39:50 +02:00
creaturesNum = = 0 ? EType : : CREATURE_PLACEHOLDER : EType : : CREATURE , creatureId . num , slotId ) ) ;
2023-12-03 17:08:30 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
if ( creaturesNum ! = 0 )
2024-02-27 13:39:50 +02:00
slot - > subtitle - > setText ( std : : to_string ( creaturesNum ) ) ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-12-04 19:16:26 +02:00
}
2024-03-19 13:53:23 +02:00
showcaseSlot = std : : make_shared < CTradeableItem > ( Rect ( selectedPos , slotDimension ) , EType : : CREATURE , 0 , 0 ) ;
2023-12-04 19:16:26 +02:00
}
2024-02-27 13:39:50 +02:00
CreaturesPanel : : CreaturesPanel ( const CTradeableItem : : ClickPressedFunctor & clickPressedCallback ,
2023-12-04 23:21:49 +02:00
const std : : vector < std : : shared_ptr < CTradeableItem > > & srcSlots , bool emptySlots )
2023-12-04 19:16:26 +02:00
{
assert ( slots . size ( ) < = GameConstants : : ARMY_SIZE ) ;
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2023-12-04 19:16:26 +02:00
2023-12-04 23:21:49 +02:00
for ( const auto & srcSlot : srcSlots )
2023-12-04 19:16:26 +02:00
{
2024-01-10 18:01:34 +02:00
auto slot = slots . emplace_back ( std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ srcSlot - > serial ] , srcSlot - > pos . dimensions ( ) ) ,
2024-02-27 13:39:50 +02:00
emptySlots ? EType : : CREATURE_PLACEHOLDER : EType : : CREATURE , srcSlot - > id , srcSlot - > serial ) ) ;
2023-12-04 19:16:26 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
2024-02-27 13:39:50 +02:00
slot - > subtitle - > setText ( emptySlots ? " " : srcSlot - > subtitle - > getText ( ) ) ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-12-03 17:08:30 +02:00
}
2024-03-19 13:53:23 +02:00
showcaseSlot = std : : make_shared < CTradeableItem > ( Rect ( selectedPos , slotDimension ) , EType : : CREATURE , 0 , 0 ) ;
2023-12-03 17:08:30 +02:00
}
2024-02-29 12:02:39 +02:00
ArtifactsAltarPanel : : ArtifactsAltarPanel ( const CTradeableItem : : ClickPressedFunctor & clickPressedCallback )
{
2024-08-09 17:30:04 +02:00
OBJECT_CONSTRUCTION ;
2024-02-29 12:02:39 +02:00
int slotNum = 0 ;
for ( auto & altarSlotPos : slotsPos )
{
auto slot = slots . emplace_back ( std : : make_shared < CTradeableItem > ( Rect ( altarSlotPos , Point ( 44 , 44 ) ) , EType : : ARTIFACT_PLACEHOLDER , - 1 , slotNum ) ) ;
slot - > clickPressedCallback = clickPressedCallback ;
slot - > subtitle - > clear ( ) ;
2024-02-29 22:33:12 +02:00
slot - > subtitle - > moveBy ( Point ( 0 , - 1 ) ) ;
2024-02-29 12:02:39 +02:00
slotNum + + ;
}
2024-03-19 13:53:23 +02:00
showcaseSlot = std : : make_shared < CTradeableItem > ( Rect ( selectedPos , slotDimension ) , EType : : ARTIFACT_TYPE , 0 , 0 ) ;
showcaseSlot - > subtitle - > moveBy ( Point ( 0 , 3 ) ) ;
2024-02-29 12:02:39 +02:00
}