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"
# include "../../../lib/CGeneralTextHandler.h"
# include "../../../lib/mapObjects/CGHeroInstance.h"
2023-11-05 00:53:37 +02:00
2024-01-10 18:01:34 +02:00
CTradeableItem : : CTradeableItem ( const Rect & area , EType Type , int ID , bool Left , int Serial )
: SelectableSlot ( area , Point ( 1 , 1 ) )
, artInstance ( nullptr )
2023-11-05 00:53:37 +02:00
, type ( EType ( - 1 ) ) // set to invalid, will be corrected in setType
, id ( ID )
, serial ( Serial )
, left ( Left )
2023-12-04 23:21:49 +02:00
, downSelection ( false )
2023-11-05 00:53:37 +02:00
{
OBJECT_CONSTRUCTION_CAPTURING ( 255 - DISPOSE ) ;
2024-01-10 18:01:34 +02:00
addUsedEvents ( LCLICK ) ;
addUsedEvents ( HOVER ) ;
addUsedEvents ( SHOW_POPUP ) ;
2023-12-04 23:21:49 +02:00
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 )
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING ( 255 - DISPOSE ) ;
type = newType ;
if ( getIndex ( ) < 0 )
{
image = std : : make_shared < CAnimImage > ( getFilename ( ) , 0 ) ;
image - > disable ( ) ;
}
else
{
image = std : : make_shared < CAnimImage > ( getFilename ( ) , getIndex ( ) ) ;
}
}
}
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 ) ;
}
}
}
}
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 : : showAll ( Canvas & to )
2023-11-05 00:53:37 +02:00
{
Point posToBitmap ;
Point posToSubCenter ;
2023-12-04 23:21:49 +02:00
switch ( type )
2023-11-05 00:53:37 +02:00
{
2023-12-04 23:21:49 +02:00
case EType : : RESOURCE :
2023-11-05 00:53:37 +02:00
posToBitmap = Point ( 19 , 9 ) ;
2023-11-28 17:01:53 +02:00
posToSubCenter = Point ( 35 , 57 ) ;
2023-11-05 00:53:37 +02:00
break ;
2023-12-04 23:21:49 +02:00
case EType : : CREATURE_PLACEHOLDER :
case EType : : CREATURE :
2023-11-05 02:01:23 +02:00
posToSubCenter = Point ( 29 , 77 ) ;
2023-11-05 00:53:37 +02:00
break ;
2023-12-04 23:21:49 +02:00
case EType : : PLAYER :
2023-11-28 17:01:53 +02:00
posToSubCenter = Point ( 31 , 77 ) ;
2023-11-05 00:53:37 +02:00
break ;
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_PLACEHOLDER :
case EType : : ARTIFACT_INSTANCE :
2023-11-28 17:01:53 +02:00
posToSubCenter = Point ( 22 , 51 ) ;
2023-11-05 00:53:37 +02:00
if ( downSelection )
posToSubCenter . y + = 8 ;
break ;
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_TYPE :
2023-11-28 17:01:53 +02:00
posToSubCenter = Point ( 35 , 57 ) ;
posToBitmap = Point ( 13 , 0 ) ;
2023-11-05 00:53:37 +02:00
break ;
}
if ( image )
{
image - > moveTo ( pos . topLeft ( ) + posToBitmap ) ;
CIntObject : : showAll ( to ) ;
}
to . drawText ( pos . topLeft ( ) + posToSubCenter , FONT_SMALL , Colors : : WHITE , ETextAlignment : : CENTER , subtitle ) ;
}
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 : : showAllAt ( const Point & dstPos , const std : : string & customSub , Canvas & to )
2023-11-05 00:53:37 +02:00
{
Rect oldPos = pos ;
std : : string oldSub = subtitle ;
downSelection = true ;
moveTo ( dstPos ) ;
subtitle = customSub ;
showAll ( to ) ;
downSelection = false ;
moveTo ( oldPos . topLeft ( ) ) ;
subtitle = oldSub ;
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : hover ( bool on )
2023-11-05 00:53:37 +02:00
{
if ( ! on )
{
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 ;
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 ;
}
}
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 ;
}
}
2023-11-19 02:05:10 +02:00
std : : string CTradeableItem : : getName ( int number ) const
2023-11-05 00:53:37 +02:00
{
switch ( type )
{
2023-12-04 23:21:49 +02:00
case EType : : PLAYER :
2023-11-05 00:53:37 +02:00
return CGI - > generaltexth - > capColors [ id ] ;
2023-12-04 23:21:49 +02:00
case EType : : RESOURCE :
2023-11-05 00:53:37 +02:00
return CGI - > generaltexth - > restypes [ id ] ;
2023-12-04 23:21:49 +02:00
case EType : : CREATURE :
2023-11-05 00:53:37 +02:00
if ( number = = 1 )
return CGI - > creh - > objects [ id ] - > getNameSingularTranslated ( ) ;
else
return CGI - > creh - > objects [ id ] - > getNamePluralTranslated ( ) ;
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_TYPE :
case EType : : ARTIFACT_INSTANCE :
2023-11-05 00:53:37 +02:00
return CGI - > artifacts ( ) - > getByIndex ( id ) - > getNameTranslated ( ) ;
}
logGlobal - > error ( " Invalid trade item type: %d " , ( int ) type ) ;
return " " ;
}
2023-11-19 02:05:10 +02:00
const CArtifactInstance * CTradeableItem : : getArtInstance ( ) const
2023-11-05 00:53:37 +02:00
{
switch ( type )
{
2023-12-04 23:21:49 +02:00
case EType : : ARTIFACT_PLACEHOLDER :
case EType : : ARTIFACT_INSTANCE :
2024-01-10 18:01:34 +02:00
return artInstance ;
2023-11-05 00:53:37 +02:00
default :
return nullptr ;
}
}
2023-11-19 02:05:10 +02:00
void CTradeableItem : : setArtInstance ( const CArtifactInstance * art )
2023-11-05 00:53:37 +02:00
{
2023-12-04 23:21:49 +02:00
assert ( type = = EType : : ARTIFACT_PLACEHOLDER | | type = = EType : : ARTIFACT_INSTANCE ) ;
2024-01-10 18:01:34 +02:00
artInstance = art ;
2023-11-05 00:53:37 +02:00
if ( art )
2023-12-04 23:21:49 +02:00
setID ( art - > getTypeId ( ) ) ;
2023-11-05 00:53:37 +02:00
else
setID ( - 1 ) ;
}
2023-12-04 23:21:49 +02:00
void TradePanelBase : : updateSlots ( )
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 )
2023-11-20 00:37:43 +02:00
slot - > subtitle . clear ( ) ;
}
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
{
2023-12-03 17:08:30 +02:00
slot . subtitle = std : : to_string ( qty ) ;
2023-11-20 00:37:43 +02:00
if ( cost ! = 1 )
2023-12-04 23:21:49 +02:00
{
slot . subtitle . append ( " / " ) ;
slot . subtitle . append ( std : : to_string ( cost ) ) ;
}
2023-11-20 00:37:43 +02:00
}
2023-12-04 23:21:49 +02:00
void TradePanelBase : : deleteSlots ( )
2023-12-03 17:08:30 +02:00
{
if ( deleteSlotsCheck )
slots . erase ( std : : remove_if ( slots . begin ( ) , slots . end ( ) , deleteSlotsCheck ) , slots . end ( ) ) ;
}
2023-12-04 23:21:49 +02:00
ResourcesPanel : : ResourcesPanel ( CTradeableItem : : ClickPressedFunctor clickPressedCallback , UpdateSlotsFunctor updateSubtitles )
2023-11-19 02:05:10 +02:00
{
assert ( resourcesForTrade . size ( ) = = slotsPos . size ( ) ) ;
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING ( 255 - DISPOSE ) ;
for ( const auto & res : resourcesForTrade )
{
2024-01-10 18:01:34 +02:00
auto slot = slots . emplace_back ( std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ res . num ] , slotDimension ) ,
EType : : RESOURCE , res . num , true , 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 ;
2023-11-19 02:05:10 +02:00
}
2023-12-04 23:21:49 +02:00
ArtifactsPanel : : ArtifactsPanel ( CTradeableItem : : ClickPressedFunctor clickPressedCallback , 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 ( ) ) ;
2023-11-20 00:37:43 +02:00
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING ( 255 - DISPOSE ) ;
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 ) ,
EType : : ARTIFACT_TYPE , artType , false , 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 ;
2023-11-19 19:49:59 +02:00
}
2023-12-04 23:21:49 +02:00
PlayersPanel : : PlayersPanel ( 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 ) ;
2023-11-28 17:01:53 +02:00
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING ( 255 - DISPOSE ) ;
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-01-10 18:01:34 +02:00
slot = std : : make_shared < CTradeableItem > ( Rect ( slotsPos [ slotNum ] , slotDimension ) , EType : : PLAYER , players [ slotNum ] . num , false , slotNum ) ;
2023-11-28 17:01:53 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-12-04 23:21:49 +02:00
slot - > subtitle = CGI - > generaltexth - > capColors [ players [ slotNum ] . num ] ;
slotNum + + ;
2023-11-28 17:01:53 +02:00
}
}
2023-12-04 23:21:49 +02:00
CreaturesPanel : : CreaturesPanel ( 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 ) ;
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING ( 255 - DISPOSE ) ;
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 ) ,
2023-12-04 23:21:49 +02:00
creaturesNum = = 0 ? EType : : CREATURE_PLACEHOLDER : EType : : CREATURE , creatureId . num , true , slotId ) ) ;
2023-12-03 17:08:30 +02:00
slot - > clickPressedCallback = clickPressedCallback ;
if ( creaturesNum ! = 0 )
2023-12-04 23:21:49 +02:00
slot - > subtitle = std : : to_string ( creaturesNum ) ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-12-04 19:16:26 +02:00
}
}
2023-12-04 23:21:49 +02:00
CreaturesPanel : : CreaturesPanel ( CTradeableItem : : ClickPressedFunctor clickPressedCallback ,
const std : : vector < std : : shared_ptr < CTradeableItem > > & srcSlots , bool emptySlots )
2023-12-04 19:16:26 +02:00
{
assert ( slots . size ( ) < = GameConstants : : ARMY_SIZE ) ;
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING ( 255 - DISPOSE ) ;
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 ( ) ) ,
2023-12-04 19:16:26 +02:00
emptySlots ? EType : : CREATURE_PLACEHOLDER : EType : : CREATURE , srcSlot - > id , true , srcSlot - > serial ) ) ;
slot - > clickPressedCallback = clickPressedCallback ;
slot - > subtitle = emptySlots ? " " : srcSlot - > subtitle ;
2024-01-10 18:01:34 +02:00
slot - > setSelectionWidth ( selectionWidth ) ;
2023-12-03 17:08:30 +02:00
}
}