2012-10-17 16:03:02 +00:00
# include "trainingwindow.hpp"
2015-01-10 01:50:43 +00:00
# include <MyGUI_Gui.h>
2020-05-20 05:09:25 +00:00
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
# include "../mwmp/Main.hpp"
# include "../mwmp/Networking.hpp"
# include "../mwmp/ObjectList.hpp"
/*
End of tes3mp addition
*/
2012-10-17 16:03:02 +00:00
# include "../mwbase/windowmanager.hpp"
# include "../mwbase/environment.hpp"
# include "../mwbase/world.hpp"
2012-11-05 18:53:55 +00:00
# include "../mwbase/mechanicsmanager.hpp"
2012-10-17 16:03:02 +00:00
2013-05-11 16:38:27 +00:00
# include "../mwworld/class.hpp"
2013-11-21 03:27:53 +00:00
# include "../mwworld/containerstore.hpp"
2014-12-19 10:26:54 +00:00
# include "../mwworld/esmstore.hpp"
2012-10-17 16:03:02 +00:00
# include "../mwmechanics/npcstats.hpp"
2015-08-21 09:12:39 +00:00
# include "../mwmechanics/actorutil.hpp"
2012-10-17 16:03:02 +00:00
2020-07-06 18:28:08 +00:00
# include <components/settings/settings.hpp>
2012-10-17 16:03:02 +00:00
# include "tooltips.hpp"
2014-06-09 01:40:14 +00: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 16:03:02 +00:00
namespace MWGui
{
2013-04-10 18:46:21 +00:00
TrainingWindow : : TrainingWindow ( )
: WindowBase ( " openmw_trainingwindow.layout " )
2015-03-08 00:07:29 +00:00
, mTimeAdvancer ( 0.05f )
2020-07-07 07:50:02 +00:00
, mTrainingSkillBasedOnBaseSkill ( Settings : : Manager : : getBool ( " trainers training skills based on base skill " , " Game " ) )
2012-10-17 16:03:02 +00:00
{
getWidget ( mTrainingOptions , " TrainingOptions " ) ;
getWidget ( mCancelButton , " CancelButton " ) ;
getWidget ( mPlayerGold , " PlayerGold " ) ;
mCancelButton - > eventMouseButtonClick + = MyGUI : : newDelegate ( this , & TrainingWindow : : onCancelButtonClicked ) ;
2015-02-07 03:05:28 +00:00
mTimeAdvancer . eventProgressChanged + = MyGUI : : newDelegate ( this , & TrainingWindow : : onTrainingProgressChanged ) ;
mTimeAdvancer . eventFinished + = MyGUI : : newDelegate ( this , & TrainingWindow : : onTrainingFinished ) ;
2012-10-17 16:03:02 +00:00
}
2017-09-22 15:10:53 +00:00
void TrainingWindow : : onOpen ( )
2012-10-17 16:03:02 +00:00
{
2017-09-24 10:58:14 +00:00
if ( mTimeAdvancer . isRunning ( ) )
{
mProgressBar . setVisible ( true ) ;
setVisible ( false ) ;
}
else
mProgressBar . setVisible ( false ) ;
2012-10-17 16:03:02 +00:00
center ( ) ;
2014-05-27 03:13:37 +00:00
}
2017-09-22 19:26:41 +00:00
void TrainingWindow : : setPtr ( const MWWorld : : Ptr & actor )
2012-10-17 16:03:02 +00:00
{
mPtr = actor ;
2015-08-21 09:12:39 +00:00
MWWorld : : Ptr player = MWMechanics : : getPlayer ( ) ;
2014-01-08 22:37:46 +00:00
int playerGold = player . getClass ( ) . getContainerStore ( player ) . count ( MWWorld : : ContainerStore : : sGoldId ) ;
2015-01-10 02:01:01 +00:00
mPlayerGold - > setCaptionWithReplacing ( " #{sGold}: " + MyGUI : : utility : : toString ( playerGold ) ) ;
2012-10-17 16:03:02 +00:00
// NPC can train you in his best 3 skills
2018-12-23 11:18:33 +00:00
std : : vector < std : : pair < int , float > > skills ;
2012-10-17 16:03:02 +00:00
2020-07-06 18:28:08 +00:00
MWMechanics : : NpcStats const & actorStats ( actor . getClass ( ) . getNpcStats ( actor ) ) ;
2012-10-17 16:03:02 +00:00
for ( int i = 0 ; i < ESM : : Skill : : Length ; + + i )
{
2020-07-06 18:28:08 +00:00
float value = getSkillForTraining ( actorStats , i ) ;
2012-10-17 16:03:02 +00:00
2020-10-17 08:26:35 +00:00
skills . emplace_back ( i , value ) ;
2012-10-17 16:03:02 +00:00
}
2014-06-09 01:40:14 +00:00
std : : sort ( skills . begin ( ) , skills . end ( ) , sortSkills ) ;
2012-10-17 16:03:02 +00:00
MyGUI : : EnumeratorWidgetPtr widgets = mTrainingOptions - > getEnumerator ( ) ;
MyGUI : : Gui : : getInstance ( ) . destroyWidgets ( widgets ) ;
2014-05-22 18:37:22 +00:00
MWMechanics : : NpcStats & pcStats = player . getClass ( ) . getNpcStats ( player ) ;
2012-10-17 16:03:02 +00:00
2012-11-06 09:43:48 +00:00
const MWWorld : : Store < ESM : : GameSetting > & gmst =
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : GameSetting > ( ) ;
2012-10-17 16:03:02 +00:00
for ( int i = 0 ; i < 3 ; + + i )
{
2020-09-08 12:55:12 +00: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 16:03:02 +00:00
2014-10-17 16:58:20 +00:00
MyGUI : : Button * button = mTrainingOptions - > createWidget < MyGUI : : Button > ( price < = playerGold ? " SandTextButton " : " SandTextButtonDisabled " , // can't use setEnabled since that removes tooltip
2012-10-17 16:03:02 +00:00
MyGUI : : IntCoord ( 5 , 5 + i * 18 , mTrainingOptions - > getWidth ( ) - 10 , 18 ) , MyGUI : : Align : : Default ) ;
2014-06-09 01:40:14 +00:00
button - > setUserData ( skills [ i ] . first ) ;
2012-10-17 16:03:02 +00:00
button - > eventMouseButtonClick + = MyGUI : : newDelegate ( this , & TrainingWindow : : onTrainingSelected ) ;
2015-01-10 02:01:01 +00:00
button - > setCaptionWithReplacing ( " #{ " + ESM : : Skill : : sSkillNameIds [ skills [ i ] . first ] + " } - " + MyGUI : : utility : : toString ( price ) ) ;
2012-10-17 16:03:02 +00:00
button - > setSize ( button - > getTextSize ( ) . width + 12 , button - > getSize ( ) . height ) ;
2014-06-09 01:40:14 +00:00
ToolTips : : createSkillToolTip ( button , skills [ i ] . first ) ;
2012-10-17 16:03:02 +00:00
}
center ( ) ;
}
void TrainingWindow : : onReferenceUnavailable ( )
{
2013-04-10 04:32:05 +00:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeGuiMode ( GM_Training ) ;
2012-10-17 16:03:02 +00:00
}
void TrainingWindow : : onCancelButtonClicked ( MyGUI : : Widget * sender )
{
2017-09-23 10:18:39 +00:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeGuiMode ( GM_Training ) ;
2012-10-17 16:03:02 +00:00
}
void TrainingWindow : : onTrainingSelected ( MyGUI : : Widget * sender )
{
int skillId = * sender - > getUserData < int > ( ) ;
2014-01-08 17:39:44 +00:00
MWWorld : : Ptr player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2014-05-22 18:37:22 +00:00
MWMechanics : : NpcStats & pcStats = player . getClass ( ) . getNpcStats ( player ) ;
2012-10-17 16:03:02 +00:00
2012-11-06 07:29:18 +00:00
const MWWorld : : ESMStore & store =
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) ;
2018-08-29 15:38:12 +00:00
int price = pcStats . getSkill ( skillId ) . getBase ( ) * store . get < ESM : : GameSetting > ( ) . find ( " iTrainingMod " ) - > mValue . getInteger ( ) ;
2012-11-09 13:42:09 +00:00
price = MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > getBarterOffer ( mPtr , price , true ) ;
2012-10-17 16:03:02 +00:00
2014-10-17 16:58:20 +00:00
if ( price > player . getClass ( ) . getContainerStore ( player ) . count ( MWWorld : : ContainerStore : : sGoldId ) )
return ;
2020-07-06 18:30:14 +00:00
if ( getSkillForTraining ( mPtr . getClass ( ) . getNpcStats ( mPtr ) , skillId ) < = pcStats . getSkill ( skillId ) . getBase ( ) )
2012-10-17 16:48:29 +00:00
{
2013-04-10 04:32:05 +00:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > messageBox ( " #{sServiceTrainingWords} " ) ;
2012-10-17 16:48:29 +00:00
return ;
}
2014-01-10 19:53:53 +00: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 16:03:02 +00:00
// increase skill
MWWorld : : LiveCellRef < ESM : : NPC > * playerRef = player . get < ESM : : NPC > ( ) ;
2012-11-06 07:29:18 +00:00
const ESM : : Class * class_ =
store . get < ESM : : Class > ( ) . find ( playerRef - > mBase - > mClass ) ;
2012-10-17 16:03:02 +00:00
pcStats . increaseSkill ( skillId , * class_ , true ) ;
// remove gold
2014-01-08 22:37:46 +00:00
player . getClass ( ) . getContainerStore ( player ) . remove ( MWWorld : : ContainerStore : : sGoldId , price , player ) ;
2012-10-17 16:03:02 +00:00
2014-07-27 22:55:57 +00:00
// add gold to NPC trading gold pool
2018-10-08 14:06:30 +00:00
MWMechanics : : NpcStats & npcStats = mPtr . getClass ( ) . getNpcStats ( mPtr ) ;
2020-05-20 05:09:25 +00:00
/*
Start of tes3mp change ( major )
Don ' t unilaterally change the merchant ' s gold pool on our client and instead let the server do it
*/
//npcStats.setGoldPool(npcStats.getGoldPool() + price);
mwmp : : ObjectList * objectList = mwmp : : Main : : get ( ) . getNetworking ( ) - > getObjectList ( ) ;
objectList - > reset ( ) ;
objectList - > packetOrigin = mwmp : : CLIENT_GAMEPLAY ;
objectList - > addObjectMiscellaneous ( mPtr , npcStats . getGoldPool ( ) + price , npcStats . getLastRestockTime ( ) . getHour ( ) ,
npcStats . getLastRestockTime ( ) . getDay ( ) ) ;
objectList - > sendObjectMiscellaneous ( ) ;
/*
End of tes3mp change ( major )
*/
2014-07-27 22:55:57 +00:00
2012-10-17 16:03:02 +00:00
// advance time
2019-01-25 16:04:35 +00:00
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > rest ( 2 , false ) ;
2018-05-23 02:49:51 +00:00
/*
Start of tes3mp change ( major )
Multiplayer requires that time not get advanced here
*/
//MWBase::Environment::get().getWorld ()->advanceTime (2);
/*
End of tes3mp change ( major )
*/
2012-10-17 16:03:02 +00:00
2017-09-24 10:58:14 +00:00
setVisible ( false ) ;
2015-02-07 03:05:28 +00:00
mProgressBar . setVisible ( true ) ;
mProgressBar . setProgress ( 0 , 2 ) ;
mTimeAdvancer . run ( 2 ) ;
2014-08-01 14:25:41 +00:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenOut ( 0.25 ) ;
2017-09-24 17:15:39 +00:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.25 , false , 0.25 ) ;
2012-10-17 16:03:02 +00:00
}
2015-02-07 03:05:28 +00:00
void TrainingWindow : : onTrainingProgressChanged ( int cur , int total )
{
mProgressBar . setProgress ( cur , total ) ;
}
void TrainingWindow : : onTrainingFinished ( )
{
mProgressBar . setVisible ( false ) ;
2017-09-24 10:58:14 +00:00
// go back to game mode
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeGuiMode ( GM_Training ) ;
2017-09-26 21:27:53 +00:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > exitCurrentGuiMode ( ) ;
2015-02-07 03:05:28 +00:00
}
2020-07-07 07:50:02 +00: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 16:03:02 +00:00
void TrainingWindow : : onFrame ( float dt )
{
2017-09-23 20:00:15 +00:00
checkReferenceAvailable ( ) ;
2015-02-07 03:05:28 +00:00
mTimeAdvancer . onFrame ( dt ) ;
2012-10-17 16:03:02 +00:00
}
2015-02-07 03:05:28 +00:00
2017-10-08 20:38:20 +00:00
bool TrainingWindow : : exit ( )
{
return ! mTimeAdvancer . isRunning ( ) ;
2012-10-17 16:03:02 +00:00
}
2017-10-08 20:38:20 +00:00
2012-10-17 16:03:02 +00:00
}