#include "ObjectList.hpp" #include "Main.hpp" #include "Networking.hpp" #include "MechanicsHelper.hpp" #include "LocalPlayer.hpp" #include "DedicatedPlayer.hpp" #include "PlayerList.hpp" #include "CellController.hpp" #include "RecordHelper.hpp" #include #include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwgui/container.hpp" #include "../mwgui/dialogue.hpp" #include "../mwgui/inventorywindow.hpp" #include "../mwgui/windowmanagerimp.hpp" #include "../mwmechanics/aifollow.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/summoning.hpp" #include "../mwrender/animation.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/timestamp.hpp" using namespace mwmp; ObjectList::ObjectList() { } ObjectList::~ObjectList() { } Networking *ObjectList::getNetworking() { return mwmp::Main::get().getNetworking(); } void ObjectList::reset() { cell.blank(); baseObjects.clear(); guid = mwmp::Main::get().getNetworking()->getLocalPlayer()->guid; action = -1; containerSubAction = 0; } void ObjectList::addBaseObject(BaseObject baseObject) { baseObjects.push_back(baseObject); } mwmp::BaseObject ObjectList::getBaseObjectFromPtr(const MWWorld::Ptr& ptr) { mwmp::BaseObject baseObject; if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { baseObject.isPlayer = true; baseObject.guid = mwmp::Main::get().getLocalPlayer()->guid; } else if (mwmp::PlayerList::isDedicatedPlayer(ptr)) { baseObject.isPlayer = true; baseObject.guid = mwmp::PlayerList::getPlayer(ptr)->guid; } else { baseObject.isPlayer = false; baseObject.refId = ptr.getCellRef().getRefId(); baseObject.refNum = ptr.getCellRef().getRefNum().mIndex; baseObject.mpNum = ptr.getCellRef().getMpNum(); } return baseObject; } void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const MWWorld::Ptr& itemPtr, int itemCount, int actionCount) { mwmp::ContainerItem containerItem; containerItem.refId = itemPtr.getCellRef().getRefId(); containerItem.count = itemCount; containerItem.charge = itemPtr.getCellRef().getCharge(); containerItem.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge(); containerItem.soul = itemPtr.getCellRef().getSoul(); containerItem.actionCount = actionCount; LOG_APPEND(TimedLog::LOG_VERBOSE, "--- Adding container item %s to packet with count %i and actionCount %i", containerItem.refId.c_str(), itemCount, actionCount); baseObject.containerItems.push_back(containerItem); } void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const MWGui::ItemStack& itemStack, int itemCount, int actionCount) { mwmp::ContainerItem containerItem; containerItem.refId = itemStack.mBase.getCellRef().getRefId(); containerItem.count = itemCount; containerItem.charge = itemStack.mBase.getCellRef().getCharge(); containerItem.enchantmentCharge = itemStack.mBase.getCellRef().getEnchantmentCharge(); containerItem.soul = itemStack.mBase.getCellRef().getSoul(); containerItem.actionCount = actionCount; LOG_APPEND(TimedLog::LOG_VERBOSE, "--- Adding container item %s to packet with count %i and actionCount %i", containerItem.refId.c_str(), itemCount, actionCount); baseObject.containerItems.push_back(containerItem); } void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const std::string itemId, int itemCount, int actionCount) { mwmp::ContainerItem containerItem; containerItem.refId = itemId; containerItem.count = itemCount; containerItem.charge = -1; containerItem.enchantmentCharge = -1; containerItem.soul = ""; containerItem.actionCount = actionCount; LOG_APPEND(TimedLog::LOG_VERBOSE, "--- Adding container item %s to packet with count %i and actionCount %i", containerItem.refId.c_str(), itemCount, actionCount); baseObject.containerItems.push_back(containerItem); } void ObjectList::addEntireContainer(const MWWorld::Ptr& ptr) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Adding entire container %s %i-%i", ptr.getCellRef().getRefId().c_str(), ptr.getCellRef().getRefNum().mIndex, ptr.getCellRef().getMpNum()); MWWorld::ContainerStore& containerStore = ptr.getClass().getContainerStore(ptr); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); // If the container store has not been populated with items yet, handle that now if (!containerStore.isResolved()) containerStore.resolve(); for (const auto itemPtr : containerStore) { addContainerItem(baseObject, itemPtr, itemPtr.getRefData().getCount(), itemPtr.getRefData().getCount()); } addBaseObject(baseObject); } void ObjectList::editContainers(MWWorld::CellStore* cellStore) { bool isLocalEvent = guid == Main::get().getLocalPlayer()->guid; LOG_APPEND(TimedLog::LOG_VERBOSE, "- isLocalEvent? %s", isLocalEvent ? "true" : "false"); BaseObject baseObject; for (unsigned int i = 0; i < baseObjectCount; i++) { baseObject = baseObjects.at(i); LOG_APPEND(TimedLog::LOG_VERBOSE, "- container %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); bool isCurrentContainer = false; bool hasActorEquipment = ptrFound.getClass().isActor() && ptrFound.getClass().hasInventoryStore(ptrFound); // If we are in a container, and it happens to be this container, keep track of that if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container)) { CurrentContainer *currentContainer = &mwmp::Main::get().getLocalPlayer()->currentContainer; if (currentContainer->refNum == ptrFound.getCellRef().getRefNum().mIndex && currentContainer->mpNum == ptrFound.getCellRef().getMpNum()) { isCurrentContainer = true; } } MWWorld::ContainerStore& containerStore = ptrFound.getClass().getContainerStore(ptrFound); // If we are setting the entire contents, clear the current ones if (action == BaseObjectList::SET) { containerStore.setResolved(true); containerStore.clear(); } bool isLocalDrag = isLocalEvent && containerSubAction == BaseObjectList::DRAG; bool isLocalTakeAll = isLocalEvent && containerSubAction == BaseObjectList::TAKE_ALL; std::string takeAllSound = ""; MWWorld::Ptr ownerPtr = ptrFound.getClass().isActor() ? ptrFound : MWBase::Environment::get().getWorld()->getPlayerPtr(); for (const auto &containerItem : baseObject.containerItems) { //LOG_APPEND(TimedLog::LOG_VERBOSE, "-- containerItem %s, count: %i, actionCount: %i", // containerItem.refId.c_str(), containerItem.count, containerItem.actionCount); if (containerItem.refId.find("$dynamic") != std::string::npos) continue; if (action == BaseObjectList::SET || action == BaseObjectList::ADD) { // Create a ManualRef to be able to set item charge MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), containerItem.refId, 1); MWWorld::Ptr newPtr = ref.getPtr(); if (containerItem.count > 1) newPtr.getRefData().setCount(containerItem.count); if (containerItem.charge > -1) newPtr.getCellRef().setCharge(containerItem.charge); if (containerItem.enchantmentCharge > -1) newPtr.getCellRef().setEnchantmentCharge(containerItem.enchantmentCharge); if (!containerItem.soul.empty()) newPtr.getCellRef().setSoul(containerItem.soul); containerStore.add(newPtr, containerItem.count, ownerPtr); } else if (action == BaseObjectList::REMOVE && containerItem.actionCount > 0) { // We have to find the right item ourselves because ContainerStore has no method // accounting for charge for (const auto itemPtr : containerStore) { if (Misc::StringUtils::ciEqual(itemPtr.getCellRef().getRefId(), containerItem.refId)) { if (itemPtr.getCellRef().getCharge() == containerItem.charge && itemPtr.getCellRef().getEnchantmentCharge() == containerItem.enchantmentCharge && Misc::StringUtils::ciEqual(itemPtr.getCellRef().getSoul(), containerItem.soul)) { // Store the sound of the first item in a TAKE_ALL if (isLocalTakeAll && takeAllSound.empty()) takeAllSound = itemPtr.getClass().getUpSoundId(itemPtr); // Is this an actor's container? If so, unequip this item if it was equipped if (hasActorEquipment) { MWWorld::InventoryStore& invStore = ptrFound.getClass().getInventoryStore(ptrFound); if (invStore.isEquipped(itemPtr)) invStore.unequipItemQuantity(itemPtr, ptrFound, containerItem.count); } bool isDragResolved = false; if (isLocalDrag && isCurrentContainer) { MWGui::ContainerWindow* containerWindow = MWBase::Environment::get().getWindowManager()->getContainerWindow(); if (!containerWindow->isOnDragAndDrop()) { isDragResolved = containerWindow->dragItemByPtr(itemPtr, containerItem.actionCount); } } if (!isLocalDrag || !isDragResolved) { containerStore.remove(itemPtr, containerItem.actionCount, ownerPtr); if (isLocalDrag || isLocalTakeAll) { MWWorld::Ptr ptrPlayer = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::ContainerStore &playerStore = ptrPlayer.getClass().getContainerStore(ptrPlayer); *playerStore.add(itemPtr, containerItem.actionCount, ownerPtr, false); } } } } } } } // Was this a SET or ADD action on an actor's container, and are we the authority // over the actor? If so, autoequip the actor if ((action == BaseObjectList::ADD || action == BaseObjectList::SET) && hasActorEquipment && mwmp::Main::get().getCellController()->isLocalActor(ptrFound)) { MWWorld::InventoryStore& invStore = ptrFound.getClass().getInventoryStore(ptrFound); invStore.autoEquip(ptrFound); mwmp::Main::get().getCellController()->getLocalActor(ptrFound)->updateEquipment(true, true); } // If this container can be harvested, disable and then enable it again to refresh its animation if (ptrFound.getClass().canBeHarvested(ptrFound)) { MWBase::Environment::get().getWorld()->disable(ptrFound); MWBase::Environment::get().getWorld()->enable(ptrFound); } // If this container was open for us, update its view if (isCurrentContainer) { if (isLocalTakeAll) { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->playSound(takeAllSound); } else { MWGui::ContainerWindow* containerWindow = MWBase::Environment::get().getWindowManager()->getContainerWindow(); containerWindow->setPtr(ptrFound); } } } } } void ObjectList::activateObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { MWWorld::Ptr ptrFound; if (baseObject.isPlayer) { if (baseObject.guid == Main::get().getLocalPlayer()->guid) { ptrFound = Main::get().getLocalPlayer()->getPlayerPtr(); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Activated object is local player"); } else { DedicatedPlayer *player = PlayerList::getPlayer(baseObject.guid); if (player != 0) { ptrFound = player->getPtr(); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Activated object is player %s", player->npc.mName.c_str()); } else { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Could not find player to activate!"); } } } else { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Activated object is %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); } if (ptrFound) { MWWorld::Ptr activatingActorPtr; if (baseObject.activatingActor.isPlayer) { activatingActorPtr = MechanicsHelper::getPlayerPtr(baseObject.activatingActor); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Object has been activated by player %s", activatingActorPtr.getClass().getName(activatingActorPtr).c_str()); } else { activatingActorPtr = cellStore->searchExact(baseObject.activatingActor.refNum, baseObject.activatingActor.mpNum, baseObject.activatingActor.refId); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Object has been activated by actor %s %i-%i", activatingActorPtr.getCellRef().getRefId().c_str(), activatingActorPtr.getCellRef().getRefNum().mIndex, activatingActorPtr.getCellRef().getMpNum()); } if (activatingActorPtr) { // Is an item that can be picked up being activated by the local player with their inventory open? if (activatingActorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container || MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory)) { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(ptrFound); } else { MWBase::Environment::get().getWorld()->activate(ptrFound, activatingActorPtr); } } } } } void ObjectList::placeObjects(MWWorld::CellStore* cellStore) { MWBase::World *world = MWBase::Environment::get().getWorld(); for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, count: %i, charge: %i, enchantmentCharge: %.2f, soul: %s", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum, baseObject.count, baseObject.charge, baseObject.enchantmentCharge, baseObject.soul.c_str()); // Ignore generic dynamic refIds because they could be anything on other clients if (baseObject.refId.find("$dynamic") != std::string::npos) continue; MWWorld::Ptr ptrFound = cellStore->searchExact(0, baseObject.mpNum); // Only create this object if it doesn't already exist if (!ptrFound) { try { MWWorld::ManualRef ref(world->getStore(), baseObject.refId, 1); MWWorld::Ptr newPtr = ref.getPtr(); if (baseObject.count > 1) newPtr.getRefData().setCount(baseObject.count); if (baseObject.charge > -1) newPtr.getCellRef().setCharge(baseObject.charge); if (baseObject.enchantmentCharge > -1) newPtr.getCellRef().setEnchantmentCharge(baseObject.enchantmentCharge); if (!baseObject.soul.empty()) newPtr.getCellRef().setSoul(baseObject.soul); newPtr.getCellRef().setGoldValue(baseObject.goldValue); newPtr = world->placeObject(newPtr, cellStore, baseObject.position); // Because gold automatically gets replaced with a new object, make sure we set the mpNum at the end newPtr.getCellRef().setMpNum(baseObject.mpNum); if (baseObject.droppedByPlayer) { MWBase::Environment::get().getSoundManager()->playSound3D(newPtr, newPtr.getClass().getDownSoundId(newPtr), 1.f, 1.f); if (guid == Main::get().getLocalPlayer()->guid) world->PCDropped(newPtr); } } catch (std::exception&) { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Ignored placement of invalid object %s", baseObject.refId.c_str()); } } else LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Object already existed!"); } } void ObjectList::spawnObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); // Ignore generic dynamic refIds because they could be anything on other clients if (baseObject.refId.find("$dynamic") != std::string::npos) continue; else if (!RecordHelper::doesRecordIdExist(baseObject.refId) && !RecordHelper::doesRecordIdExist(baseObject.refId)) { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Ignored spawning of invalid object %s", baseObject.refId.c_str()); continue; } MWWorld::Ptr ptrFound = cellStore->searchExact(0, baseObject.mpNum); // Only create this object if it doesn't already exist if (!ptrFound) { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), baseObject.refId, 1); MWWorld::Ptr newPtr = ref.getPtr(); newPtr.getCellRef().setMpNum(baseObject.mpNum); newPtr = MWBase::Environment::get().getWorld()->placeObject(newPtr, cellStore, baseObject.position); MWMechanics::CreatureStats& creatureStats = newPtr.getClass().getCreatureStats(newPtr); if (baseObject.isSummon) { MWWorld::Ptr masterPtr; if (baseObject.master.isPlayer) masterPtr = MechanicsHelper::getPlayerPtr(baseObject.master); else masterPtr = cellStore->searchExact(baseObject.master.refNum, baseObject.master.mpNum, baseObject.master.refId); if (masterPtr) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Actor has master: %s", masterPtr.getCellRef().getRefId().c_str()); MWMechanics::AiFollow package(masterPtr); creatureStats.getAiSequence().stack(package, newPtr); MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(newPtr); if (anim) { const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() .search("VFX_Summon_Start"); if (fx) anim->addEffect("meshes\\" + fx->mModel, -1, false); } int creatureActorId = newPtr.getClass().getCreatureStats(newPtr).getActorId(); MWMechanics::CreatureStats& masterCreatureStats = masterPtr.getClass().getCreatureStats(masterPtr); std::vector activeEffects; ESM::ActiveEffect activeEffect; activeEffect.mEffectId = baseObject.summonEffectId; activeEffect.mDuration = baseObject.summonDuration; activeEffect.mMagnitude = 1; activeEffects.push_back(activeEffect); LOG_APPEND(TimedLog::LOG_INFO, "-- adding active spell to master with id %s, effect %i, duration %f", baseObject.summonSpellId.c_str(), baseObject.summonEffectId, baseObject.summonDuration); auto activeSpells = masterCreatureStats.getActiveSpells(); if (!activeSpells.isSpellActive(baseObject.summonSpellId)) activeSpells.addSpell(baseObject.summonSpellId, false, activeEffects, "", masterCreatureStats.getActorId()); LOG_APPEND(TimedLog::LOG_INFO, "-- setting summoned creatureActorId for %i-%i to %i", newPtr.getCellRef().getRefNum(), newPtr.getCellRef().getMpNum(), creatureActorId); // Check if this creature is present in the summoner's summoned creature map std::map& creatureMap = masterCreatureStats.getSummonedCreatureMap(); bool foundSummonedCreature = false; for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) { if (it->first.mEffectId == baseObject.summonEffectId && it->first.mSourceId == baseObject.summonSpellId) { foundSummonedCreature = true; break; } ++it; } // If it is, update its creatureActorId if (foundSummonedCreature) { masterCreatureStats.setSummonedCreatureActorId(baseObject.refId, creatureActorId); } // If not, add it to the summoned creature map else { ESM::SummonKey summonKey(baseObject.summonEffectId, baseObject.summonSpellId, -1); creatureMap.emplace(summonKey, creatureActorId); } creatureStats.setFriendlyHits(0); } } } else LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Actor already existed!"); } } void ObjectList::deleteObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); // If we are in a container, and it happens to be this object, exit it if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container)) { CurrentContainer *currentContainer = &mwmp::Main::get().getLocalPlayer()->currentContainer; if (currentContainer->refNum == ptrFound.getCellRef().getRefNum().mIndex && currentContainer->mpNum == ptrFound.getCellRef().getMpNum()) { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->setDragDrop(false); } } // Is this a dying actor being deleted before its death animation has finished? If so, // increase the death count for the actor if applicable and run the actor's script, // which is the same as what happens in OpenMW's ContainerWindow::onDisposeCorpseButtonClicked() // if an actor's corpse is disposed of before its death animation is finished if (ptrFound.getClass().isActor()) { MWMechanics::CreatureStats& creatureStats = ptrFound.getClass().getCreatureStats(ptrFound); if (creatureStats.isDead() && !creatureStats.isDeathAnimationFinished()) { creatureStats.setDeathAnimationFinished(true); MWBase::Environment::get().getMechanicsManager()->notifyDied(ptrFound); const std::string script = ptrFound.getClass().getScript(ptrFound); if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled()) { MWScript::InterpreterContext interpreterContext(&ptrFound.getRefData().getLocals(), ptrFound); MWBase::Environment::get().getScriptManager()->run(script, interpreterContext); } } } MWBase::Environment::get().getWorld()->deleteObject(ptrFound); } } } void ObjectList::lockObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); if (baseObject.lockLevel > 0) ptrFound.getCellRef().lock(baseObject.lockLevel); else ptrFound.getCellRef().unlock(); } } } void ObjectList::triggerTrapObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); if (!baseObject.isDisarmed) { MWMechanics::CastSpell cast(ptrFound, ptrFound); cast.mHitPosition = baseObject.position.asVec3(); cast.cast(ptrFound.getCellRef().getTrap()); } ptrFound.getCellRef().setTrap(""); MWBase::Environment::get().getSoundManager()->playSound3D(ptrFound, "Disarm Trap", 1.0f, 1.0f); } } } void ObjectList::scaleObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, scale: %f", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum, baseObject.scale); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); MWBase::Environment::get().getWorld()->scaleObject(ptrFound, baseObject.scale); } } } void ObjectList::setObjectStates(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, state: %s", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum, baseObject.objectState ? "true" : "false"); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); if (baseObject.objectState) { MWBase::Environment::get().getWorld()->enable(ptrFound); // Is this an actor in a cell where we're the authority? If so, initialize it as // a LocalActor if (ptrFound.getClass().isActor() && mwmp::Main::get().getCellController()->hasLocalAuthority(*cellStore->getCell())) { mwmp::Main::get().getCellController()->getCell(*cellStore->getCell())->initializeLocalActor(ptrFound); } } else MWBase::Environment::get().getWorld()->disable(ptrFound); } } } void ObjectList::moveObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); MWBase::Environment::get().getWorld()->moveObject(ptrFound, baseObject.position.pos[0], baseObject.position.pos[1], baseObject.position.pos[2]); } } } void ObjectList::restockObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); //ptrFound.getClass().restock(ptrFound); reset(); packetOrigin = mwmp::PACKET_ORIGIN::CLIENT_GAMEPLAY; cell = *ptrFound.getCell()->getCell(); action = mwmp::BaseObjectList::SET; containerSubAction = mwmp::BaseObjectList::RESTOCK_RESULT; addEntireContainer(ptrFound); sendContainer(); } } } void ObjectList::rotateObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); MWBase::Environment::get().getWorld()->rotateObject(ptrFound, baseObject.position.rot[0], baseObject.position.rot[1], baseObject.position.rot[2], MWBase::RotationFlag_none); } } } void ObjectList::animateObjects(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); MWBase::MechanicsManager * mechanicsManager = MWBase::Environment::get().getMechanicsManager(); mechanicsManager->playAnimationGroup(ptrFound, baseObject.animGroup, baseObject.animMode, std::numeric_limits::max(), true); } } } void ObjectList::playObjectSounds(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { MWWorld::Ptr ptrFound; std::string objectDescription; if (baseObject.isPlayer) { if (baseObject.guid == Main::get().getLocalPlayer()->guid) { objectDescription = "LocalPlayer " + Main::get().getLocalPlayer()->npc.mName; ptrFound = Main::get().getLocalPlayer()->getPlayerPtr(); } else { DedicatedPlayer *player = PlayerList::getPlayer(baseObject.guid); if (player != 0) { objectDescription = "DedicatedPlayer " + player->npc.mName; ptrFound = player->getPtr(); } } } else { objectDescription = baseObject.refId + " " + std::to_string(baseObject.refNum) + "-" + std::to_string(baseObject.mpNum); ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); } if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- Playing sound %s on %s", baseObject.soundId.c_str(), objectDescription.c_str()); bool playAtPosition = false; if (ptrFound.isInCell()) { ESM::CellId localCell = Main::get().getLocalPlayer()->cell.getCellId(); ESM::CellId soundCell = ptrFound.getCell()->getCell()->getCellId(); playAtPosition = localCell == soundCell; } if (playAtPosition) { MWBase::Environment::get().getSoundManager()->playSound3D(ptrFound.getRefData().getPosition().asVec3(), baseObject.soundId, baseObject.volume, baseObject.pitch, MWSound::Type::Sfx, MWSound::PlayMode::Normal, 0); } else { MWBase::Environment::get().getSoundManager()->playSound3D(ptrFound, baseObject.soundId, baseObject.volume, baseObject.pitch, MWSound::Type::Sfx, MWSound::PlayMode::Normal, 0); } } } } void ObjectList::setGoldPoolsForObjects(MWWorld::CellStore* cellStore) { for (const auto& baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); if (ptrFound.getClass().isActor()) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Setting gold pool to %u", baseObject.goldPool); ptrFound.getClass().getCreatureStats(ptrFound).setGoldPool(baseObject.goldPool); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Setting last gold restock time to %f hours and %i days passed", baseObject.lastGoldRestockHour, baseObject.lastGoldRestockDay); ptrFound.getClass().getCreatureStats(ptrFound).setLastRestockTime(MWWorld::TimeStamp(baseObject.lastGoldRestockHour, baseObject.lastGoldRestockDay)); } else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_WARN, "Failed to set gold pool on %s %i-%i because it is not an actor!", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); } } } } void ObjectList::activateDoors(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); MWWorld::DoorState doorState = static_cast(baseObject.doorState); ptrFound.getClass().setDoorState(ptrFound, doorState); MWBase::Environment::get().getWorld()->saveDoorState(ptrFound, doorState); } } } void ObjectList::setDoorDestinations(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); ptrFound.getCellRef().setTeleport(baseObject.teleportState); if (baseObject.teleportState) { ptrFound.getCellRef().setDoorDest(baseObject.destinationPosition); if (baseObject.destinationCell.isExterior()) ptrFound.getCellRef().setDestCell(""); else ptrFound.getCellRef().setDestCell(baseObject.destinationCell.getShortDescription()); } } } } void ObjectList::runConsoleCommands(MWWorld::CellStore* cellStore) { MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); LOG_APPEND(TimedLog::LOG_VERBOSE, "- Console command: %s", consoleCommand.c_str()); if (baseObjects.empty()) { windowManager->clearConsolePtr(); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Running with no object reference"); windowManager->executeCommandInConsole(consoleCommand); } else { for (const auto &baseObject : baseObjects) { windowManager->clearConsolePtr(); if (baseObject.isPlayer) { if (baseObject.guid == Main::get().getLocalPlayer()->guid) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Running on local player"); windowManager->setConsolePtr(Main::get().getLocalPlayer()->getPlayerPtr()); windowManager->executeCommandInConsole(consoleCommand); } else { DedicatedPlayer *player = PlayerList::getPlayer(baseObject.guid); if (player != 0) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Running on player %s", player->npc.mName.c_str()); windowManager->setConsolePtr(player->getPtr()); windowManager->executeCommandInConsole(consoleCommand); } } } // Only require a valid cellStore if running on cell objects else if (cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Running on object %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); windowManager->setConsolePtr(ptrFound); windowManager->executeCommandInConsole(consoleCommand); } } } windowManager->clearConsolePtr(); } } void ObjectList::makeDialogueChoices(MWWorld::CellStore* cellStore) { for (const auto& baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); if (ptrFound.getClass().isActor()) { // Ensure the dialogue window has the correct Ptr set for it if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)) { if (MWBase::Environment::get().getWindowManager()->getDialogueWindow()->getPtr() != ptrFound) { MWBase::Environment::get().getWindowManager()->getDialogueWindow()->setPtr(ptrFound); } } else { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, ptrFound); } LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Making dialogue choice of type %i", baseObject.dialogueChoiceType); if (baseObject.dialogueChoiceType == DialogueChoiceType::TOPIC) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- topic was %s", baseObject.topicId.c_str()); } std::string topic = baseObject.topicId; if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) { char delimiter = '|'; // If we're using a translated version of Morrowind, we may have received a string that had the original // topic delimited from its possible English translation by a | character, in which case we need to use // the original topic here if (topic.find(delimiter) != std::string::npos) { topic = topic.substr(0, topic.find(delimiter)); } // Alternatively, we may have received a topic that needs to be translated into the current language's // version of it else { std::string translatedTopic = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().getLocalizedTopicId(topic); if (!translatedTopic.empty()) { topic = translatedTopic; } } } MWBase::Environment::get().getWindowManager()->getDialogueWindow()->activateDialogueChoice(baseObject.dialogueChoiceType, topic); } else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_WARN, "Failed to make dialogue choice for %s %i-%i because it is not an actor!", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); } } } } void ObjectList::setClientLocals(MWWorld::CellStore* cellStore) { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); for (const auto& clientLocal : baseObject.clientLocals) { std::string valueAsString; std::string variableTypeAsString; if (clientLocal.variableType == mwmp::VARIABLE_TYPE::SHORT || clientLocal.variableType == mwmp::VARIABLE_TYPE::LONG) { variableTypeAsString = clientLocal.variableType == mwmp::VARIABLE_TYPE::SHORT ? "short" : "long"; valueAsString = std::to_string(clientLocal.intValue); } else if (clientLocal.variableType == mwmp::VARIABLE_TYPE::FLOAT) { variableTypeAsString = "float"; valueAsString = std::to_string(clientLocal.floatValue); } if (clientLocal.variableType == mwmp::VARIABLE_TYPE::SHORT) ptrFound.getRefData().getLocals().mShorts.at(clientLocal.internalIndex) = clientLocal.intValue; else if (clientLocal.variableType == mwmp::VARIABLE_TYPE::LONG) ptrFound.getRefData().getLocals().mLongs.at(clientLocal.internalIndex) = clientLocal.intValue; else if (clientLocal.variableType == mwmp::VARIABLE_TYPE::FLOAT) ptrFound.getRefData().getLocals().mFloats.at(clientLocal.internalIndex) = clientLocal.floatValue; } } } } void ObjectList::setMemberShorts() { /* for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s, index: %i, shortVal: %i", baseObject.refId.c_str(), baseObject.index, baseObject.shortVal); // Mimic the way a Ptr is fetched in InterpreterContext for similar situations MWWorld::Ptr ptrFound = MWBase::Environment::get().getWorld()->searchPtr(baseObject.refId, false); if (ptrFound) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); std::string scriptId = ptrFound.getClass().getScript(ptrFound); ptrFound.getRefData().setLocals( *MWBase::Environment::get().getWorld()->getStore().get().find(scriptId)); ptrFound.getRefData().getLocals().mShorts.at(baseObject.index) = baseObject.shortVal;; } } */ } void ObjectList::playMusic() { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- filename: %s", baseObject.musicFilename.c_str()); MWBase::Environment::get().getSoundManager()->streamMusic(baseObject.musicFilename); } } void ObjectList::playVideo() { for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- filename: %s, allowSkipping: %s", baseObject.videoFilename.c_str(), baseObject.allowSkipping ? "true" : "false"); MWBase::Environment::get().getWindowManager()->playVideo(baseObject.videoFilename, baseObject.allowSkipping); } } void ObjectList::addAllContainers(MWWorld::CellStore* cellStore) { for (auto &ref : cellStore->getContainers()->mList) { MWWorld::Ptr ptr(&ref, 0); addEntireContainer(ptr); } for (auto &ref : cellStore->getNpcs()->mList) { MWWorld::Ptr ptr(&ref, 0); addEntireContainer(ptr); } for (auto &ref : cellStore->getCreatures()->mList) { MWWorld::Ptr ptr(&ref, 0); addEntireContainer(ptr); } } void ObjectList::addRequestedContainers(MWWorld::CellStore* cellStore, const std::vector& requestObjects) { for (const auto &baseObject : requestObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { if (ptrFound.getClass().hasContainerStore(ptrFound)) addEntireContainer(ptrFound); else LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Object lacks container store", ptrFound.getCellRef().getRefId().c_str()); } } } void ObjectList::addObjectGeneric(const MWWorld::Ptr& ptr) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); addBaseObject(baseObject); } void ObjectList::addObjectActivate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& activatingActor) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.activatingActor = MechanicsHelper::getTarget(activatingActor); addBaseObject(baseObject); } void ObjectList::addObjectHit(const MWWorld::Ptr& ptr, const MWWorld::Ptr& hittingActor) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.hittingActor = MechanicsHelper::getTarget(hittingActor); baseObject.hitAttack.success = false; addBaseObject(baseObject); } void ObjectList::addObjectHit(const MWWorld::Ptr& ptr, const MWWorld::Ptr& hittingActor, const Attack hitAttack) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.hittingActor = MechanicsHelper::getTarget(hittingActor); baseObject.hitAttack = hitAttack; addBaseObject(baseObject); } void ObjectList::addObjectPlace(const MWWorld::Ptr& ptr, bool droppedByPlayer) { if (ptr.getCellRef().getRefId().find("$dynamic") != std::string::npos) { MWBase::Environment::get().getWindowManager()->messageBox("You cannot place unsynchronized custom items in multiplayer."); return; } cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.charge = ptr.getCellRef().getCharge(); baseObject.enchantmentCharge = ptr.getCellRef().getEnchantmentCharge(); baseObject.soul = ptr.getCellRef().getSoul(); baseObject.droppedByPlayer = droppedByPlayer; baseObject.hasContainer = ptr.getClass().hasContainerStore(ptr); // Make sure we send the RefData position instead of the CellRef one, because that's what // we actually see on this client baseObject.position = ptr.getRefData().getPosition(); // We have to get the count from the dropped object because it gets changed // automatically for stacks of gold baseObject.count = ptr.getRefData().getCount(); // Get the real count of gold in a stack baseObject.goldValue = ptr.getCellRef().getGoldValue(); addBaseObject(baseObject); } void ObjectList::addObjectSpawn(const MWWorld::Ptr& ptr) { if (ptr.getCellRef().getRefId().find("$dynamic") != std::string::npos) { MWBase::Environment::get().getWindowManager()->messageBox("You're trying to spawn a custom object lacking a server-given refId, " "and those cannot be synchronized in multiplayer."); return; } cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.isSummon = false; baseObject.summonDuration = -1; // Make sure we send the RefData position instead of the CellRef one, because that's what // we actually see on this client baseObject.position = ptr.getRefData().getPosition(); addBaseObject(baseObject); } void ObjectList::addObjectSpawn(const MWWorld::Ptr& ptr, const MWWorld::Ptr& master, std::string spellId, int effectId, float duration) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.isSummon = true; baseObject.summonSpellId = spellId; baseObject.summonEffectId = effectId; baseObject.summonDuration = duration; baseObject.master = MechanicsHelper::getTarget(master); // Make sure we send the RefData position instead of the CellRef one, because that's what // we actually see on this client baseObject.position = ptr.getRefData().getPosition(); addBaseObject(baseObject); } void ObjectList::addObjectLock(const MWWorld::Ptr& ptr, int lockLevel) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.lockLevel = lockLevel; addBaseObject(baseObject); } void ObjectList::addObjectDialogueChoice(const MWWorld::Ptr& ptr, std::string dialogueChoice) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); // Because the actual text for any of the special dialogue choices can vary according to the game language used, // set the type of dialogue choice by doing a lot of checks if (dialogueChoice == gmst.find("sPersuasion")->mValue.getString()) baseObject.dialogueChoiceType = static_cast(DialogueChoiceType::PERSUASION); else if (dialogueChoice == gmst.find("sCompanionShare")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::COMPANION_SHARE; else if (dialogueChoice == gmst.find("sBarter")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::BARTER; else if (dialogueChoice == gmst.find("sSpells")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::SPELLS; else if (dialogueChoice == gmst.find("sTravel")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::TRAVEL; else if (dialogueChoice == gmst.find("sSpellMakingMenuTitle")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::SPELLMAKING; else if (dialogueChoice == gmst.find("sEnchanting")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::ENCHANTING; else if (dialogueChoice == gmst.find("sServiceTrainingTitle")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::TRAINING; else if (dialogueChoice == gmst.find("sRepair")->mValue.getString()) baseObject.dialogueChoiceType = DialogueChoiceType::REPAIR; else { baseObject.dialogueChoiceType = DialogueChoiceType::TOPIC; // For translated versions of the game, make sure we translate the topic back into English first if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) baseObject.topicId = dialogueChoice + "|" + MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().topicID(dialogueChoice); else baseObject.topicId = dialogueChoice; } addBaseObject(baseObject); } void ObjectList::addObjectMiscellaneous(const MWWorld::Ptr& ptr, unsigned int goldPool, float lastGoldRestockHour, int lastGoldRestockDay) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.goldPool = goldPool; baseObject.lastGoldRestockHour = lastGoldRestockHour; baseObject.lastGoldRestockDay = lastGoldRestockDay; addBaseObject(baseObject); } void ObjectList::addObjectTrap(const MWWorld::Ptr& ptr, const ESM::Position& pos, bool isDisarmed) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.isDisarmed = isDisarmed; baseObject.position = pos; addBaseObject(baseObject); } void ObjectList::addObjectScale(const MWWorld::Ptr& ptr, float scale) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.scale = scale; addBaseObject(baseObject); } void ObjectList::addObjectSound(const MWWorld::Ptr& ptr, std::string soundId, float volume, float pitch) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.soundId = soundId; baseObject.volume = volume; baseObject.pitch = pitch; addBaseObject(baseObject); } void ObjectList::addObjectState(const MWWorld::Ptr& ptr, bool objectState) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.objectState = objectState; addBaseObject(baseObject); } void ObjectList::addObjectAnimPlay(const MWWorld::Ptr& ptr, std::string group, int mode) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.animGroup = group; baseObject.animMode = mode; addBaseObject(baseObject); } void ObjectList::addDoorState(const MWWorld::Ptr& ptr, MWWorld::DoorState state) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); baseObject.doorState = static_cast(state); addBaseObject(baseObject); } void ObjectList::addMusicPlay(std::string filename) { mwmp::BaseObject baseObject; baseObject.musicFilename = filename; addBaseObject(baseObject); } void ObjectList::addVideoPlay(std::string filename, bool allowSkipping) { mwmp::BaseObject baseObject; baseObject.videoFilename = filename; baseObject.allowSkipping = allowSkipping; addBaseObject(baseObject); } void ObjectList::addClientScriptLocal(const MWWorld::Ptr& ptr, int internalIndex, int value, mwmp::VARIABLE_TYPE variableType) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); ClientVariable clientLocal; clientLocal.internalIndex = internalIndex; clientLocal.variableType = variableType; clientLocal.intValue = value; baseObject.clientLocals.push_back(clientLocal); addBaseObject(baseObject); } void ObjectList::addClientScriptLocal(const MWWorld::Ptr& ptr, int internalIndex, float value) { cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); ClientVariable clientLocal; clientLocal.internalIndex = internalIndex; clientLocal.variableType = mwmp::VARIABLE_TYPE::FLOAT; clientLocal.floatValue = value; baseObject.clientLocals.push_back(clientLocal); addBaseObject(baseObject); } void ObjectList::addScriptMemberShort(std::string refId, int index, int shortVal) { /* mwmp::BaseObject baseObject; baseObject.refId = refId; baseObject.index = index; baseObject.shortVal = shortVal; addBaseObject(baseObject); */ } void ObjectList::sendObjectActivate() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_ACTIVATE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_ACTIVATE)->Send(); } void ObjectList::sendObjectHit() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_HIT)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_HIT)->Send(); } void ObjectList::sendObjectPlace() { if (baseObjects.size() == 0) return; LOG_MESSAGE_SIMPLE(TimedLog::LOG_VERBOSE, "Sending ID_OBJECT_PLACE about %s", cell.getShortDescription().c_str()); for (const auto &baseObject : baseObjects) LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s, count: %i", baseObject.refId.c_str(), baseObject.count); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_PLACE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_PLACE)->Send(); } void ObjectList::sendObjectSpawn() { if (baseObjects.size() == 0) return; LOG_MESSAGE_SIMPLE(TimedLog::LOG_VERBOSE, "Sending ID_OBJECT_SPAWN about %s", cell.getShortDescription().c_str()); for (const auto &baseObject : baseObjects) LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s-%i", baseObject.refId.c_str(), baseObject.refNum); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_SPAWN)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_SPAWN)->Send(); } void ObjectList::sendObjectDelete() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_DELETE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_DELETE)->Send(); } void ObjectList::sendObjectLock() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_LOCK)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_LOCK)->Send(); } void ObjectList::sendObjectDialogueChoice() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_DIALOGUE_CHOICE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_DIALOGUE_CHOICE)->Send(); } void ObjectList::sendObjectMiscellaneous() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_MISCELLANEOUS)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_MISCELLANEOUS)->Send(); } void ObjectList::sendObjectRestock() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_RESTOCK)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_RESTOCK)->Send(); } void ObjectList::sendObjectSound() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_SOUND)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_SOUND)->Send(); } void ObjectList::sendObjectTrap() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_TRAP)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_TRAP)->Send(); } void ObjectList::sendObjectScale() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_SCALE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_SCALE)->Send(); } void ObjectList::sendObjectState() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_STATE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_STATE)->Send(); } void ObjectList::sendObjectAnimPlay() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_ANIM_PLAY)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_OBJECT_ANIM_PLAY)->Send(); } void ObjectList::sendDoorState() { LOG_MESSAGE_SIMPLE(TimedLog::LOG_VERBOSE, "Sending ID_DOOR_STATE about %s", cell.getShortDescription().c_str()); for (const auto &baseObject : baseObjects) LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s-%i, state: %s", baseObject.refId.c_str(), baseObject.refNum, baseObject.doorState ? "true" : "false"); mwmp::Main::get().getNetworking()->getObjectPacket(ID_DOOR_STATE)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_DOOR_STATE)->Send(); } void ObjectList::sendMusicPlay() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_MUSIC_PLAY)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_MUSIC_PLAY)->Send(); } void ObjectList::sendVideoPlay() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_VIDEO_PLAY)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_VIDEO_PLAY)->Send(); } void ObjectList::sendClientScriptLocal() { LOG_MESSAGE_SIMPLE(TimedLog::LOG_VERBOSE, "Sending ID_CLIENT_SCRIPT_LOCAL about %s", cell.getShortDescription().c_str()); for (const auto &baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); for (const auto& clientLocal : baseObject.clientLocals) { std::string valueAsString; std::string variableTypeAsString; if (clientLocal.variableType == mwmp::VARIABLE_TYPE::SHORT || clientLocal.variableType == mwmp::VARIABLE_TYPE::LONG) { variableTypeAsString = clientLocal.variableType == mwmp::VARIABLE_TYPE::SHORT ? "short" : "long"; valueAsString = std::to_string(clientLocal.intValue); } else if (clientLocal.variableType == mwmp::VARIABLE_TYPE::FLOAT) { variableTypeAsString = "float"; valueAsString = std::to_string(clientLocal.floatValue); } LOG_APPEND(TimedLog::LOG_VERBOSE, "- type %s, value: %s", variableTypeAsString.c_str(), valueAsString.c_str()); } } mwmp::Main::get().getNetworking()->getObjectPacket(ID_CLIENT_SCRIPT_LOCAL)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_CLIENT_SCRIPT_LOCAL)->Send(); } void ObjectList::sendScriptMemberShort() { /* LOG_MESSAGE_SIMPLE(TimedLog::LOG_VERBOSE, "Sending ID_SCRIPT_MEMBER_SHORT"); for (const auto &baseObject : baseObjects) LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s, index: %i, shortVal: %i", baseObject.refId.c_str(), baseObject.index, baseObject.shortVal); mwmp::Main::get().getNetworking()->getObjectPacket(ID_SCRIPT_MEMBER_SHORT)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_SCRIPT_MEMBER_SHORT)->Send(); */ } void ObjectList::sendContainer() { std::string debugMessage = "Sending ID_CONTAINER with action "; if (action == mwmp::BaseObjectList::SET) debugMessage += "SET"; else if (action == mwmp::BaseObjectList::ADD) debugMessage += "ADD"; else if (action == mwmp::BaseObjectList::REMOVE) debugMessage += "REMOVE"; debugMessage += " and subaction "; if (containerSubAction == mwmp::BaseObjectList::NONE) debugMessage += "NONE"; else if (containerSubAction == mwmp::BaseObjectList::DRAG) debugMessage += "DRAG"; else if (containerSubAction == mwmp::BaseObjectList::DROP) debugMessage += "DROP"; else if (containerSubAction == mwmp::BaseObjectList::TAKE_ALL) debugMessage += "TAKE_ALL"; else if (containerSubAction == mwmp::BaseObjectList::REPLY_TO_REQUEST) debugMessage += "REPLY_TO_REQUEST"; debugMessage += "\n- cell " + cell.getShortDescription(); for (const auto &baseObject : baseObjects) { debugMessage += "\n- container " + baseObject.refId + " " + std::to_string(baseObject.refNum) + "-" + std::to_string(baseObject.mpNum); for (const auto &containerItem : baseObject.containerItems) { debugMessage += "\n-- item " + containerItem.refId + ", count " + std::to_string(containerItem.count) + ", actionCount " + std::to_string(containerItem.actionCount); } } LOG_MESSAGE_SIMPLE(TimedLog::LOG_VERBOSE, "%s", debugMessage.c_str()); mwmp::Main::get().getNetworking()->getObjectPacket(ID_CONTAINER)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_CONTAINER)->Send(); } void ObjectList::sendConsoleCommand() { mwmp::Main::get().getNetworking()->getObjectPacket(ID_CONSOLE_COMMAND)->setObjectList(this); mwmp::Main::get().getNetworking()->getObjectPacket(ID_CONSOLE_COMMAND)->Send(); }