2012-10-17 18:03:02 +02:00
# include "trainingwindow.hpp"
2015-01-10 02:50:43 +01:00
# include <MyGUI_Gui.h>
2012-10-17 18:03:02 +02:00
# include "../mwbase/windowmanager.hpp"
# include "../mwbase/environment.hpp"
# include "../mwbase/world.hpp"
2012-11-05 19:53:55 +01:00
# include "../mwbase/mechanicsmanager.hpp"
2012-10-17 18:03:02 +02:00
2013-05-11 18:38:27 +02:00
# include "../mwworld/class.hpp"
2013-11-21 04:27:53 +01:00
# include "../mwworld/containerstore.hpp"
2014-12-19 11:26:54 +01:00
# include "../mwworld/esmstore.hpp"
2012-10-17 18:03:02 +02:00
# include "../mwmechanics/npcstats.hpp"
2015-08-21 21:12:39 +12:00
# include "../mwmechanics/actorutil.hpp"
2012-10-17 18:03:02 +02:00
2020-07-06 20:28:08 +02:00
# include <components/settings/settings.hpp>
2012-10-17 18:03:02 +02:00
# include "tooltips.hpp"
2014-06-09 03:40:14 +02:00
namespace
{
// Sorts a container descending by skill value. If skill value is equal, sorts ascending by skill ID.
// pair <skill ID, skill value>
bool sortSkills ( const std : : pair < int , int > & left , const std : : pair < int , int > & right )
{
if ( left = = right )
return false ;
if ( left . second > right . second )
return true ;
else if ( left . second < right . second )
return false ;
return left . first < right . first ;
}
}
2012-10-17 18:03:02 +02:00
namespace MWGui
{
2013-04-10 14:46:21 -04:00
TrainingWindow : : TrainingWindow ( )
: WindowBase ( " openmw_trainingwindow.layout " )
2015-03-08 13:07:29 +13:00
, mTimeAdvancer ( 0.05f )
2020-07-07 09:50:02 +02:00
, mTrainingSkillBasedOnBaseSkill ( Settings : : Manager : : getBool ( " trainers training skills based on base skill " , " Game " ) )
2012-10-17 18:03:02 +02:00
{
getWidget ( mTrainingOptions , " TrainingOptions " ) ;
getWidget ( mCancelButton , " CancelButton " ) ;
getWidget ( mPlayerGold , " PlayerGold " ) ;
mCancelButton - > eventMouseButtonClick + = MyGUI : : newDelegate ( this , & TrainingWindow : : onCancelButtonClicked ) ;
2015-02-07 04:05:28 +01:00
mTimeAdvancer . eventProgressChanged + = MyGUI : : newDelegate ( this , & TrainingWindow : : onTrainingProgressChanged ) ;
mTimeAdvancer . eventFinished + = MyGUI : : newDelegate ( this , & TrainingWindow : : onTrainingFinished ) ;
2012-10-17 18:03:02 +02:00
}
2017-09-22 17:10:53 +02:00
void TrainingWindow : : onOpen ( )
2012-10-17 18:03:02 +02:00
{
2017-09-24 12:58:14 +02:00
if ( mTimeAdvancer . isRunning ( ) )
{
mProgressBar . setVisible ( true ) ;
setVisible ( false ) ;
}
else
mProgressBar . setVisible ( false ) ;
2012-10-17 18:03:02 +02:00
center ( ) ;
}
2017-09-22 21:26:41 +02:00
void TrainingWindow : : setPtr ( const MWWorld : : Ptr & actor )
2012-10-17 18:03:02 +02:00
{
mPtr = actor ;
2015-08-21 21:12:39 +12:00
MWWorld : : Ptr player = MWMechanics : : getPlayer ( ) ;
2014-01-08 23:37:46 +01:00
int playerGold = player . getClass ( ) . getContainerStore ( player ) . count ( MWWorld : : ContainerStore : : sGoldId ) ;
2015-01-10 03:01:01 +01:00
mPlayerGold - > setCaptionWithReplacing ( " #{sGold}: " + MyGUI : : utility : : toString ( playerGold ) ) ;
2012-10-17 18:03:02 +02:00
// NPC can train you in his best 3 skills
2018-12-23 15:18:33 +04:00
std : : vector < std : : pair < int , float > > skills ;
2012-10-17 18:03:02 +02:00
2020-07-06 20:28:08 +02:00
MWMechanics : : NpcStats const & actorStats ( actor . getClass ( ) . getNpcStats ( actor ) ) ;
2012-10-17 18:03:02 +02:00
for ( int i = 0 ; i < ESM : : Skill : : Length ; + + i )
{
2020-07-06 20:28:08 +02:00
float value = getSkillForTraining ( actorStats , i ) ;
2012-10-17 18:03:02 +02:00
2020-10-17 12:26:35 +04:00
skills . emplace_back ( i , value ) ;
2012-10-17 18:03:02 +02:00
}
2014-06-09 03:40:14 +02:00
std : : sort ( skills . begin ( ) , skills . end ( ) , sortSkills ) ;
2012-10-17 18:03:02 +02:00
MyGUI : : EnumeratorWidgetPtr widgets = mTrainingOptions - > getEnumerator ( ) ;
MyGUI : : Gui : : getInstance ( ) . destroyWidgets ( widgets ) ;
2014-05-22 20:37:22 +02:00
MWMechanics : : NpcStats & pcStats = player . getClass ( ) . getNpcStats ( player ) ;
2012-10-17 18:03:02 +02:00
2012-11-06 13:43:48 +04:00
const MWWorld : : Store < ESM : : GameSetting > & gmst =
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : GameSetting > ( ) ;
2012-10-17 18:03:02 +02:00
for ( int i = 0 ; i < 3 ; + + i )
{
2020-09-08 16:55:12 +04:00
int price = static_cast < int > ( pcStats . getSkill ( skills [ i ] . first ) . getBase ( ) * gmst . find ( " iTrainingMod " ) - > mValue . getInteger ( ) ) ;
price = std : : max ( 1 , price ) ;
price = MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > getBarterOffer ( mPtr , price , true ) ;
2012-10-17 18:03:02 +02:00
2014-10-17 18:58:20 +02:00
MyGUI : : Button * button = mTrainingOptions - > createWidget < MyGUI : : Button > ( price < = playerGold ? " SandTextButton " : " SandTextButtonDisabled " , // can't use setEnabled since that removes tooltip
2012-10-17 18:03:02 +02:00
MyGUI : : IntCoord ( 5 , 5 + i * 18 , mTrainingOptions - > getWidth ( ) - 10 , 18 ) , MyGUI : : Align : : Default ) ;
2014-06-09 03:40:14 +02:00
button - > setUserData ( skills [ i ] . first ) ;
2012-10-17 18:03:02 +02:00
button - > eventMouseButtonClick + = MyGUI : : newDelegate ( this , & TrainingWindow : : onTrainingSelected ) ;
2015-01-10 03:01:01 +01:00
button - > setCaptionWithReplacing ( " #{ " + ESM : : Skill : : sSkillNameIds [ skills [ i ] . first ] + " } - " + MyGUI : : utility : : toString ( price ) ) ;
2012-10-17 18:03:02 +02:00
button - > setSize ( button - > getTextSize ( ) . width + 12 , button - > getSize ( ) . height ) ;
2014-06-09 03:40:14 +02:00
ToolTips : : createSkillToolTip ( button , skills [ i ] . first ) ;
2012-10-17 18:03:02 +02:00
}
center ( ) ;
}
void TrainingWindow : : onReferenceUnavailable ( )
{
2013-04-10 00:32:05 -04:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeGuiMode ( GM_Training ) ;
2012-10-17 18:03:02 +02:00
}
void TrainingWindow : : onCancelButtonClicked ( MyGUI : : Widget * sender )
{
2017-09-23 12:18:39 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeGuiMode ( GM_Training ) ;
2012-10-17 18:03:02 +02:00
}
void TrainingWindow : : onTrainingSelected ( MyGUI : : Widget * sender )
{
int skillId = * sender - > getUserData < int > ( ) ;
2014-01-08 18:39:44 +01:00
MWWorld : : Ptr player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2014-05-22 20:37:22 +02:00
MWMechanics : : NpcStats & pcStats = player . getClass ( ) . getNpcStats ( player ) ;
2012-10-17 18:03:02 +02:00
2012-11-06 11:29:18 +04:00
const MWWorld : : ESMStore & store =
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) ;
2018-08-29 18:38:12 +03:00
int price = pcStats . getSkill ( skillId ) . getBase ( ) * store . get < ESM : : GameSetting > ( ) . find ( " iTrainingMod " ) - > mValue . getInteger ( ) ;
2012-11-09 14:42:09 +01:00
price = MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > getBarterOffer ( mPtr , price , true ) ;
2012-10-17 18:03:02 +02:00
2014-10-17 18:58:20 +02:00
if ( price > player . getClass ( ) . getContainerStore ( player ) . count ( MWWorld : : ContainerStore : : sGoldId ) )
return ;
2020-07-06 20:30:14 +02:00
if ( getSkillForTraining ( mPtr . getClass ( ) . getNpcStats ( mPtr ) , skillId ) < = pcStats . getSkill ( skillId ) . getBase ( ) )
2012-10-17 18:48:29 +02:00
{
2013-04-10 00:32:05 -04:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > messageBox ( " #{sServiceTrainingWords} " ) ;
2012-10-17 18:48:29 +02:00
return ;
}
2014-01-10 20:53:53 +01:00
// You can not train a skill above its governing attribute
const ESM : : Skill * skill = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Skill > ( ) . find ( skillId ) ;
if ( pcStats . getSkill ( skillId ) . getBase ( ) > = pcStats . getAttribute ( skill - > mData . mAttribute ) . getBase ( ) )
{
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > messageBox ( " #{sNotifyMessage17} " ) ;
return ;
}
2012-10-17 18:03:02 +02:00
// increase skill
MWWorld : : LiveCellRef < ESM : : NPC > * playerRef = player . get < ESM : : NPC > ( ) ;
2012-11-06 11:29:18 +04:00
const ESM : : Class * class_ =
store . get < ESM : : Class > ( ) . find ( playerRef - > mBase - > mClass ) ;
2012-10-17 18:03:02 +02:00
pcStats . increaseSkill ( skillId , * class_ , true ) ;
// remove gold
2014-01-08 23:37:46 +01:00
player . getClass ( ) . getContainerStore ( player ) . remove ( MWWorld : : ContainerStore : : sGoldId , price , player ) ;
2012-10-17 18:03:02 +02:00
2014-07-28 00:55:57 +02:00
// add gold to NPC trading gold pool
2018-10-08 17:06:30 +03:00
MWMechanics : : NpcStats & npcStats = mPtr . getClass ( ) . getNpcStats ( mPtr ) ;
2014-07-28 00:55:57 +02:00
npcStats . setGoldPool ( npcStats . getGoldPool ( ) + price ) ;
2012-10-17 18:03:02 +02:00
// advance time
2019-01-25 20:04:35 +04:00
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > rest ( 2 , false ) ;
2016-07-06 00:20:23 +02:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > advanceTime ( 2 ) ;
2012-10-17 18:03:02 +02:00
2017-09-24 12:58:14 +02:00
setVisible ( false ) ;
2015-02-07 04:05:28 +01:00
mProgressBar . setVisible ( true ) ;
mProgressBar . setProgress ( 0 , 2 ) ;
mTimeAdvancer . run ( 2 ) ;
2014-08-01 16:25:41 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenOut ( 0.25 ) ;
2017-09-24 19:15:39 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.25 , false , 0.25 ) ;
2012-10-17 18:03:02 +02:00
}
2015-02-07 04:05:28 +01:00
void TrainingWindow : : onTrainingProgressChanged ( int cur , int total )
{
mProgressBar . setProgress ( cur , total ) ;
}
void TrainingWindow : : onTrainingFinished ( )
{
mProgressBar . setVisible ( false ) ;
2017-09-24 12:58:14 +02:00
// go back to game mode
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeGuiMode ( GM_Training ) ;
2017-09-26 23:27:53 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > exitCurrentGuiMode ( ) ;
2015-02-07 04:05:28 +01:00
}
2020-07-07 09:50:02 +02:00
float TrainingWindow : : getSkillForTraining ( const MWMechanics : : NpcStats & stats , int skillId ) const
{
if ( mTrainingSkillBasedOnBaseSkill )
return stats . getSkill ( skillId ) . getBase ( ) ;
return stats . getSkill ( skillId ) . getModified ( ) ;
}
2012-10-17 18:03:02 +02:00
void TrainingWindow : : onFrame ( float dt )
{
2017-09-23 22:00:15 +02:00
checkReferenceAvailable ( ) ;
2015-02-07 04:05:28 +01:00
mTimeAdvancer . onFrame ( dt ) ;
2012-10-17 18:03:02 +02:00
}
2017-10-08 20:38:20 +00:00
bool TrainingWindow : : exit ( )
{
return ! mTimeAdvancer . isRunning ( ) ;
}
2012-10-17 18:03:02 +02:00
}