2023-04-30 15:13:07 +02:00
/*
* Reward . cpp , part of VCMI engine
*
* 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"
# include "Reward.h"
2023-06-02 20:47:37 +02:00
# include "../mapObjects/CGHeroInstance.h"
2023-09-15 10:06:06 +02:00
# include "../serializer/JsonSerializeFormat.h"
# include "../constants/StringConstants.h"
# include "../CSkillHandler.h"
2023-06-02 20:47:37 +02:00
2023-04-30 15:13:07 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2023-10-04 13:11:13 +02:00
void Rewardable : : RewardRevealTiles : : serializeJson ( JsonSerializeFormat & handler )
{
2023-10-20 23:44:57 +02:00
handler . serializeBool ( " hide " , hide ) ;
handler . serializeInt ( " scoreSurface " , scoreSurface ) ;
handler . serializeInt ( " scoreSubterra " , scoreSubterra ) ;
handler . serializeInt ( " scoreWater " , scoreWater ) ;
handler . serializeInt ( " scoreRock " , scoreRock ) ;
handler . serializeInt ( " radius " , radius ) ;
2023-10-04 13:11:13 +02:00
}
2023-06-02 20:47:37 +02:00
Rewardable : : Reward : : Reward ( )
: heroExperience ( 0 )
, heroLevel ( 0 )
, manaDiff ( 0 )
, manaPercentage ( - 1 )
2023-12-23 21:31:29 +02:00
, manaOverflowFactor ( 0 )
2023-06-02 20:47:37 +02:00
, movePoints ( 0 )
, movePercentage ( - 1 )
, primary ( 4 , 0 )
, removeObject ( false )
2023-10-05 15:13:52 +02:00
, spellCast ( SpellID : : NONE , MasteryLevel : : NONE )
2023-06-02 20:47:37 +02:00
{
}
Rewardable : : Reward : : ~ Reward ( ) = default ;
2023-04-30 15:13:07 +02:00
si32 Rewardable : : Reward : : calculateManaPoints ( const CGHeroInstance * hero ) const
{
si32 manaScaled = hero - > mana ;
if ( manaPercentage > = 0 )
manaScaled = hero - > manaLimit ( ) * manaPercentage / 100 ;
si32 manaMissing = std : : max ( 0 , hero - > manaLimit ( ) - manaScaled ) ;
si32 manaGranted = std : : min ( manaMissing , manaDiff ) ;
si32 manaOverflow = manaDiff - manaGranted ;
si32 manaOverLimit = manaOverflow * manaOverflowFactor / 100 ;
si32 manaOutput = manaScaled + manaGranted + manaOverLimit ;
return manaOutput ;
}
Component Rewardable : : Reward : : getDisplayedComponent ( const CGHeroInstance * h ) const
{
std : : vector < Component > comps ;
loadComponents ( comps , h ) ;
2024-04-25 13:04:45 +02:00
if ( ! comps . empty ( ) )
return comps . front ( ) ;
// Rewardable requested component that represent such rewards, to be used as button in UI selection dialog, e.g. Chest with its experience / money pick
// However reward is either completely empty OR has no rewards that target hero can receive OR these rewards have no visible component (e.g. movement)
// Such cases are unreachable in H3, however can be reached by mods
logMod - > warn ( " Failed to find displayed component for reward! " ) ;
return Component ( ComponentType : : NONE , 0 ) ;
2023-04-30 15:13:07 +02:00
}
2023-10-16 22:55:37 +02:00
void Rewardable : : Reward : : loadComponents ( std : : vector < Component > & comps , const CGHeroInstance * h ) const
2023-04-30 15:13:07 +02:00
{
for ( auto comp : extraComponents )
comps . push_back ( comp ) ;
2023-09-17 16:04:34 +02:00
for ( auto & bonus : bonuses )
{
if ( bonus . type = = BonusType : : MORALE )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : MORALE , bonus . val ) ;
2023-09-17 16:04:34 +02:00
if ( bonus . type = = BonusType : : LUCK )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : LUCK , bonus . val ) ;
2023-09-17 16:04:34 +02:00
}
2023-04-30 15:13:07 +02:00
if ( heroExperience )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : EXPERIENCE , static_cast < si32 > ( h ? h - > calculateXp ( heroExperience ) : heroExperience ) ) ;
2023-10-16 22:55:37 +02:00
2023-04-30 15:13:07 +02:00
if ( heroLevel )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : LEVEL , heroLevel ) ;
2023-04-30 15:13:07 +02:00
if ( manaDiff | | manaPercentage > = 0 )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : MANA , h ? ( calculateManaPoints ( h ) - h - > mana ) : manaDiff ) ;
2023-04-30 15:13:07 +02:00
for ( size_t i = 0 ; i < primary . size ( ) ; i + + )
{
if ( primary [ i ] ! = 0 )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : PRIM_SKILL , PrimarySkill ( i ) , primary [ i ] ) ;
2023-04-30 15:13:07 +02:00
}
for ( const auto & entry : secondary )
2024-06-26 14:38:23 +02:00
{
auto skillID = entry . first ;
int levelsGained = entry . second ;
2024-07-10 16:34:05 +02:00
int currentLevel = h ? h - > getSecSkillLevel ( skillID ) : 0 ;
2024-06-26 14:38:23 +02:00
int finalLevel = std : : min ( static_cast < int > ( MasteryLevel : : EXPERT ) , currentLevel + levelsGained ) ;
comps . emplace_back ( ComponentType : : SEC_SKILL , entry . first , finalLevel ) ;
}
2023-04-30 15:13:07 +02:00
for ( const auto & entry : artifacts )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : ARTIFACT , entry ) ;
2023-04-30 15:13:07 +02:00
for ( const auto & entry : spells )
2024-07-27 20:09:12 +02:00
{
bool learnable = ! h | | h - > canLearnSpell ( entry . toEntity ( VLC ) , true ) ;
comps . emplace_back ( ComponentType : : SPELL , entry , learnable ? 0 : - 1 ) ;
}
2023-04-30 15:13:07 +02:00
for ( const auto & entry : creatures )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : CREATURE , entry . type - > getId ( ) , entry . count ) ;
2023-04-30 15:13:07 +02:00
for ( size_t i = 0 ; i < resources . size ( ) ; i + + )
{
if ( resources [ i ] ! = 0 )
2023-10-31 11:09:56 +02:00
comps . emplace_back ( ComponentType : : RESOURCE , GameResID ( i ) , resources [ i ] ) ;
2023-04-30 15:13:07 +02:00
}
}
2023-09-15 10:06:06 +02:00
void Rewardable : : Reward : : serializeJson ( JsonSerializeFormat & handler )
{
resources . serializeJson ( handler , " resources " ) ;
handler . serializeBool ( " removeObject " , removeObject ) ;
handler . serializeInt ( " manaPercentage " , manaPercentage ) ;
handler . serializeInt ( " movePercentage " , movePercentage ) ;
handler . serializeInt ( " heroExperience " , heroExperience ) ;
handler . serializeInt ( " heroLevel " , heroLevel ) ;
handler . serializeInt ( " manaDiff " , manaDiff ) ;
handler . serializeInt ( " manaOverflowFactor " , manaOverflowFactor ) ;
handler . serializeInt ( " movePoints " , movePoints ) ;
handler . serializeIdArray ( " artifacts " , artifacts ) ;
handler . serializeIdArray ( " spells " , spells ) ;
handler . enterArray ( " creatures " ) . serializeStruct ( creatures ) ;
2023-09-17 22:19:45 +02:00
handler . enterArray ( " primary " ) . serializeArray ( primary ) ;
2023-09-15 10:06:06 +02:00
{
auto a = handler . enterArray ( " secondary " ) ;
2023-09-17 22:19:45 +02:00
std : : vector < std : : pair < SecondarySkill , si32 > > fieldValue ( secondary . begin ( ) , secondary . end ( ) ) ;
a . serializeStruct < std : : pair < SecondarySkill , si32 > > ( fieldValue , [ ] ( JsonSerializeFormat & h , std : : pair < SecondarySkill , si32 > & e )
2023-09-15 10:06:06 +02:00
{
2023-11-02 17:48:48 +02:00
h . serializeId ( " skill " , e . first ) ;
2023-09-17 22:19:45 +02:00
h . serializeId ( " level " , e . second , 0 , [ ] ( const std : : string & i ) { return vstd : : find_pos ( NSecondarySkill : : levels , i ) ; } , [ ] ( si32 i ) { return NSecondarySkill : : levels . at ( i ) ; } ) ;
} ) ;
2023-09-15 10:06:06 +02:00
a . syncSize ( fieldValue ) ;
2023-09-17 22:19:45 +02:00
secondary = std : : map < SecondarySkill , si32 > ( fieldValue . begin ( ) , fieldValue . end ( ) ) ;
2023-09-15 10:06:06 +02:00
}
{
auto a = handler . enterArray ( " creaturesChange " ) ;
2023-09-17 22:19:45 +02:00
std : : vector < std : : pair < CreatureID , CreatureID > > fieldValue ( creaturesChange . begin ( ) , creaturesChange . end ( ) ) ;
a . serializeStruct < std : : pair < CreatureID , CreatureID > > ( fieldValue , [ ] ( JsonSerializeFormat & h , std : : pair < CreatureID , CreatureID > & e )
2023-09-15 10:06:06 +02:00
{
2023-09-17 22:19:45 +02:00
h . serializeId ( " creature " , e . first , CreatureID { } ) ;
h . serializeId ( " amount " , e . second , CreatureID { } ) ;
} ) ;
creaturesChange = std : : map < CreatureID , CreatureID > ( fieldValue . begin ( ) , fieldValue . end ( ) ) ;
2023-09-15 10:06:06 +02:00
}
{
auto a = handler . enterStruct ( " spellCast " ) ;
a - > serializeId ( " spell " , spellCast . first , SpellID { } ) ;
a - > serializeInt ( " level " , spellCast . second ) ;
}
}
2023-04-30 15:13:07 +02:00
VCMI_LIB_NAMESPACE_END