diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index aac076404..aec8c2533 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -6,6 +6,7 @@ set(LAUNCHER playpage.cpp textslotmsgbox.cpp settingspage.cpp + advancedpage.cpp utils/profilescombobox.cpp utils/textinputdialog.cpp @@ -21,6 +22,7 @@ set(LAUNCHER_HEADER playpage.hpp textslotmsgbox.hpp settingspage.hpp + advancedpage.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp @@ -35,6 +37,7 @@ set(LAUNCHER_HEADER_MOC playpage.hpp textslotmsgbox.hpp settingspage.hpp + advancedpage.hpp utils/textinputdialog.hpp utils/profilescombobox.hpp @@ -49,6 +52,7 @@ set(LAUNCHER_UI ${CMAKE_SOURCE_DIR}/files/ui/playpage.ui ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ${CMAKE_SOURCE_DIR}/files/ui/settingspage.ui + ${CMAKE_SOURCE_DIR}/files/ui/advancedpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp new file mode 100644 index 000000000..779556df7 --- /dev/null +++ b/apps/launcher/advancedpage.cpp @@ -0,0 +1,89 @@ +#include "advancedpage.hpp" + +#include + +Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent) + : QWidget(parent) + , mCfgMgr(cfg) + , mEngineSettings(engineSettings) +{ + setObjectName ("AdvancedPage"); + setupUi(this); + + loadSettings(); +} + +bool Launcher::AdvancedPage::loadSettings() +{ + // Game Settings + loadSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game"); + loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game"); + loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game"); + loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game"); + loadSettingBool(showMeleeInfoCheckBox, "show enchant chance", "Game"); + loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); + loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); + + // Expected values are (0, 1, 2, 3) + int showOwnedIndex = mEngineSettings.getInt("show owned", "Game"); + // Match the index with the option. Will default to 0 if invalid. + if (showOwnedIndex >= 0 && showOwnedIndex <= 3) + showOwnedComboBox->setCurrentIndex(showOwnedIndex); + + // Input Settings + loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); + loadSettingBool(grabCursorCheckBox, "grab cursor", "Input"); + loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input"); + + // Other Settings + loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); + + QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper(); + if (screenshotFormatComboBox->findText(screenshotFormatString) == -1) + screenshotFormatComboBox->addItem(screenshotFormatString); + screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString)); + + return true; +} + +void Launcher::AdvancedPage::saveSettings() +{ + // Ensure we only set the new settings if they changed. This is to avoid cluttering the + // user settings file (which by definition should only contain settings the user has touched) + + // Game Settings + saveSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game"); + saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game"); + saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game"); + saveSettingBool(showEffectDurationCheckBox, "show effect duration", "Game"); + saveSettingBool(showMeleeInfoCheckBox, "show enchant chance", "Game"); + saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); + saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); + + int showOwnedCurrentIndex = showOwnedComboBox->currentIndex(); + if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game")) + mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex); + + // Input Settings + saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); + saveSettingBool(grabCursorCheckBox, "grab cursor", "Input"); + saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input"); + + // Other Settings + saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); + + std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString(); + if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General")) + mEngineSettings.setString("screenshot format", "General", screenshotFormatString); +} + +void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) { + if (mEngineSettings.getBool(setting, group)) + checkbox->setCheckState(Qt::Checked); +} + +void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) { + bool cValue = checkbox->checkState(); + if (cValue != mEngineSettings.getBool(setting, group)) + mEngineSettings.setBool(setting, group, cValue); +} \ No newline at end of file diff --git a/apps/launcher/advancedpage.hpp b/apps/launcher/advancedpage.hpp new file mode 100644 index 000000000..a8361c98e --- /dev/null +++ b/apps/launcher/advancedpage.hpp @@ -0,0 +1,32 @@ +#ifndef ADVANCEDPAGE_H +#define ADVANCEDPAGE_H + +#include + +#include "ui_advancedpage.h" + +#include + +namespace Files { struct ConfigurationManager; } + +namespace Launcher +{ + class AdvancedPage : public QWidget, private Ui::AdvancedPage + { + Q_OBJECT + + public: + AdvancedPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent = 0); + + bool loadSettings(); + void saveSettings(); + + private: + Files::ConfigurationManager &mCfgMgr; + Settings::Manager &mEngineSettings; + + void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group); + void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group); + }; +} +#endif diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 10f3ae81b..00552de13 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -2,9 +2,7 @@ #include -#include #include -#include #include #include #include @@ -12,8 +10,6 @@ #include #include #include -#include -#include #include @@ -21,6 +17,7 @@ #include "graphicspage.hpp" #include "datafilespage.hpp" #include "settingspage.hpp" +#include "advancedpage.hpp" using namespace Process; @@ -104,6 +101,12 @@ void Launcher::MainDialog::createIcons() settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + QListWidgetItem *advancedButton = new QListWidgetItem(iconWidget); + advancedButton->setIcon(QIcon::fromTheme("emblem-system")); + advancedButton->setText(tr("Advanced")); + advancedButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); + advancedButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + connect(iconWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); @@ -116,6 +119,7 @@ void Launcher::MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); mGraphicsPage = new GraphicsPage(mCfgMgr, mEngineSettings, this); mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this); + mAdvancedPage = new AdvancedPage(mCfgMgr, mEngineSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage mPlayPage->setProfilesModel(mDataFilesPage->profilesModel()); @@ -126,6 +130,7 @@ void Launcher::MainDialog::createPages() pagesWidget->addWidget(mDataFilesPage); pagesWidget->addWidget(mGraphicsPage); pagesWidget->addWidget(mSettingsPage); + pagesWidget->addWidget(mAdvancedPage); // Select the first page iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select); @@ -245,6 +250,9 @@ bool Launcher::MainDialog::reloadSettings() if (!mGraphicsPage->loadSettings()) return false; + if (!mAdvancedPage->loadSettings()) + return false; + return true; } @@ -483,6 +491,7 @@ bool Launcher::MainDialog::writeSettings() mDataFilesPage->saveSettings(); mGraphicsPage->saveSettings(); mSettingsPage->saveSettings(); + mAdvancedPage->saveSettings(); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QDir dir(userPath); diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 8d0d61b8f..6d3871b7c 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -30,6 +30,7 @@ namespace Launcher class DataFilesPage; class UnshieldThread; class SettingsPage; + class AdvancedPage; enum FirstRunDialogResult { @@ -88,6 +89,7 @@ namespace Launcher GraphicsPage *mGraphicsPage; DataFilesPage *mDataFilesPage; SettingsPage *mSettingsPage; + AdvancedPage *mAdvancedPage; Process::ProcessInvoker *mGameInvoker; Process::ProcessInvoker *mWizardInvoker; diff --git a/apps/openmw-mp/Player.cpp b/apps/openmw-mp/Player.cpp index 6ed464870..de1bcf862 100644 --- a/apps/openmw-mp/Player.cpp +++ b/apps/openmw-mp/Player.cpp @@ -61,6 +61,7 @@ void Player::Init(LuaState &lua) "hair", sol::property(&Player::getHair, &Player::setHair), "birthsign", sol::property(&Player::getBirthsign, &Player::setBirthsign), "bounty", sol::property(&Player::getBounty, &Player::setBounty), + "reputation", sol::property(&Player::getReputation, &Player::setReputation), "levelProgress", sol::property(&Player::getLevelProgress, &Player::setLevelProgress), "creatureModel", sol::property(&Player::getCreatureModel, &Player::setCreatureModel), "isCreatureName", sol::property(&Player::isCreatureName, &Player::creatureName), @@ -89,10 +90,18 @@ void Player::Init(LuaState &lua) "getQuickKeys", &Player::getQuickKeys, "getWeatherMgr", &Player::getWeatherMgr, + "getMarkPosition", &Player::getMarkPosition, + "setMarkPosition", &Player::setMarkPosition, + "getMarkRotation", &Player::getMarkRotation, + "setMarkRotation", &Player::setMarkRotation, + "getMarkCell", &Player::getMarkCell, + "setMarkCell", &Player::setMarkCell, + "getCellState", &Player::getCellState, "cellStateSize", &Player::cellStateSize, "addCellExplored", &Player::addCellExplored, "setAuthority", &Player::setAuthority, + "storedData", &Player::storedData, "customData", &Player::customData, "markedForDeletion", sol::property(&Player::isMarkedForDeleteion) @@ -115,11 +124,15 @@ Player::Player(RakNet::RakNetGUID guid) : BasePlayer(guid), NetActor(), changedM handshakeCounter = 0; loadState = NOTLOADED; resetUpdateFlags(); + cell.blank(); npc.blank(); npcStats.blank(); creatureStats.blank(); charClass.blank(); + scale = 1; + isWerewolf = false; + markedForDeletion = false; storedData = mwmp::Networking::get().getState().getState()->create_table(); customData = mwmp::Networking::get().getState().getState()->create_table(); @@ -227,6 +240,24 @@ void Player::update() inventory.resetInventoryFlag(); } + if (changedMarkLocation) + { + miscellaneousChangeType = mwmp::MiscellaneousChangeType::MarkLocation; + auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MISCELLANEOUS); + packet->setPlayer(this); + packet->Send(false); + changedMarkLocation = false; + } + + if (changedSelectedSpell) + { + miscellaneousChangeType = mwmp::MiscellaneousChangeType::SelectedSpell; + auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MISCELLANEOUS); + packet->setPlayer(this); + packet->Send(false); + changedSelectedSpell = false; + } + if (changedMap) { auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MAP); @@ -610,6 +641,22 @@ void Player::setBounty(int bounty) packet->Send(true); } +int Player::getReputation() const +{ + return npcStats.mReputation; +} + +void Player::setReputation(int reputation, bool toOthers) +{ + npcStats.mReputation = reputation; + auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_REPUTATION); + packet->setPlayer(this); + packet->Send(false); + + if (toOthers) + packet->Send(true); +} + int Player::getLevelProgress() const { return npcStats.mLevelProgress; @@ -806,6 +853,70 @@ void Player::setWerewolfState(bool state) packet->Send(true); } +float Player::getScale() const +{ + return scale; +} + +void Player::setScale(float newScale) +{ + scale = newScale; + + auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SHAPESHIFT); + packet->setPlayer(this); + packet->Send(false); + packet->Send(true); +} + +std::tuple Player::getMarkPosition() +{ + return make_tuple(markPosition.pos[0], markPosition.pos[1], markPosition.pos[2]); +} + +void Player::setMarkPosition(float x, float y, float z) +{ + markPosition.pos[0] = x; + markPosition.pos[1] = y; + markPosition.pos[2] = z; + + changedMarkLocation = true; +} + +std::tuple Player::getMarkRotation() +{ + return make_tuple(markPosition.rot[0], markPosition.rot[2]); +} + +void Player::setMarkRotation(float x, float z) +{ + markPosition.rot[0] = x; + markPosition.rot[2] = z; + + changedMarkLocation = true; +} + +std::string Player::getMarkCell() +{ + return markCell.getDescription(); +} + +void Player::setMarkCell(const std::string &cellDescription) +{ + markCell = Utils::getCellFromDescription(cellDescription); + changedMarkLocation = true; +} + +std::string Player::getSelectedSpell() +{ + return selectedSpellId; +} + +void Player::setSelectedSpell(const std::string &newSelectedSpell) +{ + selectedSpellId = newSelectedSpell; + changedSelectedSpell = true; +} + size_t Player::cellStateSize() const { return cellStateChanges.cellStates.size(); diff --git a/apps/openmw-mp/Player.hpp b/apps/openmw-mp/Player.hpp index cdb9879b8..682d5c921 100644 --- a/apps/openmw-mp/Player.hpp +++ b/apps/openmw-mp/Player.hpp @@ -104,6 +104,9 @@ public: int getBounty() const; void setBounty(int bounty); + int getReputation() const; + void setReputation(int reputation, bool toOthers); + int getLevel() const; void setLevel(int level); int getLevelProgress() const; @@ -142,6 +145,9 @@ public: bool getWerewolfState() const; void setWerewolfState(bool state); + float getScale() const; + void setScale(float newScale); + std::string getCreatureModel() const; void setCreatureModel(const std::string &model); void creatureName(bool useName); @@ -172,6 +178,16 @@ public: int getSkillIncrease(unsigned short attributeId) const; void setSkillIncrease(unsigned short attributeId, int increase); + std::tuple getMarkPosition(); + void setMarkPosition(float x, float y, float z); + std::tuple getMarkRotation(); + void setMarkRotation(float x, float z); + std::string getMarkCell(); + void setMarkCell(const std::string &cellDescription); + + std::string getSelectedSpell(); + void setSelectedSpell(const std::string &newSelectedSpellId); + CellState getCellState(int i); size_t cellStateSize() const; void addCellExplored(const std::string &cellDescription); @@ -197,7 +213,7 @@ private: CellController::TContainer cells; int handshakeCounter; int loadState; - bool /*statsChanged, attributesChanged, skillsChanged, baseInfoChanged, positionChanged,*/ changedMap; + bool /*statsChanged, attributesChanged, skillsChanged, baseInfoChanged, positionChanged,*/ changedMarkLocation, changedSelectedSpell, changedMap; CharClass cClass; GameSettings settings; Books books; diff --git a/apps/openmw-mp/Script/EventController.cpp b/apps/openmw-mp/Script/EventController.cpp index 531694cc2..a46759a4b 100644 --- a/apps/openmw-mp/Script/EventController.cpp +++ b/apps/openmw-mp/Script/EventController.cpp @@ -69,6 +69,7 @@ EventController::EventController(LuaState *luaCtrl) ADD_CORE_EVENT(ON_PLAYER_SENDMESSAGE), ADD_CORE_EVENT(ON_PLAYER_ENDCHARGEN), ADD_CORE_EVENT(ON_PLAYER_WEATHER), + ADD_CORE_EVENT(ON_RECORD_DYNAMIC), ADD_CORE_EVENT(ON_CHANNEL_ACTION), ADD_CORE_EVENT(ON_GUI_ACTION), ADD_CORE_EVENT(ON_REQUEST_PLUGIN_LIST), diff --git a/apps/openmw-mp/Script/EventController.hpp b/apps/openmw-mp/Script/EventController.hpp index 1091bae20..a51f3f819 100644 --- a/apps/openmw-mp/Script/EventController.hpp +++ b/apps/openmw-mp/Script/EventController.hpp @@ -46,6 +46,8 @@ namespace CoreEvent ON_PLAYER_ENDCHARGEN, ON_PLAYER_WEATHER, + ON_RECORD_DYNAMIC, + ON_CHANNEL_ACTION, ON_GUI_ACTION, diff --git a/apps/openmw-mp/processors/ProcessorInitializer.cpp b/apps/openmw-mp/processors/ProcessorInitializer.cpp index 9547045aa..afea052d1 100644 --- a/apps/openmw-mp/processors/ProcessorInitializer.cpp +++ b/apps/openmw-mp/processors/ProcessorInitializer.cpp @@ -11,6 +11,7 @@ #include "player/ProcessorGUIMessageBox.hpp" #include "player/ProcessorGUIWindow.hpp" #include "player/ProcessorGameWeather.hpp" +#include "player/ProcessorRecordDynamic.hpp" #include "player/ProcessorPlayerCharGen.hpp" #include "player/ProcessorPlayerAnimFlags.hpp" #include "player/ProcessorPlayerAnimPlay.hpp" @@ -28,10 +29,13 @@ #include "player/ProcessorPlayerInventory.hpp" #include "player/ProcessorPlayerJournal.hpp" #include "player/ProcessorPlayerKillCount.hpp" +#include "player/ProcessorPlayerInteraction.hpp" #include "player/ProcessorPlayerLevel.hpp" #include "player/ProcessorPlayerMap.hpp" +#include "player/ProcessorPlayerMiscellaneous.hpp" #include "player/ProcessorPlayerPosition.hpp" #include "player/ProcessorPlayerQuickKeys.hpp" +#include "player/ProcessorPlayerReputation.hpp" #include "player/ProcessorPlayerRest.hpp" #include "player/ProcessorPlayerResurrect.hpp" #include "player/ProcessorPlayerShapeshift.hpp" @@ -50,6 +54,7 @@ #include "actor/ProcessorActorCellChange.hpp" #include "actor/ProcessorActorDeath.hpp" #include "actor/ProcessorActorEquipment.hpp" +#include "actor/ProcessorActorInteraction.hpp" #include "actor/ProcessorActorStatsDynamic.hpp" #include "actor/ProcessorActorPosition.hpp" #include "actor/ProcessorActorSpeech.hpp" @@ -70,7 +75,9 @@ #include "world/ProcessorScriptLocalShort.hpp" #include "world/ProcessorScriptLocalFloat.hpp" #include "world/ProcessorScriptMemberShort.hpp" +#include "world/ProcessorScriptMemberFloat.hpp" #include "world/ProcessorScriptGlobalShort.hpp" +#include "world/ProcessorScriptGlobalFloat.hpp" #include "world/ProcessorVideoPlay.hpp" @@ -82,6 +89,7 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorGUIMessageBox()); PlayerProcessor::AddProcessor(new ProcessorGUIWindow()); PlayerProcessor::AddProcessor(new ProcessorGameWeather()); + PlayerProcessor::AddProcessor(new ProcessorRecordDynamic()); PlayerProcessor::AddProcessor(new ProcessorPlayerCharGen()); PlayerProcessor::AddProcessor(new ProcessorPlayerAnimFlags()); PlayerProcessor::AddProcessor(new ProcessorPlayerAnimPlay()); @@ -99,10 +107,13 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorPlayerInventory()); PlayerProcessor::AddProcessor(new ProcessorPlayerJournal()); PlayerProcessor::AddProcessor(new ProcessorPlayerKillCount()); + PlayerProcessor::AddProcessor(new ProcessorPlayerInteraction()); PlayerProcessor::AddProcessor(new ProcessorPlayerLevel()); PlayerProcessor::AddProcessor(new ProcessorPlayerMap()); + PlayerProcessor::AddProcessor(new ProcessorPlayerMiscellaneous()); PlayerProcessor::AddProcessor(new ProcessorPlayerPosition()); PlayerProcessor::AddProcessor(new ProcessorPlayerQuickKeys()); + PlayerProcessor::AddProcessor(new ProcessorPlayerReputation()); PlayerProcessor::AddProcessor(new ProcessorPlayerRest()); PlayerProcessor::AddProcessor(new ProcessorPlayerResurrect()); PlayerProcessor::AddProcessor(new ProcessorPlayerShapeshift()); @@ -120,6 +131,7 @@ void ProcessorInitializer() ActorProcessor::AddProcessor(new ProcessorActorCellChange()); ActorProcessor::AddProcessor(new ProcessorActorDeath()); ActorProcessor::AddProcessor(new ProcessorActorEquipment()); + ActorProcessor::AddProcessor(new ProcessorActorInteraction()); ActorProcessor::AddProcessor(new ProcessorActorPosition()); ActorProcessor::AddProcessor(new ProcessorActorSpeech()); ActorProcessor::AddProcessor(new ProcessorActorStatsDynamic()); @@ -141,6 +153,8 @@ void ProcessorInitializer() WorldProcessor::AddProcessor(new ProcessorScriptLocalShort()); WorldProcessor::AddProcessor(new ProcessorScriptLocalFloat()); WorldProcessor::AddProcessor(new ProcessorScriptMemberShort()); + WorldProcessor::AddProcessor(new ProcessorScriptMemberFloat()); WorldProcessor::AddProcessor(new ProcessorScriptGlobalShort()); + WorldProcessor::AddProcessor(new ProcessorScriptGlobalFloat()); WorldProcessor::AddProcessor(new ProcessorVideoPlay()); } diff --git a/apps/openmw-mp/processors/actor/ProcessorActorInteraction.hpp b/apps/openmw-mp/processors/actor/ProcessorActorInteraction.hpp index 2bd6811e8..10a71bc6c 100644 --- a/apps/openmw-mp/processors/actor/ProcessorActorInteraction.hpp +++ b/apps/openmw-mp/processors/actor/ProcessorActorInteraction.hpp @@ -16,7 +16,7 @@ namespace mwmp void Do(ActorPacket &packet, const std::shared_ptr &player, BaseActorList &actorList) override { // Send only to players who have the cell loaded - Cell *serverCell = CellController::get().getCell(&actorList.cell); + Cell *serverCell = CellController::get().getCell(actorList.cell); if (serverCell != nullptr && *serverCell->getAuthority() == actorList.guid) serverCell->sendToLoaded(&packet, &actorList); diff --git a/apps/openmw-mp/processors/player/ProcessorRecordDynamic.hpp b/apps/openmw-mp/processors/player/ProcessorRecordDynamic.hpp index 9be6a75c1..14838fe06 100644 --- a/apps/openmw-mp/processors/player/ProcessorRecordDynamic.hpp +++ b/apps/openmw-mp/processors/player/ProcessorRecordDynamic.hpp @@ -1,14 +1,14 @@ -#ifndef OPENMW_PROCESSORPLAYERRECORDDYNAMIC_HPP -#define OPENMW_PROCESSORPLAYERRECORDDYNAMIC_HPP +#ifndef OPENMW_PROCESSORRECORDDYNAMIC_HPP +#define OPENMW_PROCESSORRECORDDYNAMIC_HPP #include "../PlayerProcessor.hpp" namespace mwmp { - class ProcessorPlayerRecordDynamic final : public PlayerProcessor + class ProcessorRecordDynamic final : public PlayerProcessor { public: - ProcessorPlayerRecordDynamic() + ProcessorRecordDynamic() { BPP_INIT(ID_RECORD_DYNAMIC) } @@ -17,9 +17,9 @@ namespace mwmp { DEBUG_PRINTF(strPacketID.c_str()); - Script::Call(player.getId()); + Networking::get().getState().getEventCtrl().Call(player); } }; } -#endif //OPENMW_PROCESSORPLAYERRECORDDYNAMIC_HPP +#endif //OPENMW_PROCESSORRECORDDYNAMIC_HPP diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 1c90d1503..97c57ad65 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -232,7 +232,8 @@ namespace MWGui /* Start of tes3mp addition - Send a PLAYER_QUICKKEYS packet whenever a key is assigned to an item + Send a PlayerQuickKeys packet whenever a key is assigned to an item + by a player, not by a packet received from the server */ if (!mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys) mwmp::Main::get().getLocalPlayer()->sendQuickKey(mSelectedIndex, mwmp::QuickKey::Type::Item, item.getCellRef().getRefId()); @@ -407,6 +408,16 @@ namespace MWGui store.setSelectedEnchantItem(store.end()); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); + + /* + Start of tes3mp addition + + Send a PlayerMiscellaneous packet with the player's new selected spell + */ + mwmp::Main::get().getLocalPlayer()->sendSelectedSpell(spellId); + /* + End of tes3mp addition + */ } else if (type == Type_Item) { diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 1f9e65624..bc35929a7 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -186,6 +186,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); + + /* + Start of tes3mp addition + + Send a PlayerMiscellaneous packet with the player's new selected spell + */ + mwmp::Main::get().getLocalPlayer()->sendSelectedSpell(spellId); + /* + End of tes3mp addition + */ } void SpellWindow::onDeleteSpellAccept() diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7d1c80652..5c203ab9b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -186,10 +186,25 @@ namespace MWInput } } + bool isLeftOrRightButton(int action, ICS::InputControlSystem* ics, int deviceId, bool joystick) + { + int mouseBinding = ics->getMouseButtonBinding(ics->getControl(action), ICS::Control::INCREASE); + if (mouseBinding != ICS_MAX_DEVICE_BUTTONS) + return true; + int buttonBinding = ics->getJoystickButtonBinding(ics->getControl(action), deviceId, ICS::Control::INCREASE); + if (joystick && (buttonBinding == 0 || buttonBinding == 1)) + return true; + return false; + } + void InputManager::handleGuiArrowKey(int action) { if (SDL_IsTextInputActive()) return; + + if (isLeftOrRightButton(action, mInputBinder, mFakeDeviceID, mJoystickLastUsed)) + return; + MyGUI::KeyCode key; switch (action) { @@ -1185,7 +1200,7 @@ namespace MWInput { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (!SDL_IsTextInputActive()) + if (!SDL_IsTextInputActive() && !isLeftOrRightButton(A_Activate, mInputBinder, mFakeDeviceID, mJoystickLastUsed)) MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); } else if (mControlSwitch["playercontrols"]) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ce1e67b89..1b32a6f7c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -579,9 +579,16 @@ namespace MWMechanics { std::string itFaction = playerFactionIt->first; + // Ignore the faction, if a player was expelled from it. + if (playerStats.getExpelled(itFaction)) + continue; + int itReaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction); if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction) + { reaction = static_cast(itReaction); + rank = playerFactionIt->second; + } } } else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 27c83249e..381a1047c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -755,6 +755,17 @@ namespace MWMechanics { MWBase::Environment::get().getWorld()->getPlayer().markPosition( target.getCell(), target.getRefData().getPosition()); + + /* + Start of tes3mp addition + + Send a PlayerMiscellaneous packet with the player's new mark location + */ + mwmp::Main::get().getLocalPlayer()->sendMarkLocation(*target.getCell()->getCell(), target.getRefData().getPosition()); + /* + End of tes3mp addition + */ + return true; } else if (effectId == ESM::MagicEffect::Recall) diff --git a/apps/openmw/mwmp/CellController.cpp b/apps/openmw/mwmp/CellController.cpp index a99a1d279..b57ad0ed4 100644 --- a/apps/openmw/mwmp/CellController.cpp +++ b/apps/openmw/mwmp/CellController.cpp @@ -364,7 +364,6 @@ void CellController::openContainer(const MWWorld::Ptr &container) /*if (::Misc::StringUtils::ciEqual(name, "gold_001")) cont.remove("gold_001", count, container);*/ } - } void CellController::closeContainer(const MWWorld::Ptr &container) diff --git a/apps/openmw/mwmp/DedicatedPlayer.cpp b/apps/openmw/mwmp/DedicatedPlayer.cpp index 88947e19c..a945ba148 100644 --- a/apps/openmw/mwmp/DedicatedPlayer.cpp +++ b/apps/openmw/mwmp/DedicatedPlayer.cpp @@ -242,6 +242,7 @@ void DedicatedPlayer::setCell() void DedicatedPlayer::setShapeshift() { + MWBase::Environment::get().getWorld()->scaleObject(ptr, scale); MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, isWerewolf); } diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 50caa315d..0646fca46 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp" +#include "../mwmechanics/spellcasting.hpp" #include "../mwscript/scriptmanagerimp.hpp" @@ -65,6 +66,7 @@ LocalPlayer::LocalPlayer() jailProgressText = ""; jailEndText = ""; + scale = 1; isWerewolf = false; diedSinceArrestAttempt = false; @@ -106,6 +108,7 @@ void LocalPlayer::update() updateSkills(); updateLevel(); updateBounty(); + updateReputation(); } } @@ -322,6 +325,19 @@ void LocalPlayer::updateBounty(bool forceUpdate) } } +void LocalPlayer::updateReputation(bool forceUpdate) +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + const MWMechanics::NpcStats &ptrNpcStats = ptrPlayer.getClass().getNpcStats(ptrPlayer); + + if (ptrNpcStats.getReputation() != npcStats.mReputation || forceUpdate) + { + npcStats.mReputation = ptrNpcStats.getReputation(); + getNetworking()->getPlayerPacket(ID_PLAYER_REPUTATION)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_REPUTATION)->Send(); + } +} + void LocalPlayer::updatePosition(bool forceUpdate) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -920,6 +936,15 @@ void LocalPlayer::setBounty() ptrNpcStats->setBounty(npcStats.mBounty); } +void LocalPlayer::setReputation() +{ + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr ptrPlayer = world->getPlayerPtr(); + + MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer); + ptrNpcStats->setReputation(npcStats.mReputation); +} + void LocalPlayer::setPosition() { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1235,9 +1260,33 @@ void LocalPlayer::setMapExplored() void LocalPlayer::setShapeshift() { MWWorld::Ptr ptrPlayer = getPlayerPtr(); + + MWBase::Environment::get().getWorld()->scaleObject(ptrPlayer, scale); MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptrPlayer, isWerewolf); } +void LocalPlayer::setMarkLocation() +{ + MWWorld::CellStore *ptrCellStore = Main::get().getCellController()->getCellStore(markCell); + + if (ptrCellStore) + MWBase::Environment::get().getWorld()->getPlayer().markPosition(ptrCellStore, markPosition); +} + +void LocalPlayer::setSelectedSpell() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + + MWMechanics::CreatureStats& stats = ptrPlayer.getClass().getCreatureStats(ptrPlayer); + MWMechanics::Spells& spells = stats.getSpells(); + + if (!spells.hasSpell(selectedSpellId)) + return; + + MWBase::Environment::get().getWindowManager()->setSelectedSpell(selectedSpellId, + int(MWMechanics::getSpellSuccessChance(selectedSpellId, ptrPlayer))); +} + void LocalPlayer::sendClass() { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1367,7 +1416,7 @@ void LocalPlayer::sendSpellRemoval(const ESM::Spell &spell) */ } -void LocalPlayer::sendQuickKey(int slot, QuickKey::Type type, const std::string& itemId) +void LocalPlayer::sendQuickKey(unsigned short slot, QuickKey::Type type, const std::string& itemId) { quickKeyChanges.quickKeys.clear(); @@ -1512,7 +1561,17 @@ void LocalPlayer::sendBook(const std::string& bookId) getNetworking()->getPlayerPacket(ID_PLAYER_BOOK)->Send(); } -void LocalPlayer::sendShapeshift(bool werewolfState) +void LocalPlayer::sendScale(float newScale) +{ + scale = newScale; + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_PLAYER_SHAPESHIFT with scale of %f", scale); + + getNetworking()->getPlayerPacket(ID_PLAYER_SHAPESHIFT)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_SHAPESHIFT)->Send(); +} + +void LocalPlayer::sendWerewolfState(bool werewolfState) { isWerewolf = werewolfState; @@ -1522,6 +1581,25 @@ void LocalPlayer::sendShapeshift(bool werewolfState) getNetworking()->getPlayerPacket(ID_PLAYER_SHAPESHIFT)->Send(); } +void LocalPlayer::sendMarkLocation(const ESM::Cell& newMarkCell, const ESM::Position& newMarkPosition) +{ + miscellaneousChangeType = mwmp::MiscellaneousChangeType::MarkLocation; + markCell = newMarkCell; + markPosition = newMarkPosition; + + getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->Send(); +} + +void LocalPlayer::sendSelectedSpell(const std::string& newSelectedSpellId) +{ + miscellaneousChangeType = mwmp::MiscellaneousChangeType::SelectedSpell; + selectedSpellId = newSelectedSpellId; + + getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->Send(); +} + void LocalPlayer::clearCellStates() { cellStateChanges.cellStates.clear(); diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 3584e49c8..57b8b2440 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -29,6 +29,7 @@ namespace mwmp void updateSkills(bool forceUpdate = false); void updateLevel(bool forceUpdate = false); void updateBounty(bool forceUpdate = false); + void updateReputation(bool forceUpdate = false); void updatePosition(bool forceUpdate = false); void updateCell(bool forceUpdate = false); void updateChar(); @@ -55,6 +56,7 @@ namespace mwmp void setSkills(); void setLevel(); void setBounty(); + void setReputation(); void setPosition(); void setCell(); void setClass(); @@ -67,16 +69,18 @@ namespace mwmp void setBooks(); void setMapExplored(); void setShapeshift(); + void setMarkLocation(); + void setSelectedSpell(); void sendClass(); void sendInventory(); void sendSpellbook(); void sendCellStates(); void sendSpellAddition(std::string id); - void sendSpellAddition(const ESM::Spell &spell); + void sendSpellAddition(const ESM::Spell& spell); void sendSpellRemoval(std::string id); - void sendSpellRemoval(const ESM::Spell &spell); - void sendQuickKey(int slot, QuickKey::Type type, const std::string& itemId = ""); + void sendSpellRemoval(const ESM::Spell& spell); + void sendQuickKey(unsigned short slot, QuickKey::Type type, const std::string& itemId = ""); void sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor); void sendJournalIndex(const std::string& quest, int index); void sendFactionRank(const std::string& factionId, int rank); @@ -85,7 +89,10 @@ namespace mwmp void sendTopic(const std::string& topic); void sendKill(const std::string& refId, int number); void sendBook(const std::string& bookId); - void sendShapeshift(bool isWerewolf); + void sendScale(float newScale); + void sendWerewolfState(bool isWerewolf); + void sendMarkLocation(const ESM::Cell& newMarkCell, const ESM::Position& newMarkPosition); + void sendSelectedSpell(const std::string& newSelectedSpellId); void clearCellStates(); void clearCurrentContainer(); diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index 40fd7b9a6..299b01448 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -166,26 +166,35 @@ void WorldEvent::placeObjects(MWWorld::CellStore* cellStore) // Only create this object if it doesn't already exist if (!ptrFound) { - MWWorld::ManualRef ref(world->getStore(), worldObject.refId, 1); - MWWorld::Ptr newPtr = ref.getPtr(); + try + { + MWWorld::ManualRef ref(world->getStore(), worldObject.refId, 1); - if (worldObject.count > 1) - newPtr.getRefData().setCount(worldObject.count); + MWWorld::Ptr newPtr = ref.getPtr(); - if (worldObject.charge > -1) - newPtr.getCellRef().setCharge(worldObject.charge); + if (worldObject.count > 1) + newPtr.getRefData().setCount(worldObject.count); - if (worldObject.enchantmentCharge > -1.0f) - newPtr.getCellRef().setEnchantmentCharge(worldObject.enchantmentCharge); + if (worldObject.charge > -1) + newPtr.getCellRef().setCharge(worldObject.charge); - newPtr.getCellRef().setGoldValue(worldObject.goldValue); - newPtr = world->placeObject(newPtr, cellStore, worldObject.position); + if (worldObject.enchantmentCharge > -1.0f) + newPtr.getCellRef().setEnchantmentCharge(worldObject.enchantmentCharge); - // Because gold automatically gets replaced with a new object, make sure we set the mpNum at the end - newPtr.getCellRef().setMpNum(worldObject.mpNum); + newPtr.getCellRef().setGoldValue(worldObject.goldValue); + newPtr = world->placeObject(newPtr, cellStore, worldObject.position); - if (guid == Main::get().getLocalPlayer()->guid && worldObject.droppedByPlayer) - world->PCDropped(newPtr); + // Because gold automatically gets replaced with a new object, make sure we set the mpNum at the end + newPtr.getCellRef().setMpNum(worldObject.mpNum); + + if (guid == Main::get().getLocalPlayer()->guid && worldObject.droppedByPlayer) + world->PCDropped(newPtr); + + } + catch (std::exception&) + { + LOG_APPEND(Log::LOG_INFO, "-- Ignored placement of invalid object"); + } } else LOG_APPEND(Log::LOG_VERBOSE, "-- Object already existed!"); @@ -468,24 +477,20 @@ void WorldEvent::runConsoleCommands(MWWorld::CellStore* cellStore) if (worldObject.isPlayer) { - BasePlayer *player = 0; - if (worldObject.guid == Main::get().getLocalPlayer()->guid) { - player = Main::get().getLocalPlayer(); - LOG_APPEND(Log::LOG_VERBOSE, "-- running on local player"); - windowManager->setConsolePtr(static_cast(player)->getPlayerPtr()); + windowManager->setConsolePtr(Main::get().getLocalPlayer()->getPlayerPtr()); windowManager->executeCommandInConsole(consoleCommand); } else { - player = PlayerList::getPlayer(worldObject.guid); + DedicatedPlayer *player = PlayerList::getPlayer(worldObject.guid); if (player != 0) { LOG_APPEND(Log::LOG_VERBOSE, "-- running on player %s", player->npc.mName.c_str()); - windowManager->setConsolePtr(static_cast(player)->getPtr()); + windowManager->setConsolePtr(player->getPtr()); windowManager->executeCommandInConsole(consoleCommand); } } @@ -508,7 +513,7 @@ void WorldEvent::runConsoleCommands(MWWorld::CellStore* cellStore) } windowManager->clearConsolePtr(); - } + } } void WorldEvent::setLocalShorts(MWWorld::CellStore* cellStore) diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp index 62e365459..8845ab393 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerMiscellaneous.hpp @@ -23,7 +23,16 @@ namespace mwmp if (!isRequest()) { LocalPlayer &localPlayer = static_cast(*player); - //localPlayer.setMiscellaneous(); + + switch (player->miscellaneousChangeType) + { + case MiscellaneousChangeType::MarkLocation: + localPlayer.setMarkLocation(); + break; + case MiscellaneousChangeType::SelectedSpell: + localPlayer.setSelectedSpell(); + break; + } } } }; diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerReputation.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerReputation.hpp index bb8d633f1..4911bbdfc 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerReputation.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerReputation.hpp @@ -16,19 +16,13 @@ namespace mwmp virtual void Do(PlayerPacket &packet, BasePlayer *player) { - if (isLocal()) + if (isRequest()) { - //if (isRequest()) - // static_cast(player)->updateReputation(true); - //else - // static_cast(player)->setReputation(); + static_cast(player)->updateReputation(true); } else if (player != 0) { - MWWorld::Ptr ptrPlayer = static_cast(player)->getPtr(); - MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer); - - ptrNpcStats->setReputation(player->npcStats.mReputation); + static_cast(player)->setReputation(); } } }; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6c599fc3f..2e4329f69 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1203,6 +1203,18 @@ void SkyManager::create() mCreated = true; } +class RainCounter : public osgParticle::ConstantRateCounter +{ +public: + virtual int numParticlesToCreate(double dt) const + { + // limit dt to avoid large particle emissions if there are jumps in the simulation time + // 0.2 seconds is the same cap as used in Engine's frame loop + dt = std::min(dt, 0.2); + return ConstantRateCounter::numParticlesToCreate(dt); + } +}; + class RainShooter : public osgParticle::Shooter { public: @@ -1473,7 +1485,7 @@ void SkyManager::createRain() placer->setZRange(300, 300); emitter->setPlacer(placer); - osg::ref_ptr counter (new osgParticle::ConstantRateCounter); + osg::ref_ptr counter (new RainCounter); counter->setNumberOfParticlesPerSecondToCreate(600.0); emitter->setCounter(counter); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 17ae6b304..c3618aa9e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1231,7 +1231,7 @@ namespace MWScript When the player's werewolf state changes, send an ID_PLAYER_SHAPESHIFT packet */ if (ptr == MWMechanics::getPlayer()) - mwmp::Main::get().getLocalPlayer()->sendShapeshift(set); + mwmp::Main::get().getLocalPlayer()->sendWerewolfState(set); /* End of tes3mp addition */ diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index ea0531fea..874cbe1b7 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -8,6 +8,8 @@ #include #include "../mwmp/Main.hpp" #include "../mwmp/Networking.hpp" +#include "../mwmp/LocalPlayer.hpp" +#include "../mwmp/PlayerList.hpp" #include "../mwmp/WorldEvent.hpp" /* End of tes3mp addition @@ -57,16 +59,26 @@ namespace MWScript /* Start of tes3mp addition - Send an ID_OBJECT_SCALE every time an object's scale is changed - through a script - */ - if (ptr.isInCell() && (ptr.getCellRef().getScale() != scale)) - { + Send an ID_PLAYER_SHAPESHIFT every time a player changes + their own scale - mwmp::WorldEvent *worldEvent = mwmp::Main::get().getNetworking()->getWorldEvent(); - worldEvent->reset(); - worldEvent->addObjectScale(ptr, scale); - worldEvent->sendObjectScale(); + Otherwise, send an ID_OBJECT_SCALE every time an object's + scale is changed through a script + */ + if (ptr == MWMechanics::getPlayer()) + mwmp::Main::get().getLocalPlayer()->sendScale(scale); + else if (ptr.isInCell() && (ptr.getCellRef().getScale() != scale)) + { + // Ignore attempts to change another player's scale + if (mwmp::PlayerList::isDedicatedPlayer(ptr)) + return; + else + { + mwmp::WorldEvent *worldEvent = mwmp::Main::get().getNetworking()->getWorldEvent(); + worldEvent->reset(); + worldEvent->addObjectScale(ptr, scale); + worldEvent->sendObjectScale(); + } } /* End of tes3mp addition diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 640d90e23..843d5e00b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -168,16 +168,16 @@ namespace MWWorld ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, const std::string& resourcePath, const std::string& userDataPath) - : mResourceSystem(resourceSystem), mFallback(fallbackMap), mPlayer (0), mLocalScripts (mStore), + : mResourceSystem(resourceSystem), mFallback(fallbackMap), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), mUserDataPath(userDataPath), mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript), mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true), mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0), mSpellPreloadTimer(0.f) { - mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); - mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath); - mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering, mPhysics)); + mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode)); + mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath)); + mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get())); mRendering->preloadCommonAssets(); @@ -209,10 +209,10 @@ namespace MWWorld mSwimHeightScale = mStore.get().find("fSwimHeightScale")->getFloat(); - mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); - mwmp::Main::get().setWeatherManager(mWeatherManager); + mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mFallback, mStore)); + mwmp::Main::get().setWeatherManager(mWeatherManager.get()); - mWorldScene = new Scene(*mRendering, mPhysics); + mWorldScene.reset(new Scene(*mRendering.get(), mPhysics.get())); } void World::fillGlobalVariables() @@ -245,9 +245,9 @@ namespace MWWorld // we don't want old weather to persist on a new game // Note that if reset later, the initial ChangeWeather that the chargen script calls will be lost. - delete mWeatherManager; - mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); - mwmp::Main::get().setWeatherManager(mWeatherManager); + mWeatherManager.reset(); + mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering.get(), mFallback, mStore)); + mwmp::Main::get().setWeatherManager(mWeatherManager.get()); if (!bypass) { @@ -527,12 +527,6 @@ namespace MWWorld { // Must be cleared before mRendering is destroyed mProjectileManager->clear(); - delete mWeatherManager; - delete mWorldScene; - delete mRendering; - delete mPhysics; - - delete mPlayer; } const ESM::Cell *World::getExterior (const std::string& cellName) const @@ -2316,7 +2310,7 @@ namespace MWWorld { const ESM::NPC *player = mStore.get().find("player"); if (!mPlayer) - mPlayer = new MWWorld::Player(player); + mPlayer.reset(new MWWorld::Player(player)); else { // Remove the old CharacterController @@ -3669,17 +3663,17 @@ namespace MWWorld if (MWMechanics::isSummoningEffect(it->mEffectID)) { - preload(mWorldScene, mStore, "VFX_Summon_Start"); - preload(mWorldScene, mStore, MWMechanics::getSummonedCreature(it->mEffectID)); + preload(mWorldScene.get(), mStore, "VFX_Summon_Start"); + preload(mWorldScene.get(), mStore, MWMechanics::getSummonedCreature(it->mEffectID)); } - preload(mWorldScene, mStore, effect->mCasting); - preload(mWorldScene, mStore, effect->mHit); + preload(mWorldScene.get(), mStore, effect->mCasting); + preload(mWorldScene.get(), mStore, effect->mHit); if (it->mArea > 0) - preload(mWorldScene, mStore, effect->mArea); + preload(mWorldScene.get(), mStore, effect->mArea); if (it->mRange == ESM::RT_Target) - preload(mWorldScene, mStore, effect->mBolt); + preload(mWorldScene.get(), mStore, effect->mBolt); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 229ad2da8..de3e20c7e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -74,17 +74,11 @@ namespace MWWorld Resource::ResourceSystem* mResourceSystem; Fallback::Map mFallback; - MWRender::RenderingManager* mRendering; - MWWorld::WeatherManager* mWeatherManager; - - MWWorld::Scene *mWorldScene; - MWWorld::Player *mPlayer; std::vector mEsm; MWWorld::ESMStore mStore; LocalScripts mLocalScripts; MWWorld::Globals mGlobalVariables; - MWPhysics::PhysicsSystem *mPhysics; bool mSky; ESM::Variant* mGameHour; @@ -98,6 +92,11 @@ namespace MWWorld std::string mCurrentWorldSpace; + std::unique_ptr mPlayer; + std::unique_ptr mPhysics; + std::unique_ptr mRendering; + std::unique_ptr mWorldScene; + std::unique_ptr mWeatherManager; std::shared_ptr mProjectileManager; bool mGodMode; diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 6e365611a..516f11e13 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -187,6 +187,12 @@ namespace mwmp TribunalTemple }; + enum class MiscellaneousChangeType : uint8_t + { + MarkLocation = 0, + SelectedSpell + }; + class BasePlayer : public mwmp::BaseNetCreature { public: @@ -316,6 +322,7 @@ namespace mwmp std::string sound; Animation animation; + float scale; bool isWerewolf; std::string creatureModel; bool useCreatureName; @@ -329,10 +336,15 @@ namespace mwmp std::string jailEndText; ResurrectType resurrectType; + MiscellaneousChangeType miscellaneousChangeType; + + ESM::Cell markCell; + ESM::Position markPosition; + std::string selectedSpellId; - bool diedSinceArrestAttempt; bool isReceivingQuickKeys; bool isPlayingAnimation; + bool diedSinceArrestAttempt; }; } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp b/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp index 6a6aa40f8..c185c0739 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerMiscellaneous.cpp @@ -12,5 +12,20 @@ void PacketPlayerMiscellaneous::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - // Placeholder + RW(player->miscellaneousChangeType, send); + + switch (player->miscellaneousChangeType) + { + case MiscellaneousChangeType::MarkLocation: + RW(player->markCell.mData, send, 1); + RW(player->markCell.mName, send, 1); + + RW(player->markPosition.pos, send); + RW(player->markPosition.rot[0], send); + RW(player->markPosition.rot[2], send); + break; + case MiscellaneousChangeType::SelectedSpell: + RW(player->selectedSpellId, send, 1); + break; + } } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerReputation.cpp b/components/openmw-mp/Packets/Player/PacketPlayerReputation.cpp index 291846ef9..25f058a98 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerReputation.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerReputation.cpp @@ -12,5 +12,5 @@ void PacketPlayerReputation::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - // Placeholder + RW(player->npcStats.mReputation, send); } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerShapeshift.cpp b/components/openmw-mp/Packets/Player/PacketPlayerShapeshift.cpp index 1e6c06a70..352342ccd 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerShapeshift.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerShapeshift.cpp @@ -12,5 +12,6 @@ void PacketPlayerShapeshift::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); + RW(player->scale, send); RW(player->isWerewolf, send); } diff --git a/files/launcher/icons/tango/48x48/emblem-system.png b/files/launcher/icons/tango/48x48/emblem-system.png new file mode 100644 index 000000000..9a765247c Binary files /dev/null and b/files/launcher/icons/tango/48x48/emblem-system.png differ diff --git a/files/launcher/launcher.qrc b/files/launcher/launcher.qrc index 4f55fccd5..ddcc26e59 100644 --- a/files/launcher/launcher.qrc +++ b/files/launcher/launcher.qrc @@ -9,8 +9,9 @@ icons/tango/index.theme - icons/tango/48x48/video-display.png + icons/tango/48x48/emblem-system.png icons/tango/48x48/preferences-system.png + icons/tango/48x48/video-display.png icons/tango/16x16/document-new.png icons/tango/16x16/edit-copy.png icons/tango/16x16/edit-delete.png diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui new file mode 100644 index 000000000..8a0795d34 --- /dev/null +++ b/files/ui/advancedpage.ui @@ -0,0 +1,286 @@ + + + AdvancedPage + + + + 0 + 0 + 434 + 373 + + + + + + + <html><head/><body><p>This temporary page contains new settings that will be available in-game in a post-1.0 release of OpenMW.</p></body></html> + + + + + + + true + + + + + 0 + 0 + 393 + 437 + + + + + + + Game + + + + + + <html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. This is how original Morrowind behaves.</p><p>If this setting is false, player has to wait until end of death animation in all cases. This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.</p></body></html> + + + Can loot during death animation + + + + + + + <html><head/><body><p>Makes player followers and escorters start combat with enemies who have started combat with them or the player. Otherwise they wait for the enemies or the player to do an attack first.</p></body></html> + + + Followers attack on sight + + + + + + + <html><head/><body><p>Prevents merchants from equipping items that are sold to them.</p></body></html> + + + Prevent merchant equipping + + + + + + + <html><head/><body><p>Show the remaining duration of magic effects and lights if this setting is true. The remaining duration is displayed in the tooltip by hovering over the magical effect. </p><p>The default value is false.</p></body></html> + + + Show effect duration + + + + + + + <html><head/><body><p>Whether or not the chance of success will be displayed in the enchanting menu.</p><p>The default value is false.</p></body></html> + + + Show enchant chance + + + + + + + <html><head/><body><p>If this setting is true, melee weapons reach and speed will be showed on item tooltip.</p><p>The default value is false.</p></body></html> + + + Show melee info + + + + + + + <html><head/><body><p>If this setting is true, damage bonus of arrows and bolts will be showed on item tooltip.</p><p>The default value is false.</p></body></html> + + + Show projectile damage + + + + + + + <html><head/><body><p>Enable visual clues for items owned by NPCs when the crosshair is on the object.</p><p>The default value is Off.</p></body></html> + + + + -1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Show owned: + + + + + + + + Off + + + + + Tool Tip Only + + + + + Crosshair Only + + + + + Tool Tip and Crosshair + + + + + + + + + + + + + + Input + + + + + + <html><head/><body><p>Allow zooming in and out using the middle mouse wheel in third person view. This feature may not work correctly if the mouse wheel is bound to other actions, and may be triggered accidentally in some cases, so is disabled by default.</p></body></html> + + + Allow third person zoom + + + + + + + <html><head/><body><p>OpenMW will capture control of the cursor if this setting is true.</p><p>In “look mode”, OpenMW will center the cursor regardless of the value of this setting (since the cursor/crosshair is always centered in the OpenMW window). However, in GUI mode, this setting determines the behavior when the cursor is moved outside the OpenMW window. If true, the cursor movement stops at the edge of the window preventing access to other applications. If false, the cursor is allowed to move freely on the desktop.</p><p>This setting does not apply to the screen where escape has been pressed, where the cursor is never captured. Regardless of this setting “Alt-Tab” or some other operating system dependent key sequence can be used to allow the operating system to regain control of the mouse cursor. This setting interacts with the minimize on focus loss setting by affecting what counts as a focus loss. Specifically on a two-screen configuration it may be more convenient to access the second screen with setting disabled.</p><p>Note for developers: it’s desirable to have this setting disabled when running the game in a debugger, to prevent the mouse cursor from becoming unusable when the game pauses on a breakpoint.</p></body></html> + + + Grab cursor + + + + + + + <html><head/><body><p>This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. </p></body></html> + + + Toggle sneak + + + + + + + + + + Other + + + + + + <html><head/><body><p>This setting determines whether the amount of the time the player has spent playing will be displayed for each saved game in the Load menu.</p></body></html> + + + Add "Time Played" to saves + + + + + + + <html><head/><body><p>Specify the format for screen shots taken by pressing the screen shot key (bound to F12 by default). This setting should be the file extension commonly associated with the desired format. The formats supported will be determined at compilation, but “jpg”, “png”, and “tga” should be allowed.</p></body></html> + + + + -1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Screenshot Format + + + + + + + + JPG + + + + + PNG + + + + + TGA + + + + + + + + + + + + + + + + + + + diff --git a/files/ui/mainwindow.ui b/files/ui/mainwindow.ui index 45578ef9e..13e8593e0 100644 --- a/files/ui/mainwindow.ui +++ b/files/ui/mainwindow.ui @@ -6,13 +6,13 @@ 0 0 - 635 + 720 565 - 635 + 720 565