From c6874509b6f6524ccc1d3e62aa86810ec9dd582f Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 24 Jan 2018 02:25:44 +0200 Subject: [PATCH 1/9] [Client] Ignore invalid faction IDs from packets --- apps/openmw/mwmp/LocalPlayer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index b19189429..b2a8ce65f 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -1091,8 +1091,18 @@ void LocalPlayer::setFactions() MWWorld::Ptr ptrPlayer = getPlayerPtr(); MWMechanics::NpcStats &ptrNpcStats = ptrPlayer.getClass().getNpcStats(ptrPlayer); + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_FACTION from server\n- action: %i", factionChanges.action); + for (const auto &faction : factionChanges.factions) { + const ESM::Faction *esmFaction = MWBase::Environment::get().getWorld()->getStore().get().search(faction.factionId); + + if (!esmFaction) + { + LOG_APPEND(Log::LOG_INFO, "- Ignored invalid faction %s", faction.factionId.c_str()); + continue; + } + // If the player isn't in this faction, make them join it if (!ptrNpcStats.isInFaction(faction.factionId)) ptrNpcStats.joinFaction(faction.factionId); From ace825b99cd9edc648e82ccc1e3db790e2d7da70 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 24 Jan 2018 02:47:56 +0200 Subject: [PATCH 2/9] [Client] Ignore invalid player class IDs from packets Additionally, clean up variables names in related code. --- apps/openmw/mwmp/LocalPlayer.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index b2a8ce65f..7db9b2338 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -933,6 +933,8 @@ void LocalPlayer::setCell() void LocalPlayer::setClass() { + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_CLASS from server"); + if (charClass.mId.empty()) // custom class { charClass.mData.mIsPlayable = 0x1; @@ -941,12 +943,15 @@ void LocalPlayer::setClass() } else { - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(charClass.mId); - - const ESM::Class *existingCharClass = MWBase::Environment::get().getWorld()->getStore().get().find(charClass.mId); + const ESM::Class *existingCharClass = MWBase::Environment::get().getWorld()->getStore().get().search(charClass.mId); if (existingCharClass) + { + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(charClass.mId); MWBase::Environment::get().getWindowManager()->setPlayerClass(charClass); + } + else + LOG_APPEND(Log::LOG_INFO, "- Ignored invalid default class %s", charClass.mId.c_str()); } } @@ -1175,18 +1180,18 @@ void LocalPlayer::setShapeshift() void LocalPlayer::sendClass() { MWBase::World *world = MWBase::Environment::get().getWorld(); - const ESM::NPC *cpl = world->getPlayerPtr().get()->mBase; - const ESM::Class *cls = world->getStore().get().find(cpl->mClass); + const ESM::NPC *npcBase = world->getPlayerPtr().get()->mBase; + const ESM::Class *esmClass = world->getStore().get().find(npcBase->mClass); - if (cpl->mClass.find("$dynamic") != string::npos) // custom class + if (npcBase->mClass.find("$dynamic") != string::npos) // custom class { charClass.mId = ""; - charClass.mName = cls->mName; - charClass.mDescription = cls->mDescription; - charClass.mData = cls->mData; + charClass.mName = esmClass->mName; + charClass.mDescription = esmClass->mDescription; + charClass.mData = esmClass->mData; } else - charClass.mId = cls->mId; + charClass.mId = esmClass->mId; getNetworking()->getPlayerPacket(ID_PLAYER_CHARCLASS)->setPlayer(this); getNetworking()->getPlayerPacket(ID_PLAYER_CHARCLASS)->Send(); From aa392ebf20ca6caab76cd250d4aa646593cf2097 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 26 Jan 2018 00:45:39 +0200 Subject: [PATCH 3/9] [Client] Unequip items if necessary when attr/skill modifier is set to 0 --- apps/openmw/mwmp/GUIController.cpp | 9 +++++ apps/openmw/mwmp/GUIController.hpp | 3 ++ apps/openmw/mwmp/LocalPlayer.cpp | 54 +++++++++++++++++++--------- apps/openmw/mwmp/MechanicsHelper.cpp | 35 ++++++++++++++++++ apps/openmw/mwmp/MechanicsHelper.hpp | 2 ++ 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmp/GUIController.cpp b/apps/openmw/mwmp/GUIController.cpp index c601221ec..a1ca5f999 100644 --- a/apps/openmw/mwmp/GUIController.cpp +++ b/apps/openmw/mwmp/GUIController.cpp @@ -59,6 +59,15 @@ void mwmp::GUIController::cleanUp() mChat = nullptr; } +void mwmp::GUIController::refreshGuiMode(MWGui::GuiMode guiMode) +{ + if (MWBase::Environment::get().getWindowManager()->containsMode(guiMode)) + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(guiMode); + MWBase::Environment::get().getWindowManager()->pushGuiMode(guiMode); + } +} + void mwmp::GUIController::setupChat(const Settings::Manager &mgr) { assert(mChat == nullptr); diff --git a/apps/openmw/mwmp/GUIController.hpp b/apps/openmw/mwmp/GUIController.hpp index db42d692f..7ed57bcf6 100644 --- a/apps/openmw/mwmp/GUIController.hpp +++ b/apps/openmw/mwmp/GUIController.hpp @@ -35,6 +35,9 @@ namespace mwmp GUIController(); ~GUIController(); void cleanUp(); + + void refreshGuiMode(MWGui::GuiMode guiMode); + void setupChat(const Settings::Manager &manager); void printChatMessage(std::string &msg); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 7db9b2338..02de21c5a 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -35,6 +35,7 @@ #include "Main.hpp" #include "Networking.hpp" #include "CellController.hpp" +#include "GUIController.hpp" #include "MechanicsHelper.hpp" using namespace mwmp; @@ -442,6 +443,7 @@ void LocalPlayer::updateEquipment(bool forceUpdate) { auto &item = equipedItems[slot]; MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) { if (!::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), equipedItems[slot].refId)) @@ -796,47 +798,67 @@ void LocalPlayer::setDynamicStats() void LocalPlayer::setAttributes() { - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr ptrPlayer = world->getPlayerPtr(); + MWWorld::Ptr ptrPlayer = getPlayerPtr(); MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer); MWMechanics::AttributeValue attributeValue; - for (int i = 0; i < 8; ++i) + for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex) { // If the server wants to clear our attribute's non-zero modifier, we need to remove // the spell effect causing it, to avoid an infinite loop where the effect keeps resetting // the modifier - if (creatureStats.mAttributes[i].mMod == 0 && ptrCreatureStats->getAttribute(i).getModifier() > 0) - ptrCreatureStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, i); + if (creatureStats.mAttributes[attributeIndex].mMod == 0 && ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0) + { + ptrCreatureStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, attributeIndex); + MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(ptrPlayer); + + // Is the modifier for this attribute still higher than 0? If so, unequip items that + // fortify the attribute + if (ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0) + { + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1); + mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory); + } + } - attributeValue.readState(creatureStats.mAttributes[i]); - ptrCreatureStats->setAttribute(i, attributeValue); + attributeValue.readState(creatureStats.mAttributes[attributeIndex]); + ptrCreatureStats->setAttribute(attributeIndex, attributeValue); } } void LocalPlayer::setSkills() { - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr ptrPlayer = world->getPlayerPtr(); + MWWorld::Ptr ptrPlayer = getPlayerPtr(); MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer); MWMechanics::SkillValue skillValue; - for (int i = 0; i < 27; ++i) + for (int skillIndex = 0; skillIndex < 27; ++skillIndex) { // If the server wants to clear our skill's non-zero modifier, we need to remove // the spell effect causing it, to avoid an infinite loop where the effect keeps resetting // the modifier - if (npcStats.mSkills[i].mMod == 0 && ptrNpcStats->getSkill(i).getModifier() > 0) - ptrNpcStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifySkill, i); + if (npcStats.mSkills[skillIndex].mMod == 0 && ptrNpcStats->getSkill(skillIndex).getModifier() > 0) + { + ptrNpcStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifySkill, skillIndex); + MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(ptrPlayer); - skillValue.readState(npcStats.mSkills[i]); - ptrNpcStats->setSkill(i, skillValue); + // Is the modifier for this skill still higher than 0? If so, unequip items that + // fortify the skill + if (ptrNpcStats->getSkill(skillIndex).getModifier() > 0) + { + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::MagicEffect::FortifySkill, -1, skillIndex); + mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory); + } + } + + skillValue.readState(npcStats.mSkills[skillIndex]); + ptrNpcStats->setSkill(skillIndex, skillValue); } - for (int i = 0; i < 8; ++i) - ptrNpcStats->setSkillIncrease(i, npcStats.mSkillIncrease[i]); + for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex) + ptrNpcStats->setSkillIncrease(attributeIndex, npcStats.mSkillIncrease[attributeIndex]); ptrNpcStats->setLevelProgress(npcStats.mLevelProgress); } diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index 9092eec9c..6b880dfd7 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -213,3 +213,38 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) LOG_APPEND(Log::LOG_VERBOSE, " - success: %d", attack.success); } } + +void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short effectId, short attributeId, short skillId) +{ + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::InventoryStore &ptrInventory = ptr.getClass().getInventoryStore(ptr); + + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++) + { + if (ptrInventory.getSlot(slot) != ptrInventory.end()) + { + MWWorld::ConstContainerStoreIterator itemIterator = ptrInventory.getSlot(slot); + std::string enchantmentName = itemIterator->getClass().getEnchantment(*itemIterator); + + if (!enchantmentName.empty()) + { + const ESM::Enchantment* enchantment = world->getStore().get().find(enchantmentName); + + for (const auto &effect : enchantment->mEffects.mList) + { + if (effect.mEffectID == effectId) + { + if (attributeId == -1 || effect.mAttribute == attributeId) + { + if (skillId == -1 || effect.mSkill == skillId) + { + ptrInventory.unequipSlot(slot, ptr); + break; + } + } + } + } + } + } + } +} diff --git a/apps/openmw/mwmp/MechanicsHelper.hpp b/apps/openmw/mwmp/MechanicsHelper.hpp index e4248241f..0c024cfa9 100644 --- a/apps/openmw/mwmp/MechanicsHelper.hpp +++ b/apps/openmw/mwmp/MechanicsHelper.hpp @@ -23,6 +23,8 @@ namespace MechanicsHelper bool getSpellSuccess(std::string spellId, const MWWorld::Ptr& caster); void processAttack(mwmp::Attack attack, const MWWorld::Ptr& attacker); + + void unequipItemsByEffect(const MWWorld::Ptr& ptr, short effectId, short attributeId = -1, short skillId = -1); } From c6a85ee8f9631be740c16be14da4a937a49b6283 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 26 Jan 2018 03:18:01 +0200 Subject: [PATCH 4/9] [Client] Add doesEffectListContainEffect() method to MechanicsHelper --- apps/openmw/mwmp/MechanicsHelper.cpp | 35 +++++++++++++++++----------- apps/openmw/mwmp/MechanicsHelper.hpp | 1 + 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index 6b880dfd7..a63d890f1 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -214,6 +214,25 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) } } +bool MechanicsHelper::doesEffectListContainEffect(const ESM::EffectList& effectList, short effectId, short attributeId, short skillId) +{ + for (const auto &effect : effectList.mList) + { + if (effect.mEffectID == effectId) + { + if (attributeId == -1 || effect.mAttribute == attributeId) + { + if (skillId == -1 || effect.mSkill == skillId) + { + return true; + } + } + } + } + + return false; +} + void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short effectId, short attributeId, short skillId) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -230,20 +249,8 @@ void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short effect { const ESM::Enchantment* enchantment = world->getStore().get().find(enchantmentName); - for (const auto &effect : enchantment->mEffects.mList) - { - if (effect.mEffectID == effectId) - { - if (attributeId == -1 || effect.mAttribute == attributeId) - { - if (skillId == -1 || effect.mSkill == skillId) - { - ptrInventory.unequipSlot(slot, ptr); - break; - } - } - } - } + if (doesEffectListContainEffect(enchantment->mEffects, effectId, attributeId, skillId)) + ptrInventory.unequipSlot(slot, ptr); } } } diff --git a/apps/openmw/mwmp/MechanicsHelper.hpp b/apps/openmw/mwmp/MechanicsHelper.hpp index 0c024cfa9..cf0eaa273 100644 --- a/apps/openmw/mwmp/MechanicsHelper.hpp +++ b/apps/openmw/mwmp/MechanicsHelper.hpp @@ -24,6 +24,7 @@ namespace MechanicsHelper void processAttack(mwmp::Attack attack, const MWWorld::Ptr& attacker); + bool doesEffectListContainEffect(const ESM::EffectList& effectList, short effectId, short attributeId = -1, short skillId = -1); void unequipItemsByEffect(const MWWorld::Ptr& ptr, short effectId, short attributeId = -1, short skillId = -1); } From e3bc11d9eb5af7d0a3328e91a45fa2364bb497f7 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 27 Jan 2018 15:41:11 +0200 Subject: [PATCH 5/9] [Client] Fix ListBox overlap crashes by removing ListBoxes properly --- apps/openmw/mwgui/windowmanagerimp.cpp | 17 +---------------- apps/openmw/mwmp/GUIController.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 55331d933..a5c3a3b2a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -908,23 +908,8 @@ namespace MWGui window->onFrame(frameDuration); } - /* - Start of tes3mp change (major) - - Custom GUI elements added by TES3MP often cause a crash here when their - mMainWidget becomes null, so a temporary fix has been added until a - more appropriate solution is researched - */ if (!mCurrentModals.empty()) - { - if (mCurrentModals.back()->mMainWidget != 0) - mCurrentModals.back()->onFrame(frameDuration); - else - mCurrentModals.pop_back(); - } - /* - End of tes3mp change (major) - */ + mCurrentModals.back()->onFrame(frameDuration); mKeyboardNavigation->onFrame(); diff --git a/apps/openmw/mwmp/GUIController.cpp b/apps/openmw/mwmp/GUIController.cpp index a1ca5f999..37e358388 100644 --- a/apps/openmw/mwmp/GUIController.cpp +++ b/apps/openmw/mwmp/GUIController.cpp @@ -100,8 +100,13 @@ void mwmp::GUIController::setChatVisible(bool chatVisible) void mwmp::GUIController::showDialogList(const mwmp::BasePlayer::GUIMessageBox &guiMessageBox) { MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); - windowManager->removeDialog(mListBox); - mListBox = nullptr; + + if (mListBox != NULL) + { + windowManager->removeDialog(mListBox); + windowManager->removeCurrentModal(mListBox); + mListBox = NULL; + } std::vector list; From 6b75a827770f7972948228276ac4a4118c22f2da Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 27 Jan 2018 18:08:45 +0200 Subject: [PATCH 6/9] [Client] Ignore equipment items for DedicatedActors with count below 0 --- apps/openmw/mwmp/DedicatedActor.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmp/DedicatedActor.cpp b/apps/openmw/mwmp/DedicatedActor.cpp index e0f18b816..6efad4ded 100644 --- a/apps/openmw/mwmp/DedicatedActor.cpp +++ b/apps/openmw/mwmp/DedicatedActor.cpp @@ -168,6 +168,11 @@ void DedicatedActor::setEquipment() for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) { + int count = equipedItems[slot].count; + + // If we've somehow received a corrupted item with a count lower than 0, ignore it + if (count < 0) continue; + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); const string &packetRefId = equipedItems[slot].refId; @@ -188,8 +193,6 @@ void DedicatedActor::setEquipment() if (packetRefId.empty() || equal) continue; - int count = equipedItems[slot].count; - if (hasItem(packetRefId, packetCharge)) equipItem(packetRefId, packetCharge); else From 6c4bb8c423b64278d445c375313b9632ba75f4a2 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 27 Jan 2018 19:09:55 +0200 Subject: [PATCH 7/9] [Client] Move resurrection code for local player to LocalPlayer --- apps/openmw/mwmp/LocalPlayer.cpp | 39 +++++++++++++++++++ apps/openmw/mwmp/LocalPlayer.hpp | 2 + .../player/ProcessorPlayerResurrect.hpp | 38 +----------------- 3 files changed, 42 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 02de21c5a..0bfb30675 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -770,6 +770,45 @@ void LocalPlayer::removeSpells() } } +void LocalPlayer::resurrect() +{ + creatureStats.mDead = false; + + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + + if (resurrectType == mwmp::RESURRECT_TYPE::IMPERIAL_SHRINE) + MWBase::Environment::get().getWorld()->teleportToClosestMarker(ptrPlayer, "divinemarker"); + else if (resurrectType == mwmp::RESURRECT_TYPE::TRIBUNAL_TEMPLE) + MWBase::Environment::get().getWorld()->teleportToClosestMarker(ptrPlayer, "templemarker"); + + ptrPlayer.getClass().getCreatureStats(ptrPlayer).resurrect(); + + // The player could have died from a hand-to-hand attack, so reset their fatigue + // as well + if (creatureStats.mDynamic[2].mMod < 1) + creatureStats.mDynamic[2].mMod = 1; + + creatureStats.mDynamic[2].mCurrent = creatureStats.mDynamic[2].mMod; + MWMechanics::DynamicStat fatigue; + fatigue.readState(creatureStats.mDynamic[2]); + ptrPlayer.getClass().getCreatureStats(ptrPlayer).setFatigue(fatigue); + + // If this player had a weapon or spell readied when dying, they will still have it + // readied but be unable to use it unless we clear it here + ptrPlayer.getClass().getNpcStats(ptrPlayer).setDrawState(MWMechanics::DrawState_Nothing); + + // Record that the player has died since the last attempt was made to arrest them, + // used to make guards lenient enough to attempt an arrest again + diedSinceArrestAttempt = true; + + LOG_APPEND(Log::LOG_INFO, "- diedSinceArrestAttempt is now true"); + + Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_RESURRECT)->setPlayer(this); + Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_RESURRECT)->Send(); + + updateStatsDynamic(true); +} + void LocalPlayer::closeInventoryWindows() { if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container) || diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 41c170c8d..6f1dc9e07 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -47,6 +47,8 @@ namespace mwmp void removeItems(); void removeSpells(); + void resurrect(); + void closeInventoryWindows(); void setDynamicStats(); diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp index c6e6ab5b3..af14a3cf1 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp @@ -27,43 +27,7 @@ namespace mwmp { LOG_APPEND(Log::LOG_INFO, "- Packet was about me with resurrectType of %i", player->resurrectType); - player->creatureStats.mDead = false; - - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - if (player->resurrectType == mwmp::RESURRECT_TYPE::IMPERIAL_SHRINE) - MWBase::Environment::get().getWorld()->teleportToClosestMarker(playerPtr, "divinemarker"); - else if (player->resurrectType == mwmp::RESURRECT_TYPE::TRIBUNAL_TEMPLE) - MWBase::Environment::get().getWorld()->teleportToClosestMarker(playerPtr, "templemarker"); - - playerPtr.getClass().getCreatureStats(playerPtr).resurrect(); - - // The player could have died from a hand-to-hand attack, so reset their fatigue - // as well - if (player->creatureStats.mDynamic[2].mMod < 1) - player->creatureStats.mDynamic[2].mMod = 1; - - player->creatureStats.mDynamic[2].mCurrent = player->creatureStats.mDynamic[2].mMod; - MWMechanics::DynamicStat fatigue; - fatigue.readState(player->creatureStats.mDynamic[2]); - playerPtr.getClass().getCreatureStats(playerPtr).setFatigue(fatigue); - - // If this player had a weapon or spell readied when dying, they will still have it - // readied but be unable to use it unless we clear it here - playerPtr.getClass().getNpcStats(playerPtr).setDrawState(MWMechanics::DrawState_Nothing); - - // Record that the player has died since the last attempt was made to arrest them, - // used to make guards lenient enough to attempt an arrest again - player->diedSinceArrestAttempt = true; - - LOG_APPEND(Log::LOG_INFO, "- diedSinceArrestAttempt is now true"); - - packet.setPlayer(player); - packet.Send(serverAddr); - - static_cast(player)->updateStatsDynamic(true); - Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_STATS_DYNAMIC)->setPlayer(player); - Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_STATS_DYNAMIC)->Send(serverAddr); + static_cast(player)->resurrect(); } else if (player != 0) { From d19d8b0a34a93d036d2e3ad1af7f26b5d683b67e Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 27 Jan 2018 19:37:16 +0200 Subject: [PATCH 8/9] [Client] Add and use enchantmentType argument for unequipItemsByEffect() --- apps/openmw/mwmp/LocalPlayer.cpp | 4 ++-- apps/openmw/mwmp/MechanicsHelper.cpp | 4 ++-- apps/openmw/mwmp/MechanicsHelper.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 0bfb30675..64e04620e 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -856,7 +856,7 @@ void LocalPlayer::setAttributes() // fortify the attribute if (ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0) { - MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1); + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1); mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory); } } @@ -887,7 +887,7 @@ void LocalPlayer::setSkills() // fortify the skill if (ptrNpcStats->getSkill(skillIndex).getModifier() > 0) { - MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::MagicEffect::FortifySkill, -1, skillIndex); + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FortifySkill, -1, skillIndex); mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory); } } diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index a63d890f1..e0ecb0478 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -233,7 +233,7 @@ bool MechanicsHelper::doesEffectListContainEffect(const ESM::EffectList& effectL return false; } -void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short effectId, short attributeId, short skillId) +void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short enchantmentType, short effectId, short attributeId, short skillId) { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::InventoryStore &ptrInventory = ptr.getClass().getInventoryStore(ptr); @@ -249,7 +249,7 @@ void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short effect { const ESM::Enchantment* enchantment = world->getStore().get().find(enchantmentName); - if (doesEffectListContainEffect(enchantment->mEffects, effectId, attributeId, skillId)) + if (enchantment->mData.mType == enchantmentType && doesEffectListContainEffect(enchantment->mEffects, effectId, attributeId, skillId)) ptrInventory.unequipSlot(slot, ptr); } } diff --git a/apps/openmw/mwmp/MechanicsHelper.hpp b/apps/openmw/mwmp/MechanicsHelper.hpp index cf0eaa273..b707c13fc 100644 --- a/apps/openmw/mwmp/MechanicsHelper.hpp +++ b/apps/openmw/mwmp/MechanicsHelper.hpp @@ -25,7 +25,7 @@ namespace MechanicsHelper void processAttack(mwmp::Attack attack, const MWWorld::Ptr& attacker); bool doesEffectListContainEffect(const ESM::EffectList& effectList, short effectId, short attributeId = -1, short skillId = -1); - void unequipItemsByEffect(const MWWorld::Ptr& ptr, short effectId, short attributeId = -1, short skillId = -1); + void unequipItemsByEffect(const MWWorld::Ptr& ptr, short enchantmentType, short effectId, short attributeId = -1, short skillId = -1); } From d7e29f1f61f7cddabe8c07fc1882e0294f783530 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 27 Jan 2018 20:19:39 +0200 Subject: [PATCH 9/9] [Client] Unequip items with constant effect damage when resurrected --- apps/openmw/mwmp/LocalPlayer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 64e04620e..5973ffea3 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -803,6 +803,14 @@ void LocalPlayer::resurrect() LOG_APPEND(Log::LOG_INFO, "- diedSinceArrestAttempt is now true"); + // Ensure we unequip any items with constant effects that can put us into an infinite + // death loop + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::DrainHealth); + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FireDamage); + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FrostDamage); + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::ShockDamage); + MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::SunDamage); + Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_RESURRECT)->setPlayer(this); Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_RESURRECT)->Send();