1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 23:49:55 +00:00
openmw-tes3mp/apps/openmw/mwgui/trainingwindow.cpp
David Cernat 03832f933b [Client] Send only individual items in PlayerInventory packets
For a long time, whenever a PlayerInventory packet was sent, it contained all the items in the player's inventory, because that's how Koncord originally implemented it and I always had too many other priorities to go back and rework it.

From now on, clients only send PlayerInventory packet with the one item added or removed, with the single exception being trading with merchants, where the entire inventory is still sent for the time being.
2018-08-21 10:10:06 +03:00

242 lines
8 KiB
C++

#include "trainingwindow.hpp"
#include <MyGUI_Gui.h>
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
#include "../mwmp/Main.hpp"
#include "../mwmp/LocalPlayer.hpp"
/*
End of tes3mp addition
*/
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "tooltips.hpp"
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;
}
}
namespace MWGui
{
TrainingWindow::TrainingWindow()
: WindowBase("openmw_trainingwindow.layout")
, mTimeAdvancer(0.05f)
{
getWidget(mTrainingOptions, "TrainingOptions");
getWidget(mCancelButton, "CancelButton");
getWidget(mPlayerGold, "PlayerGold");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked);
mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged);
mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished);
}
void TrainingWindow::onOpen()
{
if (mTimeAdvancer.isRunning())
{
mProgressBar.setVisible(true);
setVisible(false);
}
else
mProgressBar.setVisible(false);
center();
}
void TrainingWindow::setPtr (const MWWorld::Ptr& actor)
{
mPtr = actor;
MWWorld::Ptr player = MWMechanics::getPlayer();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor);
// NPC can train you in his best 3 skills
std::vector< std::pair<int, int> > skills;
for (int i=0; i<ESM::Skill::Length; ++i)
{
int value = npcStats.getSkill (i).getModified ();
skills.push_back(std::make_pair(i, value));
}
std::sort(skills.begin(), skills.end(), sortSkills);
MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator ();
MyGUI::Gui::getInstance ().destroyWidgets (widgets);
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
for (int i=0; i<3; ++i)
{
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer
(mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true);
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip
MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default);
button->setUserData(skills[i].first);
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[skills[i].first] + "} - " + MyGUI::utility::toString(price));
button->setSize(button->getTextSize ().width+12, button->getSize().height);
ToolTips::createSkillToolTip (button, skills[i].first);
}
center();
}
void TrainingWindow::onReferenceUnavailable ()
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training);
}
void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender)
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training);
}
void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender)
{
int skillId = *sender->getUserData<int>();
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
const MWWorld::ESMStore &store =
MWBase::Environment::get().getWorld()->getStore();
int price = pcStats.getSkill (skillId).getBase() * store.get<ESM::GameSetting>().find("iTrainingMod")->getInt ();
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
return;
MWMechanics::NpcStats& npcStats = mPtr.getClass().getNpcStats (mPtr);
if (npcStats.getSkill (skillId).getModified () <= pcStats.getSkill (skillId).getBase ())
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sServiceTrainingWords}");
return;
}
// 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;
}
// increase skill
MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>();
const ESM::Class *class_ =
store.get<ESM::Class>().find(playerRef->mBase->mClass);
pcStats.increaseSkill (skillId, *class_, true);
// remove gold
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
/*
Start of tes3mp addition
Send an ID_PLAYER_INVENTORY packet with the gold lost
*/
mwmp::Main::get().getLocalPlayer()->sendItemChange(MWWorld::ContainerStore::sGoldId, price, mwmp::InventoryChanges::REMOVE);
/*
End of tes3mp addition
*/
// add gold to NPC trading gold pool
npcStats.setGoldPool(npcStats.getGoldPool() + price);
// advance time
MWBase::Environment::get().getMechanicsManager()->rest(false);
MWBase::Environment::get().getMechanicsManager()->rest(false);
/*
Start of tes3mp change (major)
Multiplayer requires that time not get advanced here
*/
//MWBase::Environment::get().getWorld ()->advanceTime (2);
/*
End of tes3mp change (major)
*/
setVisible(false);
mProgressBar.setVisible(true);
mProgressBar.setProgress(0, 2);
mTimeAdvancer.run(2);
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25);
MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25, false, 0.25);
}
void TrainingWindow::onTrainingProgressChanged(int cur, int total)
{
mProgressBar.setProgress(cur, total);
}
void TrainingWindow::onTrainingFinished()
{
mProgressBar.setVisible(false);
// go back to game mode
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training);
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
}
void TrainingWindow::onFrame(float dt)
{
checkReferenceAvailable();
mTimeAdvancer.onFrame(dt);
}
bool TrainingWindow::exit()
{
return !mTimeAdvancer.isRunning();
}
}