mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-30 12:06:48 +00:00
Merge pull request #373 from TES3MP/0.6.2 while resolving conflicts
# Conflicts: # apps/openmw/mwmp/DedicatedActor.cpp # apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp
This commit is contained in:
commit
d70b93e095
9 changed files with 191 additions and 93 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 = equipmentItems[slot].refId;
|
||||
|
@ -188,8 +193,6 @@ void DedicatedActor::setEquipment()
|
|||
if (packetRefId.empty() || equal)
|
||||
continue;
|
||||
|
||||
int count = equipmentItems[slot].count;
|
||||
|
||||
if (hasItem(packetRefId, packetCharge))
|
||||
equipItem(packetRefId, packetCharge);
|
||||
else
|
||||
|
|
|
@ -60,6 +60,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);
|
||||
|
@ -120,8 +129,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<std::string> list;
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ namespace mwmp
|
|||
GUIController();
|
||||
~GUIController();
|
||||
void cleanUp();
|
||||
|
||||
void refreshGuiMode(MWGui::GuiMode guiMode);
|
||||
|
||||
void setupChat(const Settings::Manager &manager);
|
||||
|
||||
void printChatMessage(const mwmp::Chat &chat);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "Main.hpp"
|
||||
#include "Networking.hpp"
|
||||
#include "CellController.hpp"
|
||||
#include "GUIController.hpp"
|
||||
#include "MechanicsHelper.hpp"
|
||||
|
||||
using namespace mwmp;
|
||||
|
@ -428,6 +429,7 @@ void LocalPlayer::updateEquipment(bool forceUpdate)
|
|||
{
|
||||
auto &item = equipmentItems[slot];
|
||||
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
|
||||
|
||||
if (it != invStore.end())
|
||||
{
|
||||
if (!::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), equipmentItems[slot].refId) || forceUpdate)
|
||||
|
@ -753,6 +755,61 @@ void LocalPlayer::removeSpells()
|
|||
}
|
||||
}
|
||||
|
||||
void LocalPlayer::resurrect()
|
||||
{
|
||||
creatureStats.mDead = false;
|
||||
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
||||
|
||||
switch (player->resurrectType)
|
||||
{
|
||||
case ResurrectType::Regular:
|
||||
break;
|
||||
case ResurrectType::ImperialShrine:
|
||||
world->teleportToClosestMarker(ptrPlayer, "divinemarker");
|
||||
break;
|
||||
case ResurrectType::TribunalTemple:
|
||||
world->teleportToClosestMarker(ptrPlayer, "templemarker");
|
||||
break;
|
||||
}
|
||||
|
||||
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<float> 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");
|
||||
|
||||
// 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();
|
||||
|
||||
updateStatsDynamic(true);
|
||||
}
|
||||
|
||||
void LocalPlayer::closeInventoryWindows()
|
||||
{
|
||||
if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container) ||
|
||||
|
@ -781,47 +838,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);
|
||||
|
||||
attributeValue.readState(creatureStats.mAttributes[i]);
|
||||
ptrCreatureStats->setAttribute(i, attributeValue);
|
||||
// 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::Enchantment::ConstantEffect, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1);
|
||||
mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory);
|
||||
}
|
||||
}
|
||||
|
||||
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::Enchantment::ConstantEffect, 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);
|
||||
}
|
||||
|
@ -918,6 +995,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;
|
||||
|
@ -926,12 +1005,15 @@ void LocalPlayer::setClass()
|
|||
}
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(charClass.mId);
|
||||
|
||||
const ESM::Class *existingCharClass = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find(charClass.mId);
|
||||
const ESM::Class *existingCharClass = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,8 +1156,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<ESM::Faction>().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);
|
||||
|
@ -1145,18 +1237,18 @@ void LocalPlayer::setShapeshift()
|
|||
void LocalPlayer::sendClass()
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const ESM::NPC *cpl = world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
||||
const ESM::Class *cls = world->getStore().get<ESM::Class>().find(cpl->mClass);
|
||||
const ESM::NPC *npcBase = world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
||||
const ESM::Class *esmClass = world->getStore().get<ESM::Class>().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();
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace mwmp
|
|||
void removeItems();
|
||||
void removeSpells();
|
||||
|
||||
void resurrect();
|
||||
|
||||
void closeInventoryWindows();
|
||||
|
||||
void setDynamicStats();
|
||||
|
|
|
@ -213,3 +213,45 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
LOG_APPEND(Log::LOG_VERBOSE, " - success: %d", attack.success);
|
||||
}
|
||||
}
|
||||
|
||||
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 enchantmentType, 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<ESM::Enchantment>().find(enchantmentName);
|
||||
|
||||
if (enchantment->mData.mType == enchantmentType && doesEffectListContainEffect(enchantment->mEffects, effectId, attributeId, skillId))
|
||||
ptrInventory.unequipSlot(slot, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace MechanicsHelper
|
|||
bool getSpellSuccess(std::string spellId, const MWWorld::Ptr& caster);
|
||||
|
||||
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 enchantmentType, short effectId, short attributeId = -1, short skillId = -1);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,53 +27,7 @@ namespace mwmp
|
|||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Packet was about me with resurrectType of %i", (int) player->resurrectType);
|
||||
|
||||
player->creatureStats.mDead = false;
|
||||
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::Ptr playerPtr = world->getPlayerPtr();
|
||||
|
||||
|
||||
switch(player->resurrectType)
|
||||
{
|
||||
case ResurrectType::Regular:
|
||||
break;
|
||||
case ResurrectType::ImperialShrine:
|
||||
world->teleportToClosestMarker(playerPtr, "divinemarker");
|
||||
break;
|
||||
case ResurrectType::TribunalTemple:
|
||||
world->teleportToClosestMarker(playerPtr, "templemarker");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
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<float> 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<LocalPlayer*>(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<LocalPlayer*>(player)->resurrect();
|
||||
}
|
||||
else if (player != 0)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue