diff --git a/apps/openmw-mp/Script/Functions/Mechanics.cpp b/apps/openmw-mp/Script/Functions/Mechanics.cpp index b1a3ce413..d4ddcef87 100644 --- a/apps/openmw-mp/Script/Functions/Mechanics.cpp +++ b/apps/openmw-mp/Script/Functions/Mechanics.cpp @@ -68,6 +68,14 @@ double MechanicsFunctions::GetMarkRotZ(unsigned short pid) noexcept return player->markPosition.rot[2]; } +const char *MechanicsFunctions::GetSelectedSpellId(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->selectedSpellId.c_str(); +} + double MechanicsFunctions::GetScale(unsigned short pid) noexcept { Player *player; @@ -111,6 +119,14 @@ void MechanicsFunctions::SetMarkRot(unsigned short pid, double x, double z) noex player->markPosition.rot[2] = z; } +void MechanicsFunctions::SetSelectedSpellId(unsigned short pid, const char *spellId) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->selectedSpellId = spellId; +} + void MechanicsFunctions::SetScale(unsigned short pid, double scale) noexcept { Player *player; @@ -138,6 +154,17 @@ void MechanicsFunctions::SendMarkLocation(unsigned short pid) mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MISCELLANEOUS)->Send(false); } +void MechanicsFunctions::SendSelectedSpell(unsigned short pid) +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->miscellaneousChangeType = mwmp::MISCELLANEOUS_CHANGE_TYPE::SELECTED_SPELL; + + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MISCELLANEOUS)->setPlayer(player); + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MISCELLANEOUS)->Send(false); +} + void MechanicsFunctions::SendShapeshift(unsigned short pid) { Player *player; diff --git a/apps/openmw-mp/Script/Functions/Mechanics.hpp b/apps/openmw-mp/Script/Functions/Mechanics.hpp index 7db879f0f..f0e3e13d3 100644 --- a/apps/openmw-mp/Script/Functions/Mechanics.hpp +++ b/apps/openmw-mp/Script/Functions/Mechanics.hpp @@ -12,6 +12,7 @@ {"GetMarkPosZ", MechanicsFunctions::GetMarkPosZ},\ {"GetMarkRotX", MechanicsFunctions::GetMarkRotX},\ {"GetMarkRotZ", MechanicsFunctions::GetMarkRotZ},\ + {"GetSelectedSpellId", MechanicsFunctions::GetSelectedSpellId},\ \ {"GetScale", MechanicsFunctions::GetScale},\ {"IsWerewolf", MechanicsFunctions::IsWerewolf},\ @@ -19,11 +20,13 @@ {"SetMarkCell", MechanicsFunctions::SetMarkCell},\ {"SetMarkPos", MechanicsFunctions::SetMarkPos},\ {"SetMarkRot", MechanicsFunctions::SetMarkRot},\ + {"SetSelectedSpellId", MechanicsFunctions::SetSelectedSpellId},\ \ {"SetScale", MechanicsFunctions::SetScale},\ {"SetWerewolfState", MechanicsFunctions::SetWerewolfState},\ \ {"SendMarkLocation", MechanicsFunctions::SendMarkLocation},\ + {"SendSelectedSpell", MechanicsFunctions::SendSelectedSpell},\ {"SendShapeshift", MechanicsFunctions::SendShapeshift},\ \ {"Jail", MechanicsFunctions::Jail},\ @@ -89,6 +92,14 @@ public: */ static double GetMarkRotZ(unsigned short pid) noexcept; + /** + * \brief Get the ID of a player's selected spell. + * + * \param pid The player ID. + * \return The spell ID. + */ + static const char *GetSelectedSpellId(unsigned short pid) noexcept; + /** * \brief Get the scale of a player. * @@ -149,6 +160,18 @@ public: */ static void SetMarkRot(unsigned short pid, double x, double z) noexcept; + /** + * \brief Set the ID of a player's selected spell. + * + * This changes the spell ID recorded for that player in the server memory, but does not by itself + * send a packet. + * + * \param pid The player ID. + * \param spellId The spell ID. + * \return void + */ + static void SetSelectedSpellId(unsigned short pid, const char *spellId) noexcept; + /** * \brief Set the scale of a player. * @@ -181,6 +204,14 @@ public: */ static void SendMarkLocation(unsigned short pid); + /** + * \brief Send a PlayerMiscellaneous packet with a selected spell ID to a player. + * + * \param pid The player ID. + * \return void + */ + static void SendSelectedSpell(unsigned short pid); + /** * \brief Send a PlayerShapeshift packet about a player. * diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index aa2726799..61b064c38 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -232,7 +232,8 @@ namespace MWGui /* Start of tes3mp addition - Send a PLAYER_QUICKKEYS packet whenever a key is assigned to an item + Send a PlayerQuickKeys packet whenever a key is assigned to an item + by a player, not by a packet received from the server */ if (!mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys) mwmp::Main::get().getLocalPlayer()->sendQuickKey(mSelectedIndex, Type_Item, item.getCellRef().getRefId()); @@ -407,6 +408,16 @@ namespace MWGui store.setSelectedEnchantItem(store.end()); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); + + /* + Start of tes3mp addition + + Send a PlayerMiscellaneous packet with the player's new selected spell + */ + mwmp::Main::get().getLocalPlayer()->sendSelectedSpell(spellId); + /* + End of tes3mp addition + */ } else if (type == Type_Item) { diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 1f9e65624..bc35929a7 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -186,6 +186,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); + + /* + Start of tes3mp addition + + Send a PlayerMiscellaneous packet with the player's new selected spell + */ + mwmp::Main::get().getLocalPlayer()->sendSelectedSpell(spellId); + /* + End of tes3mp addition + */ } void SpellWindow::onDeleteSpellAccept() diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 4eb824bde..4265b5c57 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp" +#include "../mwmechanics/spellcasting.hpp" #include "../mwscript/scriptmanagerimp.hpp" @@ -1280,6 +1281,20 @@ void LocalPlayer::setMarkLocation() MWBase::Environment::get().getWorld()->getPlayer().markPosition(ptrCellStore, markPosition); } +void LocalPlayer::setSelectedSpell() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + + MWMechanics::CreatureStats& stats = ptrPlayer.getClass().getCreatureStats(ptrPlayer); + MWMechanics::Spells& spells = stats.getSpells(); + + if (!spells.hasSpell(selectedSpellId)) + return; + + MWBase::Environment::get().getWindowManager()->setSelectedSpell(selectedSpellId, + int(MWMechanics::getSpellSuccessChance(selectedSpellId, ptrPlayer))); +} + void LocalPlayer::sendClass() { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1586,6 +1601,15 @@ void LocalPlayer::sendMarkLocation(const ESM::Cell& newMarkCell, const ESM::Posi getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->Send(); } +void LocalPlayer::sendSelectedSpell(const std::string& newSelectedSpellId) +{ + miscellaneousChangeType = mwmp::MISCELLANEOUS_CHANGE_TYPE::SELECTED_SPELL; + selectedSpellId = newSelectedSpellId; + + getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->Send(); +} + void LocalPlayer::clearCellStates() { cellStateChanges.cellStates.clear(); diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 5efe3ffb5..bd475977d 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -71,6 +71,7 @@ namespace mwmp void setMapExplored(); void setShapeshift(); void setMarkLocation(); + void setSelectedSpell(); void sendClass(); void sendInventory(); @@ -92,6 +93,7 @@ namespace mwmp void sendScale(float newScale); void sendWerewolfState(bool isWerewolf); void sendMarkLocation(const ESM::Cell& newMarkCell, const ESM::Position& newMarkPosition); + void sendSelectedSpell(const std::string& newSelectedSpellId); void clearCellStates(); void clearCurrentContainer(); diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp index 4dcc8a5be..f23d1af13 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp @@ -26,6 +26,8 @@ namespace mwmp if (player->miscellaneousChangeType == mwmp::MISCELLANEOUS_CHANGE_TYPE::MARK_LOCATION) localPlayer.setMarkLocation(); + else if (player->miscellaneousChangeType == mwmp::MISCELLANEOUS_CHANGE_TYPE::SELECTED_SPELL) + localPlayer.setSelectedSpell(); } } }; diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 2865a22f6..1a024c6a9 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -303,10 +303,11 @@ namespace mwmp ESM::Cell markCell; ESM::Position markPosition; + std::string selectedSpellId; - bool diedSinceArrestAttempt; bool isReceivingQuickKeys; bool isPlayingAnimation; + bool diedSinceArrestAttempt; }; } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp b/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp index cffb6a446..8aca6b52f 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp @@ -23,4 +23,6 @@ void PacketPlayerMiscellaneous::Packet(RakNet::BitStream *bs, bool send) RW(player->markPosition.rot[0], send); RW(player->markPosition.rot[2], send); } + else if (player->miscellaneousChangeType == mwmp::MISCELLANEOUS_CHANGE_TYPE::SELECTED_SPELL) + RW(player->selectedSpellId, send, 1); }