From c822b1fa35d0289ad188b8bdd2bb9dc1417ca8f2 Mon Sep 17 00:00:00 2001 From: HiPhish Date: Mon, 8 Feb 2016 09:56:51 +0100 Subject: [PATCH 001/321] Write chapters about tables and record types. The "Tables", "Record Types" and "Record Filters" chapters have been adapted from the already existing manual. --- docs/cs-manual/source/record-filters.rst | 293 +++++++++++++++++++++++ docs/cs-manual/source/record-types.rst | 62 +++++ docs/cs-manual/source/tables.rst | 168 +++++++++++++ docs/source/openmw-cs/index.rst | 3 + 4 files changed, 526 insertions(+) create mode 100644 docs/cs-manual/source/record-filters.rst create mode 100644 docs/cs-manual/source/record-types.rst create mode 100644 docs/cs-manual/source/tables.rst diff --git a/docs/cs-manual/source/record-filters.rst b/docs/cs-manual/source/record-filters.rst new file mode 100644 index 000000000..3379f557f --- /dev/null +++ b/docs/cs-manual/source/record-filters.rst @@ -0,0 +1,293 @@ +Record Filters +############## + +Filters are a key element of the OpenMW CS user interface, they allow rapid and +easy access to records presented in all tables. In order to use this +application effectively you need to familiarise yourself with all the concepts +and instructions explained in this chapter. The filter system is somewhat +unusual at first glance, but once you understand the basics it will be fairly +intuitive and easy to use + +Filters are a key element to using the OpenMW CS efficiently by allowing you to +narrow down the table entries very quickly and find what you are looking for. +The filter system might appear unusual at first, you don't just type in a word +and get all instances where it occurs, instead filters are first-class objects +in the CS with their own table. This allows you to define very specific filters +for your project and store them on disc to use in the next session. The CS +allows you fine-grained control, you can choose whether to make a filter +persistent between session, only for one session or use a one-off filter by +typing it directly into the filter field. + + + +Terms used +********** + +Filter + A Filter is generally speaking a tool able to filter the elements of a + table, that is select some elements while discarding others, according to + some criteria. These criteria are written using their own syntax. + +Criterion + A criterion describes some condition a record needs to satisfy in order to + be selected. They are written using a special syntax which is explained + below. We can logically combine multiple criteria in a filter for finer + control. + +Expression + Expressions are how we perform filtering. They look like functions in a + programming language: they have a name and accept a number of arguments. + The expression evaluates to either ``true`` or ``false`` for every record in + the table. The arguments are expressions themselves. + +Arity + The arity of an expression tells us how many arguments it takes. Expressions + taking no arguments are called *nullary*, those taking one argument are + known as *unary* expressions and those taking two arguments are called + *binary*. + + + +Interface +********* + +Above each table there is a text field which is used to enter a filter: either +one predefined by the OpenMW CS developers or one made by you. Another +important element is the filter table found under *View* → *Filters*. You +should see the default filters made by the OpenMW team in the table. The table +has the columns *Filter*, *Description* and *Modified*. + +ID + A unique name used to refer to this filter. Note that every ID has a + scope prefix, we will explain these soon. + +Modified + This is the same as for all the other records, it tells us whether the + filter is *added* or *removed*. Filters are specific to a project instead of + a content file, they have no effect on the game itself. + +Filter + The actual contents of the filter are given here using the filter syntax. + Change the expressions to modify what the filter returns. + +Description + A textual description of what the filter does. + + + +Using predefined filters +************************ + +To use a filter you have to type its ID into the filter field above a table. + +For instance, try to opening the objects table (under the world menu) and type +into the filters field ``project::weapons``. As soon as you complete the text +the table will show only the weapons. The string ``project::weapons`` is the ID +of one of the predefined filters. This means that in order to use the filter +inside the table you type its name inside the filter field. + +Filter IDs follow these general conventions: + +- IDs of filters for a specific record type contain usually the name of a + specific group. For instance the ``project::weapons`` filter contains the + term ``weapons``. Plural form is always used. + +- When filtering a specific subgroup the ID is prefixed with the name of the + more general filter. For instance ``project::weaponssilver`` will filter only + silver weapons and ``project::weaponsmagical`` will filter only magical + weapons. + +- There are few exceptions from the above rule. For instance there are + ``project::added``, ``project::removed``, ``project::modified`` and + ``project::base``. You might except something more like + ``project::statusadded`` but in this case requiring these extra characters + would not improve readability. + +We strongly recommend you take a look at the filters table right now to see +what you can filter with the defaults. Try using the default filters first +before writing you own. + + + +Writing your own filters +************************ + +As mentioned before, filters are just another type of record in the OpenMW CS. +To create a new filter you will have to add a new record to the *Filters* table +and set its properties to your liking. Filters are created by combining +existing filters into more complex ones. + + +Scopes +====== + +Every default filter has the prefix ``project``. This is a *scpoe*, a mechanism +that determines the lifetime of the filter. These are the supported scopes: + +``project::`` + Indicates that the filter is to be used throughout the project in multiple + sessions. You can restart the CS and the filter will still be there. + +``session::`` + Indicates that the filter is not stored between multiple sessions and once + you quit the OpenMW CS application the filter will be gone. Until then it + can be found inside the filters table. + +Project-filters are stored in an internal project file, not final content file +meant for the player. Keep in mind when collaborating with other modders that +you need to share the same project file. + + + +Writing expressions +=================== + +The syntax for expressions is as follows: + +.. code-block:: + + + () + (, , ..., ) + +Where ```` is the name of the expression, such as ``string`` and the +```` are expressions themselves. A nullary expression consists only of its +name. A unary expression contains its argument within a pair of parentheses +following the name. If there is more than one argument they are separated by +commas inside the parentheses. + +An example of a binary expression is ``string("Record Type", weapon)``; the +name is ``string``, and it takes two arguments which are strings of string +type. The meaning of arguments depends on the expression itself. In this case +the first argument is the name of a record column and the second field is the +values we want to test it against. + +Strings are sequences of characters and are case-insensitive. If a string +contains spaces it must be quoted, otherwise the quotes are optional and +ignored. + + +Constant Expressions +-------------------- + +These expressions take no arguments and always return the same result. + +``true`` + Always evaluates to ``true``. + +``false`` + Always evaluates to ``false``. + + +Comparison Expressions +---------------------- + +``string(, )`` + The ```` is a regular expression pattern. The expressions evaluates + to ``true`` when the value of a record in ```` matches the pattern. + Since the majority of the columns contain string values, ``string`` is among + the most often used expressions. Examples: + + ``string("Record Type", "Weapon")`` + Will evaluate to ``true`` for all records containing ``Weapon`` in the + *Record Type* column cell. + + ``string("Portable", "true")`` + Will evaluate to ``true`` [#]_ for all records containing word ``true`` inside + *Portable* column cell. + +.. [#] There is no Boolean (``true`` or ``false``) value in the OpenMW CS. You + should use a string for those. + + +``value(, (, ))`` + Match a value type, such as a number, with a range of possible values. The + argument ```` is the string name of the value we want to compare, the + second argument is a pair of lower and upper bounds for the range interval. + + One can use either parentheses ``()`` or brackets ``[]`` to surround the + pair. Brackets are inclusive and parentheses are exclusive. We can also mix + both styles: + + .. code:: + + value("Weight", [20, 50)) + + This will match any objects with a weight greater or equal to 20 and + strictly less than 50. + + +Logical Expressions +------------------- + +``not `` + Logically negates the result of an expression. If ```` evaluates + to ``true`` the negation is ``false``, and if ```` evaluates to + ``false`` the negation is ``true``. Note that there are no parentheses + around the argument. + +``or(, , ..., )`` + Logical disjunction, evaluates to ``true`` if at least one argument + evaluates to ``true`` as well, otherwise the expression evaluates to + ``false``. + + As an example assume we want to filter for both NPCs and creatures; the + expression for that use-case is + + .. code:: + + or(string("record type", "npc"), string("record type", "creature")) + + In this particular case only one argument can evaluate to ``true``, but one + can write expressions where multiple arguments can be ``true`` at a time. + +``or(, , ..., )`` + Logical conjunction, evaluates to ``true`` if and only if all arguments + evaluate to ``true`` as well, otherwise the expression evaluates to + ``false``. + + As an example assume we want to filter for weapons weighting less than a hundred + units The expression for that use-case is + + .. code:: + + and(string("record type", "weapon"), value("weight", (0, 100))) + + +Anonymous filters +================= + +Creating a whole new filter when you only intend to use it once can be +cumbersome. For that reason the OpenMW CS supports *anonymous* filters which +can be typed directly into the filters field of a table. They are not stored +anywhere, when you clear the field the filter is gone forever. + +In order to define an anonymous filter you type an exclamation mark as the +first character into the field followed by the filter definition (e.g. +``!string("Record Type", weapon)`` to filter only for weapons). + + + +Creating and saving filters +*************************** + +Filters are managed the same way as other records: go to the filters table, +right click and select the option *Add Record* from the context menu. You are +given a choice between project- or session scope. Choose the scope from the +dropdown and type in your desired ID for the filter. A newly created filter +does nothing since it still lacks expressions. In order to add your queries you +have to edit the filter record. + + +Replacing the default filters set +================================= + +OpenMW CS allows you to substitute the default filter set for the entire +application. This will affect the default filters for all content files that +have not been edited on this computer and user account. + +Create a new content file, add the desired filters, remove the undesired ones +and save. Now rename the *project* file to ``defaultfilters`` and make sure the +``.omwaddon.project`` file extension is removed. This file will act as a +template for all new files from now on. If you wish to go back to the +old default set rename or remove this custom file. diff --git a/docs/cs-manual/source/record-types.rst b/docs/cs-manual/source/record-types.rst new file mode 100644 index 000000000..3742cc9e8 --- /dev/null +++ b/docs/cs-manual/source/record-types.rst @@ -0,0 +1,62 @@ +Record Types +############ + +A game world contains many items, such as chests, weapons and monsters. All +these items are merely instances of templates we call *Objects*. The OpenMW CS +*Objects* table contains information about each of these template objects, such +as its value and weight in the case of items, or an aggression level in the +case of NPCs. + +The following is a list of all Record Types and what you can tell OpenMW CS +about each of them. + +Activator + Activators can have a script attached to them. As long as the cell this + object is in is active the script will be run once per frame. + +Potion + This is a potion which is not self-made. It has an Icon for your inventory, + weight, coin value, and an attribute called *Auto Calc* set to ``False``. + This means that the effects of this potion are pre-configured. This does not + happen when the player makes their own potion. + +Apparatus + This is a tool to make potions. Again there’s an icon for your inventory as + well as a weight and a coin value. It also has a *Quality* value attached to + it: the higher the number, the better the effect on your potions will be. + The *Apparatus Type* describes if the item is a *Calcinator*, *Retort*, + *Alembic* or *Mortar & Pestle*. + +Armor + This type of item adds *Enchantment Points* to the mix. Every piece of + clothing or armor has a "pool" of potential *Magicka* that gets unlocked + when the player enchants it. Strong enchantments consume more magicka from + this pool: the stronger the enchantment, the more *Enchantment Points* each + cast will take up. *Health* means the amount of hit points this piece of + armor has. If it sustains enough damage, the armor will be destroyed. + Finally, *Armor Value* tells the game how much points to add to the player + character’s *Armor Rating*. + +Book + This includes scrolls and notes. For the game to make the distinction + between books and scrolls, an extra property, *Scroll*, has been added. + Under the *Skill* column a scroll or book can have an in-game skill listed. + Reading this item will raise the player’s level in that specific skill. + +Clothing + These items work just like armors, but confer no protective properties. + Rather than *Armor Type*, these items have a *Clothing Type*. + +Container + This is all the stuff that stores items, from chests to sacks to plants. Its + *Capacity* shows how much stuff you can put in the container. You can + compare it to the maximum allowed load a player character can carry. A + container, however, will just refuse to take the item in question when it + gets "over-encumbered". Organic Containers are containers such as plants. + Containers that respawn are not safe to store stuff in. After a certain + amount of time they will reset to their default contents, meaning that + everything in them is gone forever. + +Creature + These can be monsters, animals and the like. + diff --git a/docs/cs-manual/source/tables.rst b/docs/cs-manual/source/tables.rst new file mode 100644 index 000000000..43da03f07 --- /dev/null +++ b/docs/cs-manual/source/tables.rst @@ -0,0 +1,168 @@ +Tables +###### + +If you have launched OpenMW CS already and played around with it for a bit, you +will have noticed that the interface is made entirely of tables. This does not +mean it works just like a spreadsheet application though, it would be more +accurate to think of databases instead. Due to the vast amounts of information +involved with Morrowind tables made the most sense. You have to be able to spot +information quickly and be able to change them on the fly. + + +Used Terms +********** + +Record + An entry in OpenMW CS representing an item, location, sound, NPC or anything + else. + +Instance, Object + When an item is placed in the world, it does not create a whole new record + each time, but an *instance* of the *object*. + + For example, the game world might contain a lot of exquisite belts on + different NPCs and in many crates, but they all refer to one specific + instance: the Exquisite Belt record. In this case, all those belts in crates + and on NPCs are instances. The central Exquisite Belt instance is called an + *object*. This allows modders to make changes to all items of the same type + in one place. + + If you wanted all exquisite belts to have 4000 enchantment points rather + than 400, you would only need to change the object Exquisite Belt rather + than all exquisite belt instances individually. + +Some columns are recurring throughout OpenMW CS, they show up in (nearly) every +table. + +ID + Each item, location, sound, etc. gets the same unique identifier in both + OpenMW CS and Morrowind. This is usually a very self-explanatory name. For + example, the ID for the (unique) black pants of Caius Cosades is + ``Caius_pants``. This allows players to manipulate the game in many ways. + For example, they could add these pants to their inventory by opening the + console and entering: ``player- >addItem Caius_pants``. In both Morrowind + and OpenMW CS the ID is the primary way to identify all these different + parts of the game. + +Modified + This column shows what has happened (if anything) to this record. There are + four possible states in which it can exist: + + Base + The record is unmodified and from a content file other than the one + currently being edited. + + Added + This record has been added in the currently content file. + + Modified + Similar to *base*, but has been changed in some way. + + Deleted + Similar to *base*, but has been removed as an entry. This does not mean, + however, that the occurrences in the game itself have been removed! For + example, if you were to remove the ``CharGen_Bed`` entry from + ``morrowind.esm``, it does not mean the bedroll in the basement of the + Census and Excise Office in Seyda Neen will be gone. You will have to + delete that instance yourself or make sure that that object is replaced + by something that still exists otherwise the player will get crashes in + the worst case scenario. + + + +World Screens +************* + +The contents of the game world can be changed by choosing one of the options in +the appropriate menu at the top of the screen. + + +Regions +======= + +This describes the general areas of Vvardenfell. Each of these areas has +different rules about things such as encounters and weather. + +Name + This is how the game will show the player's location in-game. + +MapColour + This is a six-digit hexadecimal representation of the colour used to + identify the region on the map available in *World* → *Region Map*. + +Sleep Encounter + These are the rules for what kinds of enemies the player might encounter + when sleeping outside in the wilderness. + + +Cells +===== + +Expansive worlds such as Vvardenfell, with all its items, NPCs, etc. have a lot +going on simultaneously. But if the player is in Balmora, why would the +computer need to keep track the exact locations of NPCs walking through the +corridors in a Vivec canton? All that work would be quite useless and bring +the player's system down to its knees! So the world has been divided up into +squares we call *cells*. Once your character enters a cell, the game will load +everything that is going on in that cell so the player can interact with it. + +In the original Morrowind this could be seen when a small loading bar would +appear near the bottom of the screen while travelling; the player had just +entered a new cell and the game had to load all the items and NPCs. The *Cells* +screen in OpenMW CS provides you with a list of cells in the game, both the +interior cells (houses, dungeons, mines, etc.) and the exterior cells (the +outside world). + +Sleep Forbidden + Can the player sleep on the floor? In most cities it is forbidden to sleep + outside. Sleeping in the wilderness carries its own risks of attack, though, + and this entry lets you decide if a player should be allowed to sleep on the + floor in this cell or not. + +Interior Water + Should water be rendered in this interior cell? The game world consists of + an endless ocean at height 0, then the landscape is added. If part of the + landscape goes below height 0, the player will see water. + + Setting the cell’s Interior Water to true tells the game that this cell that + there needs to be water at height 0. This is useful for dungeons or mines + that have water in them. + + Setting the cell’s Interior Water to ``false`` tells the game that the water + at height 0 should not be used. This flag is useless for outside cells. + +Interior Sky + Should this interior cell have a sky? This is a rather unique case. The + Tribunal expansion took place in a city on the mainland. Normally this would + require the city to be composed of exterior cells so it has a sky, weather + and the like. But if the player is in an exterior cell and were to look at + their in-game map, they would see Vvardenfell with an overview of all + exterior cells. The player would have to see the city’s very own map, as if + they were walking around in an interior cell. + + So the developers decided to create a workaround and take a bit of both: The + whole city would technically work exactly like an interior cell, but it + would need a sky as if it was an exterior cell. That is what this is. This + is why the vast majority of the cells you will find in this screen will have + this option set to false: It is only meant for these "fake exteriors". + +Region + To which Region does this cell belong? This has an impact on the way the + game handles weather and encounters in this area. It is also possible for a + cell not to belong to any region. + + +Objects +======= + +This is a library of all the items, triggers, containers, NPCs, etc. in the +game. There are several kinds of Record Types. Depending on which type a record +is, it will need specific information to function. For example, an NPC needs a +value attached to its aggression level. A chest, of course, does not. All +Record Types contain at least a 3D model or else the player would not see them. +Usually they also have a *Name*, which is what the players sees when they hover +their reticle over the object during the game. + +Please refer to the Record Types chapter for an overview of what each type of +object does and what you can tell OpenMW CS about these objects. + diff --git a/docs/source/openmw-cs/index.rst b/docs/source/openmw-cs/index.rst index dcd28081a..b9c03980b 100644 --- a/docs/source/openmw-cs/index.rst +++ b/docs/source/openmw-cs/index.rst @@ -22,4 +22,7 @@ few chapters to familiarise yourself with the new interface. tour files-and-directories starting-dialog + tables + record-types + record-filters From 97924d97c785fda67f690ad49d9b624996526fc8 Mon Sep 17 00:00:00 2001 From: Daniel Vukelich Date: Fri, 12 Jan 2018 20:02:43 -0500 Subject: [PATCH 002/321] Add the option for multiple quicksave slots With more than 1 quicksave slot, slots will be created each time you quicksave until the maximum number (configured in settings) of quicksaves has been reached. After that, the oldest quicksave slot will be replaced each time you quicksave. Saves are numbered sequentially, unless the maximum number of slots is 1, in which case it is not numbered. --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwstate/quicksavemanager.cpp | 73 +++++++++++++++++++ apps/openmw/mwstate/quicksavemanager.hpp | 42 +++++++++++ apps/openmw/mwstate/statemanagerimp.cpp | 17 +++-- .../reference/modding/settings/saves.rst | 13 +++- files/settings-default.cfg | 8 +- 6 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 apps/openmw/mwstate/quicksavemanager.cpp create mode 100644 apps/openmw/mwstate/quicksavemanager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 491394324..6e97df297 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -89,7 +89,7 @@ add_openmw_dir (mwmechanics ) add_openmw_dir (mwstate - statemanagerimp charactermanager character + statemanagerimp charactermanager character quicksavemanager ) add_openmw_dir (mwbase @@ -223,4 +223,3 @@ endif (MSVC) if (WIN32) INSTALL(TARGETS openmw RUNTIME DESTINATION ".") endif (WIN32) - diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp new file mode 100644 index 000000000..3ead7165a --- /dev/null +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -0,0 +1,73 @@ +#include "quicksavemanager.hpp" + +#include + +MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, int maxSaves){ + this->saveName = saveName; + this->maxSaves = maxSaves; + this->oldestSlotVisited = NULL; + this->oldestSlotId = 0; + this->slotsVisited = 0; +} + +void MWState::QuickSaveManager::visitSave(const Slot *saveSlot){ + int slotId; + if(tryExtractSlotId(saveSlot->mProfile.mDescription, slotId)){ + ++slotsVisited; + if(isOldestSave(saveSlot)){ + oldestSlotVisited = saveSlot; + oldestSlotId = slotId; + } + } +} + +bool MWState::QuickSaveManager::isOldestSave(const Slot *compare){ + if(oldestSlotVisited == NULL) + return true; + return (compare->mTimeStamp < oldestSlotVisited->mTimeStamp); +} + +bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, int &extractedId){ + std::istringstream formattedExtractor = std::istringstream(slotName); + + std::string nameToTest; + formattedExtractor >> nameToTest; + if(nameToTest == saveName){ + //Only try to extract the id if maxSaves > 1 + //With maxSaves == 1, we don't append the slotId to the name + if(formattedExtractor >> extractedId) + return (isSlotIdValid(extractedId)); + else if(maxSaves == 1) + return formattedExtractor.eof(); + } + return false; +} + +bool MWState::QuickSaveManager::isSlotIdValid(int slotId){ + return (slotId > 0 && slotId <= maxSaves); +} + +bool MWState::QuickSaveManager::shouldCreateNewSlot(){ + return (slotsVisited < maxSaves); +} + +const MWState::Slot *MWState::QuickSaveManager::getNextQuickSaveSlot(){ + if(shouldCreateNewSlot()) + return NULL; + return oldestSlotVisited; +} + +std::string MWState::QuickSaveManager::getNextQuickSaveName(){ + std::ostringstream nameFormatter; + nameFormatter << saveName; + //Only print the number if there will be more than 1 + if(maxSaves > 1) + nameFormatter << " " << calcNextSlotId(); + return nameFormatter.str(); +} + +int MWState::QuickSaveManager::calcNextSlotId(){ + if(shouldCreateNewSlot()) + return (slotsVisited + 1); + return oldestSlotId; +} diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp new file mode 100644 index 000000000..04341897f --- /dev/null +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -0,0 +1,42 @@ +#ifndef GAME_STATE_QUICKSAVEMANAGER_H +#define GAME_STATE_QUICKSAVEMANAGER_H + +#include "character.hpp" +#include "../mwbase/statemanager.hpp" + +#include + +namespace MWState{ + class QuickSaveManager{ + std::string saveName; + int maxSaves; + int slotsVisited; + int oldestSlotId; + const Slot *oldestSlotVisited; + private: + bool tryExtractSlotId(const std::string &slotName, int &extractedIdll); + bool isSlotIdValid(int slotId); + bool shouldCreateNewSlot(); + bool isOldestSave(const Slot *compare); + int calcNextSlotId(); + public: + QuickSaveManager(std::string &saveName, int maxSaves); + ///< A utility class to manage multiple quicksave slots + /// + /// \param saveName The name of the save ("QuickSave", "AutoSave", etc) + /// \param maxSaves The maximum number of save slots to use before recycling old ones + + void visitSave(const Slot *saveSlot); + ///< Visits the given \a slot \a + + const Slot *getNextQuickSaveSlot(); + ///< Get the slot that the next quicksave should use. + /// + ///\return Either the oldest quicksave slot visited, or NULL if a new slot can be made + + std::string getNextQuickSaveName(); + ///< Get the name that the next quicksave should use ("QuickSave 1", "AutoSave 10", etc) + }; +} + +#endif diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 14ee5adee..5b126cbb5 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -37,6 +37,8 @@ #include "../mwscript/globalscripts.hpp" +#include "quicksavemanager.hpp" + void MWState::StateManager::cleanup (bool force) { if (mState!=State_NoGame || force) @@ -324,20 +326,25 @@ void MWState::StateManager::quickSave (std::string name) return; } - const Slot* slot = NULL; + int maxSaves = Settings::Manager::getInt("max quicksaves", "Saves"); + if(maxSaves < 1) + maxSaves = 1; + Character* currentCharacter = getCurrentCharacter(); //Get current character + QuickSaveManager saveFinder = QuickSaveManager(name, maxSaves); - //Find quicksave slot if (currentCharacter) { for (Character::SlotIterator it = currentCharacter->begin(); it != currentCharacter->end(); ++it) { - if (it->mProfile.mDescription == name) - slot = &*it; + //Visiting slots allows the quicksave finder to find the oldest quicksave + saveFinder.visitSave(&*it); } } - saveGame(name, slot); + //Once all the saves have been visited, the save finder can tell us which + //one to replace (or create) + saveGame(saveFinder.getNextQuickSaveName(), saveFinder.getNextQuickSaveSlot()); } void MWState::StateManager::loadGame(const std::string& filepath) diff --git a/docs/source/reference/modding/settings/saves.rst b/docs/source/reference/modding/settings/saves.rst index 90bd56ca5..f5fd553a9 100644 --- a/docs/source/reference/modding/settings/saves.rst +++ b/docs/source/reference/modding/settings/saves.rst @@ -5,7 +5,7 @@ character --------- :Type: string -:Range: +:Range: :Default: "" This setting contains the default character name for loading saved games. @@ -35,3 +35,14 @@ This setting determines whether the amount of the time the player has spent play for each saved game in the Load menu. This setting can only be configured by editing the settings configuration file. + +max quicksaves +---------- + +:Type: integer +:Range: >0 +:Default: 5 + +This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave. + +This setting can only be configured by editing the settings configuration file. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c694d4db2..3da88b01a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -7,7 +7,7 @@ # significance of each setting, interaction with other settings, hard # limits on value ranges and more information in general, please read # the detailed documentation at: -# +# # http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html # @@ -288,6 +288,10 @@ autosave = true # Display the time played on each save file in the load menu. timeplayed = false +# The maximum number of quick (or auto) save slots to have. +# If all slots are used, the oldest save is reused +max quicksaves = 5 + [Sound] # Name of audio device file. Blank means use the default device. @@ -376,7 +380,7 @@ reflect actors = false # Overrides the value in '[Camera] small feature culling pixel size' specifically for water reflection/refraction textures. small feature culling pixel size = 20.0 -# By what factor water downscales objects. Only works with water shader and refractions on. +# By what factor water downscales objects. Only works with water shader and refractions on. refraction scale = 1.0 [Windows] From f09fd6795c4519523e7ea927106a17e573019d17 Mon Sep 17 00:00:00 2001 From: Daniel Vukelich Date: Fri, 12 Jan 2018 20:02:43 -0500 Subject: [PATCH 003/321] Follow openmw style guide --- apps/openmw/mwstate/quicksavemanager.cpp | 74 ++++++++++++++---------- apps/openmw/mwstate/quicksavemanager.hpp | 14 ++--- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp index 3ead7165a..1457f7075 100644 --- a/apps/openmw/mwstate/quicksavemanager.cpp +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -2,72 +2,84 @@ #include -MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, int maxSaves){ - this->saveName = saveName; - this->maxSaves = maxSaves; - this->oldestSlotVisited = NULL; - this->oldestSlotId = 0; - this->slotsVisited = 0; +MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, int maxSaves) +{ + this->mSaveName = saveName; + this->mMaxSaves = maxSaves; + this->mOldestSlotVisited = NULL; + this->mOldestSlotId = 0; + this->mSlotsVisited = 0; } -void MWState::QuickSaveManager::visitSave(const Slot *saveSlot){ +void MWState::QuickSaveManager::visitSave(const Slot *saveSlot) +{ int slotId; - if(tryExtractSlotId(saveSlot->mProfile.mDescription, slotId)){ - ++slotsVisited; - if(isOldestSave(saveSlot)){ - oldestSlotVisited = saveSlot; - oldestSlotId = slotId; + if(tryExtractSlotId(saveSlot->mProfile.mDescription, slotId)) + { + ++mSlotsVisited; + if(isOldestSave(saveSlot)) + { + mOldestSlotVisited = saveSlot; + mOldestSlotId = slotId; } } } -bool MWState::QuickSaveManager::isOldestSave(const Slot *compare){ - if(oldestSlotVisited == NULL) +bool MWState::QuickSaveManager::isOldestSave(const Slot *compare) +{ + if(mOldestSlotVisited == NULL) return true; - return (compare->mTimeStamp < oldestSlotVisited->mTimeStamp); + return (compare->mTimeStamp <= mOldestSlotVisited->mTimeStamp); } -bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, int &extractedId){ - std::istringstream formattedExtractor = std::istringstream(slotName); +bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, int &extractedId) +{ + std::istringstream formattedExtractor(slotName); std::string nameToTest; formattedExtractor >> nameToTest; - if(nameToTest == saveName){ + if(nameToTest == mSaveName) + { //Only try to extract the id if maxSaves > 1 //With maxSaves == 1, we don't append the slotId to the name if(formattedExtractor >> extractedId) return (isSlotIdValid(extractedId)); - else if(maxSaves == 1) + else if(mMaxSaves == 1) return formattedExtractor.eof(); } return false; } -bool MWState::QuickSaveManager::isSlotIdValid(int slotId){ - return (slotId > 0 && slotId <= maxSaves); +bool MWState::QuickSaveManager::isSlotIdValid(int slotId) +{ + return (slotId > 0 && slotId <= mMaxSaves); } -bool MWState::QuickSaveManager::shouldCreateNewSlot(){ - return (slotsVisited < maxSaves); +bool MWState::QuickSaveManager::shouldCreateNewSlot() +{ + return (mSlotsVisited < mMaxSaves); } -const MWState::Slot *MWState::QuickSaveManager::getNextQuickSaveSlot(){ +const MWState::Slot *MWState::QuickSaveManager::getNextQuickSaveSlot() +{ if(shouldCreateNewSlot()) return NULL; - return oldestSlotVisited; + return mOldestSlotVisited; } -std::string MWState::QuickSaveManager::getNextQuickSaveName(){ +std::string MWState::QuickSaveManager::getNextQuickSaveName() +{ std::ostringstream nameFormatter; - nameFormatter << saveName; + nameFormatter << mSaveName; //Only print the number if there will be more than 1 - if(maxSaves > 1) + if(mMaxSaves > 1) nameFormatter << " " << calcNextSlotId(); return nameFormatter.str(); } -int MWState::QuickSaveManager::calcNextSlotId(){ +int MWState::QuickSaveManager::calcNextSlotId() +{ if(shouldCreateNewSlot()) - return (slotsVisited + 1); - return oldestSlotId; + return (mSlotsVisited + 1); + return mOldestSlotId; } diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp index 04341897f..6a06171d9 100644 --- a/apps/openmw/mwstate/quicksavemanager.hpp +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -1,18 +1,18 @@ #ifndef GAME_STATE_QUICKSAVEMANAGER_H #define GAME_STATE_QUICKSAVEMANAGER_H +#include + #include "character.hpp" #include "../mwbase/statemanager.hpp" -#include - namespace MWState{ class QuickSaveManager{ - std::string saveName; - int maxSaves; - int slotsVisited; - int oldestSlotId; - const Slot *oldestSlotVisited; + std::string mSaveName; + int mMaxSaves; + int mSlotsVisited; + int mOldestSlotId; + const Slot *mOldestSlotVisited; private: bool tryExtractSlotId(const std::string &slotName, int &extractedIdll); bool isSlotIdValid(int slotId); From 3af8f63895c94e1a0268720be0680af83130954b Mon Sep 17 00:00:00 2001 From: Daniel Vukelich Date: Wed, 17 Jan 2018 21:43:30 -0500 Subject: [PATCH 004/321] Use unsigned integer types for QuickSave indices --- apps/openmw/mwstate/quicksavemanager.cpp | 8 ++++---- apps/openmw/mwstate/quicksavemanager.hpp | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp index 1457f7075..e49f376d6 100644 --- a/apps/openmw/mwstate/quicksavemanager.cpp +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -2,7 +2,7 @@ #include -MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, int maxSaves) +MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, unsigned int maxSaves) { this->mSaveName = saveName; this->mMaxSaves = maxSaves; @@ -13,7 +13,7 @@ MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, int maxSaves) void MWState::QuickSaveManager::visitSave(const Slot *saveSlot) { - int slotId; + unsigned int slotId; if(tryExtractSlotId(saveSlot->mProfile.mDescription, slotId)) { ++mSlotsVisited; @@ -32,7 +32,7 @@ bool MWState::QuickSaveManager::isOldestSave(const Slot *compare) return (compare->mTimeStamp <= mOldestSlotVisited->mTimeStamp); } -bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, int &extractedId) +bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, unsigned int &extractedId) { std::istringstream formattedExtractor(slotName); @@ -50,7 +50,7 @@ bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, in return false; } -bool MWState::QuickSaveManager::isSlotIdValid(int slotId) +bool MWState::QuickSaveManager::isSlotIdValid(unsigned int slotId) { return (slotId > 0 && slotId <= mMaxSaves); } diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp index 6a06171d9..abe7ef426 100644 --- a/apps/openmw/mwstate/quicksavemanager.hpp +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -9,18 +9,18 @@ namespace MWState{ class QuickSaveManager{ std::string mSaveName; - int mMaxSaves; - int mSlotsVisited; - int mOldestSlotId; + unsigned int mMaxSaves; + unsigned int mSlotsVisited; + unsigned int mOldestSlotId; const Slot *mOldestSlotVisited; private: - bool tryExtractSlotId(const std::string &slotName, int &extractedIdll); - bool isSlotIdValid(int slotId); + bool tryExtractSlotId(const std::string &slotName, unsigned int &extractedIdll); + bool isSlotIdValid(unsigned int slotId); bool shouldCreateNewSlot(); bool isOldestSave(const Slot *compare); int calcNextSlotId(); public: - QuickSaveManager(std::string &saveName, int maxSaves); + QuickSaveManager(std::string &saveName, unsigned int maxSaves); ///< A utility class to manage multiple quicksave slots /// /// \param saveName The name of the save ("QuickSave", "AutoSave", etc) From 3bdd989a509fd5d1b56c86ed7db3604583407ace Mon Sep 17 00:00:00 2001 From: Daniel Vukelich Date: Tue, 13 Feb 2018 21:01:15 -0500 Subject: [PATCH 005/321] Remove numeric quicksave slot IDs When multiple quicksaves occurred in quick succession, the numeric order of the saves could not be guaranteed. To prevent players from getting confused as to why their saves appear out of order, don't number them. --- apps/openmw/mwstate/quicksavemanager.cpp | 49 +----------------------- apps/openmw/mwstate/quicksavemanager.hpp | 9 +---- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- 3 files changed, 3 insertions(+), 57 deletions(-) diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp index e49f376d6..4bae9e674 100644 --- a/apps/openmw/mwstate/quicksavemanager.cpp +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -1,27 +1,20 @@ #include "quicksavemanager.hpp" -#include - MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, unsigned int maxSaves) { this->mSaveName = saveName; this->mMaxSaves = maxSaves; this->mOldestSlotVisited = NULL; - this->mOldestSlotId = 0; this->mSlotsVisited = 0; } void MWState::QuickSaveManager::visitSave(const Slot *saveSlot) { - unsigned int slotId; - if(tryExtractSlotId(saveSlot->mProfile.mDescription, slotId)) + if(mSaveName == saveSlot->mProfile.mDescription) { ++mSlotsVisited; if(isOldestSave(saveSlot)) - { mOldestSlotVisited = saveSlot; - mOldestSlotId = slotId; - } } } @@ -32,29 +25,6 @@ bool MWState::QuickSaveManager::isOldestSave(const Slot *compare) return (compare->mTimeStamp <= mOldestSlotVisited->mTimeStamp); } -bool MWState::QuickSaveManager::tryExtractSlotId(const std::string &slotName, unsigned int &extractedId) -{ - std::istringstream formattedExtractor(slotName); - - std::string nameToTest; - formattedExtractor >> nameToTest; - if(nameToTest == mSaveName) - { - //Only try to extract the id if maxSaves > 1 - //With maxSaves == 1, we don't append the slotId to the name - if(formattedExtractor >> extractedId) - return (isSlotIdValid(extractedId)); - else if(mMaxSaves == 1) - return formattedExtractor.eof(); - } - return false; -} - -bool MWState::QuickSaveManager::isSlotIdValid(unsigned int slotId) -{ - return (slotId > 0 && slotId <= mMaxSaves); -} - bool MWState::QuickSaveManager::shouldCreateNewSlot() { return (mSlotsVisited < mMaxSaves); @@ -66,20 +36,3 @@ const MWState::Slot *MWState::QuickSaveManager::getNextQuickSaveSlot() return NULL; return mOldestSlotVisited; } - -std::string MWState::QuickSaveManager::getNextQuickSaveName() -{ - std::ostringstream nameFormatter; - nameFormatter << mSaveName; - //Only print the number if there will be more than 1 - if(mMaxSaves > 1) - nameFormatter << " " << calcNextSlotId(); - return nameFormatter.str(); -} - -int MWState::QuickSaveManager::calcNextSlotId() -{ - if(shouldCreateNewSlot()) - return (mSlotsVisited + 1); - return mOldestSlotId; -} diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp index abe7ef426..e52cd609f 100644 --- a/apps/openmw/mwstate/quicksavemanager.hpp +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -11,20 +11,16 @@ namespace MWState{ std::string mSaveName; unsigned int mMaxSaves; unsigned int mSlotsVisited; - unsigned int mOldestSlotId; const Slot *mOldestSlotVisited; private: - bool tryExtractSlotId(const std::string &slotName, unsigned int &extractedIdll); - bool isSlotIdValid(unsigned int slotId); bool shouldCreateNewSlot(); bool isOldestSave(const Slot *compare); - int calcNextSlotId(); public: QuickSaveManager(std::string &saveName, unsigned int maxSaves); ///< A utility class to manage multiple quicksave slots /// /// \param saveName The name of the save ("QuickSave", "AutoSave", etc) - /// \param maxSaves The maximum number of save slots to use before recycling old ones + /// \param maxSaves The maximum number of save slots to create before recycling old ones void visitSave(const Slot *saveSlot); ///< Visits the given \a slot \a @@ -33,9 +29,6 @@ namespace MWState{ ///< Get the slot that the next quicksave should use. /// ///\return Either the oldest quicksave slot visited, or NULL if a new slot can be made - - std::string getNextQuickSaveName(); - ///< Get the name that the next quicksave should use ("QuickSave 1", "AutoSave 10", etc) }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 5b126cbb5..c1bb589e8 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -344,7 +344,7 @@ void MWState::StateManager::quickSave (std::string name) //Once all the saves have been visited, the save finder can tell us which //one to replace (or create) - saveGame(saveFinder.getNextQuickSaveName(), saveFinder.getNextQuickSaveSlot()); + saveGame(name, saveFinder.getNextQuickSaveSlot()); } void MWState::StateManager::loadGame(const std::string& filepath) From 104495a9a432acfbb34f2eb7c9d38766573564d8 Mon Sep 17 00:00:00 2001 From: Daniel Vukelich Date: Tue, 13 Feb 2018 21:05:24 -0500 Subject: [PATCH 006/321] Set default number of quicksaves to 1 --- docs/source/reference/modding/settings/saves.rst | 2 +- files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/settings/saves.rst b/docs/source/reference/modding/settings/saves.rst index f5fd553a9..a3cf5b4e0 100644 --- a/docs/source/reference/modding/settings/saves.rst +++ b/docs/source/reference/modding/settings/saves.rst @@ -41,7 +41,7 @@ max quicksaves :Type: integer :Range: >0 -:Default: 5 +:Default: 1 This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3da88b01a..e2a0bdf54 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -290,7 +290,7 @@ timeplayed = false # The maximum number of quick (or auto) save slots to have. # If all slots are used, the oldest save is reused -max quicksaves = 5 +max quicksaves = 1 [Sound] From 929fc68160a031e17d419af74ed6354bef895dd9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 26 Feb 2018 23:21:51 +0300 Subject: [PATCH 007/321] Consider items with dead owner not stolen (fixes bug #4328) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bd5fa1b11..cd3cd1f80 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1118,8 +1118,11 @@ namespace MWMechanics Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) - mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; - + { + const MWWorld::Ptr victimRef = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); + if (!victimRef.getClass().getCreatureStats(victimRef).isDead()) + mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; + } if (alarm) commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } From 3393ad623fde05ce8957d556ae5430b436c6100a Mon Sep 17 00:00:00 2001 From: bret curtis Date: Tue, 27 Feb 2018 16:15:43 +0100 Subject: [PATCH 008/321] fix rtd --- docs/source/conf.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index b18b40c50..e3fe58bc7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,13 +60,29 @@ copyright = u'2017, OpenMW Team' # The short X.Y version. # The full version, including alpha/beta/rc tags. +def get_openmw_version(haystack): + needle = 'OPENMW_VERSION_MAJOR' + line_counter = 0 + for hay in haystack: + if needle in str(hay): + break + line_counter += 1 + + if line_counter == 0: + raise ImportError('Unable to find OpenMW Version') + + version = '.'.join([haystack[line_counter][1][1].contents, + haystack[line_counter+1][1][1].contents, + haystack[line_counter+2][1][1].contents]) + return version + + try: from parse_cmake import parsing cmake_raw = open(project_root+'/CMakeLists.txt', 'r').read() cmake_data = parsing.parse(cmake_raw) - release = version = '.'.join([cmake_data[24][1][1].contents, - cmake_data[25][1][1].contents, - cmake_data[26][1][1].contents]) + release = version = get_openmw_version(cmake_data) + except ImportError: release = "UNRELEASED" print("WARNING: Unable to import parse_cmake, version will be set to: {0}.".format(release)) From 81d90d7fb725007783a419eeaaf30dcac8a3c6fa Mon Sep 17 00:00:00 2001 From: bret curtis Date: Tue, 27 Feb 2018 18:57:37 +0100 Subject: [PATCH 009/321] break for all errors that would raise when checking for version, make them UNRELEASED --- docs/source/conf.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index e3fe58bc7..0ba8567c0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,6 +60,9 @@ copyright = u'2017, OpenMW Team' # The short X.Y version. # The full version, including alpha/beta/rc tags. +release = version = "UNRELEASED" + + def get_openmw_version(haystack): needle = 'OPENMW_VERSION_MAJOR' line_counter = 0 @@ -68,9 +71,6 @@ def get_openmw_version(haystack): break line_counter += 1 - if line_counter == 0: - raise ImportError('Unable to find OpenMW Version') - version = '.'.join([haystack[line_counter][1][1].contents, haystack[line_counter+1][1][1].contents, haystack[line_counter+2][1][1].contents]) @@ -83,9 +83,9 @@ try: cmake_data = parsing.parse(cmake_raw) release = version = get_openmw_version(cmake_data) -except ImportError: - release = "UNRELEASED" - print("WARNING: Unable to import parse_cmake, version will be set to: {0}.".format(release)) +except Exception as ex: + print("WARNING: Version will be set to '{0}' because: '{1}'.".format(release, str(ex))) + import traceback; traceback.print_exc() # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 4a2e9f2e3d8c9a5bad6fe795d24fb286549f4540 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 27 Feb 2018 23:52:12 +0000 Subject: [PATCH 010/321] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 155d017f3..f6cc51181 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -41,6 +41,7 @@ Programmers Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) crussell187 + DanielVukelich darkf devnexen Dieho From 4292351993c2d10ef72a26d4925e27684f4312f4 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 27 Feb 2018 20:17:21 -0600 Subject: [PATCH 011/321] Adding Max Quicksaves setting to Launcher --- apps/launcher/advancedpage.cpp | 9 +++-- files/ui/advancedpage.ui | 66 +++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 3ba378599..27f3cc39d 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -35,8 +35,11 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(grabCursorCheckBox, "grab cursor", "Input"); loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input"); - // Other Settings + // Saves Settings loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); + maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves")); + + // Other Settings QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper(); if (screenshotFormatComboBox->findText(screenshotFormatString) == -1) @@ -69,9 +72,11 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(grabCursorCheckBox, "grab cursor", "Input"); saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input"); - // Other Settings + // Saves Settings saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); + mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksavesComboBox->value()); + // Other Settings std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString(); if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General")) mEngineSettings.setString("screenshot format", "General", screenshotFormatString); diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 8a0795d34..6832b86df 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -6,7 +6,7 @@ 0 0 - 434 + 671 373 @@ -27,9 +27,9 @@ 0 - 0 - 393 - 437 + -187 + 630 + 510 @@ -139,6 +139,9 @@ + + 1 + Off @@ -207,11 +210,11 @@ - + - Other + Saves - + @@ -222,12 +225,59 @@ + + + + <html><head/><body><p>This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave.</p></body></html> + + + + -1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Maximum Quicksaves + + + + + + + 1 + + + + + + + + + + + + + Other + + <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 From b6d9b6f544ee1e761be5dc8ffa82b9b665eec59f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 27 Feb 2018 20:17:43 -0600 Subject: [PATCH 012/321] Formatting improvement for advanced page --- apps/launcher/advancedpage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 27f3cc39d..0abefcc8f 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -40,7 +40,6 @@ bool Launcher::AdvancedPage::loadSettings() maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves")); // Other Settings - QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper(); if (screenshotFormatComboBox->findText(screenshotFormatString) == -1) screenshotFormatComboBox->addItem(screenshotFormatString); From 10fe3342477816e99e7d9cd12e726cd09146f98d Mon Sep 17 00:00:00 2001 From: Florian Weber Date: Fri, 2 Mar 2018 15:05:00 +0100 Subject: [PATCH 013/321] add more precise float-spinbox and use it for rotations --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 6 +++--- apps/opencs/view/world/util.cpp | 9 +++++++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index d609a6253..df37afe60 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -88,6 +88,7 @@ namespace CSMWorld Display_UnsignedInteger8, Display_Integer, Display_Float, + Display_Double, Display_Var, Display_GmstVarType, Display_GlobalVarType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index f1025acb9..4ad447b0a 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1371,7 +1371,7 @@ namespace CSMWorld RotColumn (ESM::Position ESXRecordT::* position, int index, bool door) : Column ( (door ? Columns::ColumnId_DoorPositionXRot : Columns::ColumnId_PositionXRot)+index, - ColumnBase::Display_Float), mPosition (position), mIndex (index) {} + ColumnBase::Display_Double), mPosition (position), mIndex (index) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 44a6ce07d..daebc2dcb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -184,11 +184,11 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); + new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Double)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); + new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Double)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Double)); // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index efba1ea82..eab37e1bf 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -233,6 +233,15 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return dsb; } + case CSMWorld::ColumnBase::Display_Double: + { + DialogueDoubleSpinBox *dsb = new DialogueDoubleSpinBox(parent); + dsb->setRange(-FLT_MAX, FLT_MAX); + dsb->setSingleStep(0.01f); + dsb->setDecimals(6); + return dsb; + } + case CSMWorld::ColumnBase::Display_LongString: { QPlainTextEdit *edit = new QPlainTextEdit(parent); From 839196e4faaa4782c2cc339413e964e4ed698b78 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 3 Mar 2018 00:15:57 +0000 Subject: [PATCH 014/321] Force normal polygon mode for the map camera (Fixes #4235) --- apps/openmw/mwrender/localmap.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b78c4dcd2..0b65a6b13 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -174,6 +175,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; + stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE); // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) From cc0c6ddaa6aed5c93f83597a58d12fbacba34d46 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 28 Feb 2018 14:04:56 +0300 Subject: [PATCH 015/321] Account for empty victimRef (Bug #4328) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index cd3cd1f80..be5125a2b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1120,7 +1120,7 @@ namespace MWMechanics if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { const MWWorld::Ptr victimRef = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); - if (!victimRef.getClass().getCreatureStats(victimRef).isDead()) + if (victimRef.isEmpty() || !victimRef.getClass().getCreatureStats(victimRef).isDead()) mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; } if (alarm) From d371bebb333c419c0c5589bfca090410eb25a1be Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 2 Mar 2018 21:10:05 +0300 Subject: [PATCH 016/321] Prevent items in a container owned by a dead actor from being counted as stolen (Bug #4328) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index be5125a2b..225427829 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1119,7 +1119,7 @@ namespace MWMechanics if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - const MWWorld::Ptr victimRef = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); + const MWWorld::Ptr victimRef = MWBase::Environment::get().getWorld()->searchPtr(ownerCellRef->getOwner(), true); if (victimRef.isEmpty() || !victimRef.getClass().getCreatureStats(victimRef).isDead()) mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; } From 6d557fec8e08dc65683454fde47d1d01a87faa9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Sep 2017 11:42:15 -0700 Subject: [PATCH 017/321] Increase the far clip plane when distant terrain is enabled --- apps/openmw/mwrender/renderingmanager.cpp | 20 ++++++++++++-------- apps/openmw/mwrender/renderingmanager.hpp | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3281a787b..b880943a4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -179,8 +179,9 @@ namespace MWRender , mUnderwaterFog(0.f) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) - , mFieldOfViewOverride(0.f) + , mDistantTerrain(false) , mFieldOfViewOverridden(false) + , mFieldOfViewOverride(0.f) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); @@ -216,12 +217,12 @@ namespace MWRender mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); - const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); + mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"), - Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), + Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain specular maps", "Shaders")); - if (distantTerrain) + if (mDistantTerrain) mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile)); else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile)); @@ -288,8 +289,10 @@ namespace MWRender mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); mStateUpdater->setFogEnd(mViewDistance); + mFarClip = mDistantTerrain ? 8192.0f*5.0f : mViewDistance; + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mFarClip)); mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); @@ -632,7 +635,7 @@ namespace MWRender rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); - rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); + rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mFarClip); rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); rttCamera->setViewport(0, 0, w, h); @@ -897,10 +900,10 @@ namespace MWRender float fov = mFieldOfView; if (mFieldOfViewOverridden) fov = mFieldOfViewOverride; - mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); + mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mFarClip); mUniformNear->set(mNearClip); - mUniformFar->set(mViewDistance); + mUniformFar->set(mFarClip); } void RenderingManager::updateTextureFiltering() @@ -960,6 +963,7 @@ namespace MWRender else if (it->first == "Camera" && it->second == "viewing distance") { mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); + mFarClip = mDistantTerrain ? 8192.0f*5.0f : mViewDistance; mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0087e43d..16854aaea 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -252,9 +252,11 @@ namespace MWRender float mNightEyeFactor; float mNearClip; + float mFarClip; float mViewDistance; + bool mDistantTerrain : 1; + bool mFieldOfViewOverridden : 1; float mFieldOfViewOverride; - bool mFieldOfViewOverridden; float mFieldOfView; float mFirstPersonFieldOfView; From 154cc8c6592cfe775f0953078ad1ceeb13afd398 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Sep 2017 03:08:45 -0700 Subject: [PATCH 018/321] Use alternate fog parameters when distant land is enabled This allows the distant land to actually be seen when the user enables it. The values used are replicated from MGE XE's default settings and should probably be exposed somewhere. --- apps/openmw/mwrender/renderingmanager.cpp | 85 +++++++++++++++++------ apps/openmw/mwrender/renderingmanager.hpp | 8 ++- apps/openmw/mwrender/sky.hpp | 3 + apps/openmw/mwworld/weather.cpp | 35 ++++++---- apps/openmw/mwworld/weather.hpp | 9 +++ 5 files changed, 103 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b880943a4..ea0fef197 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -51,6 +51,20 @@ #include "terrainstorage.hpp" #include "util.hpp" +namespace +{ + // These values are what MGE XE uses by default when distant land is enabled, and are specified + // in cells (8192 units each). Should make them settings somewhere? Or wait to expose them + // "properly"? + const float DLRenderDistance = 5.0f; + const float DLLandFogStart = 2.0f; + const float DLLandFogEnd = 5.0f; + const float DLUnderwaterFogStart = -0.5f; + const float DLUnderwaterFogEnd = 0.3f; + const float DLInteriorFogStart = 0.0f; + const float DLInteriorFogEnd = 2.0f; +} + namespace MWRender { @@ -173,10 +187,12 @@ namespace MWRender , mResourceSystem(resourceSystem) , mWorkQueue(workQueue) , mUnrefQueue(new SceneUtil::UnrefQueue) - , mFogDepth(0.f) + , mLandFogStart(0.f) + , mLandFogEnd(std::numeric_limits::max()) + , mUnderwaterFogStart(0.f) + , mUnderwaterFogEnd(std::numeric_limits::max()) , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) - , mUnderwaterFog(0.f) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) , mDistantTerrain(false) @@ -289,7 +305,7 @@ namespace MWRender mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); mStateUpdater->setFogEnd(mViewDistance); - mFarClip = mDistantTerrain ? 8192.0f*5.0f : mViewDistance; + mFarClip = mDistantTerrain ? DLRenderDistance*8192.0f : mViewDistance; mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mFarClip)); @@ -482,14 +498,44 @@ namespace MWRender { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); - configureFog (cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, color); + if(mDistantTerrain) + { + float density = std::max(0.2f, cell->mAmbi.mFogDensity); + mLandFogStart = (DLInteriorFogEnd*(1.0f-density) + DLInteriorFogStart*density) * 8192.0f; + mLandFogEnd = DLInteriorFogEnd * 8192.0f; + mUnderwaterFogStart = DLUnderwaterFogStart * 8192.0f; + mUnderwaterFogEnd = DLUnderwaterFogEnd * 8192.0f; + mFogColor = color; + } + else + configureFog(cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); } - void RenderingManager::configureFog(float fogDepth, float underwaterFog, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color) { - mFogDepth = fogDepth; + if(mDistantTerrain) + { + mLandFogStart = dlFactor * (DLLandFogStart - dlOffset*DLLandFogEnd) * 8192.0f; + mLandFogEnd = dlFactor * (1.0f-dlOffset) * DLLandFogEnd * 8192.0f; + mUnderwaterFogStart = DLUnderwaterFogStart * 8192.0f; + mUnderwaterFogEnd = DLUnderwaterFogEnd * 8192.0f; + } + else + { + if(fogDepth == 0.0) + { + mLandFogStart = 0.0f; + mLandFogEnd = std::numeric_limits::max(); + } + else + { + mLandFogStart = mViewDistance * (1 - fogDepth); + mLandFogEnd = mViewDistance; + } + mUnderwaterFogStart = mViewDistance * (1 - underwaterFog); + mUnderwaterFogEnd = mViewDistance; + } mFogColor = color; - mUnderwaterFog = underwaterFog; } SkyManager* RenderingManager::getSkyManager() @@ -520,23 +566,15 @@ namespace MWRender float viewDistance = mViewDistance; viewDistance = std::min(viewDistance, 6666.f); setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); - mStateUpdater->setFogStart(viewDistance * (1 - mUnderwaterFog)); - mStateUpdater->setFogEnd(viewDistance); + mStateUpdater->setFogStart(mUnderwaterFogStart); + mStateUpdater->setFogEnd(mUnderwaterFogEnd); } else { setFogColor(mFogColor); - if (mFogDepth == 0.f) - { - mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(std::numeric_limits::max()); - } - else - { - mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); - mStateUpdater->setFogEnd(mViewDistance); - } + mStateUpdater->setFogStart(mLandFogStart); + mStateUpdater->setFogEnd(mLandFogEnd); } } @@ -963,9 +1001,12 @@ namespace MWRender else if (it->first == "Camera" && it->second == "viewing distance") { mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - mFarClip = mDistantTerrain ? 8192.0f*5.0f : mViewDistance; - mStateUpdater->setFogEnd(mViewDistance); - updateProjectionMatrix(); + if(!mDistantTerrain) + { + mFarClip = mViewDistance; + mStateUpdater->setFogEnd(mViewDistance); + updateProjectionMatrix(); + } } else if (it->first == "General" && (it->second == "texture filter" || it->second == "texture mipmap" || diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 16854aaea..d44266e97 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -106,7 +106,7 @@ namespace MWRender void configureAmbient(const ESM::Cell* cell); void configureFog(const ESM::Cell* cell); - void configureFog(float fogDepth, float underwaterFog, const osg::Vec4f& colour); + void configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour); void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); @@ -241,10 +241,12 @@ namespace MWRender osg::ref_ptr mStateUpdater; - float mFogDepth; + float mLandFogStart; + float mLandFogEnd; + float mUnderwaterFogStart; + float mUnderwaterFogEnd; osg::Vec4f mUnderwaterColor; float mUnderwaterWeight; - float mUnderwaterFog; float mUnderwaterIndoorFog; osg::Vec4f mFogColor; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4357d468c..a9345cdb4 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -65,6 +65,9 @@ namespace MWRender float mFogDepth; + float mDLFogFactor; + float mDLFogOffset; + float mWindSpeed; float mCloudSpeed; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 2f0a2f8cf..bde4c4c22 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -103,6 +103,8 @@ Weather::Weather(const std::string& name, const Fallback::Map& fallback, float stormWindSpeed, float rainSpeed, + float dlFactor, + float dlOffset, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), @@ -129,6 +131,7 @@ Weather::Weather(const std::string& name, , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) + , mDL{dlFactor, dlOffset} , mIsStorm(mWindSpeed > stormWindSpeed) , mRainSpeed(rainSpeed) , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) @@ -541,16 +544,18 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall mTimeSettings.mSunriseTime = mSunriseTime; mWeatherSettings.reserve(10); - addWeather("Clear", fallback); // 0 - addWeather("Cloudy", fallback); // 1 - addWeather("Foggy", fallback); // 2 - addWeather("Overcast", fallback); // 3 - addWeather("Rain", fallback); // 4 - addWeather("Thunderstorm", fallback); // 5 - addWeather("Ashstorm", fallback, "meshes\\ashcloud.nif"); // 6 - addWeather("Blight", fallback, "meshes\\blightcloud.nif"); // 7 - addWeather("Snow", fallback, "meshes\\snow.nif"); // 8 - addWeather("Blizzard", fallback, "meshes\\blizzard.nif"); // 9 + // These distant land fog factor and offset values are the defaults MGE XE provides. Should be + // provided by settings somewhere? + addWeather("Clear", fallback, 1.0f, 0.0f); // 0 + addWeather("Cloudy", fallback, 0.9f, 0.0f); // 1 + addWeather("Foggy", fallback, 0.2f, 30.0f); // 2 + addWeather("Overcast", fallback, 0.7f, 0.0f); // 3 + addWeather("Rain", fallback, 0.5f, 10.0f); // 4 + addWeather("Thunderstorm", fallback, 0.5f, 20.0f); // 5 + addWeather("Ashstorm", fallback, 0.2f, 50.0f, "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, 0.2f, 60.0f, "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, 0.5f, 40.0f, "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, 0.16f, 70.0f, "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) @@ -720,7 +725,8 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mDLFogFactor, + mResult.mDLFogOffset/100.0f, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor, mResult.mSunColor * mResult.mGlareView); @@ -866,11 +872,12 @@ void WeatherManager::clear() inline void WeatherManager::addWeather(const std::string& name, const Fallback::Map& fallback, + float dlFactor, float dlOffset, const std::string& particleEffect) { static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); - Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, particleEffect); + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect); mWeatherSettings.push_back(weather); } @@ -1058,6 +1065,8 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings); + mResult.mDLFogFactor = current.mDL.FogFactor; + mResult.mDLFogOffset = current.mDL.FogOffset; mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); @@ -1113,6 +1122,8 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mDLFogFactor = lerp(current.mDLFogFactor, other.mDLFogFactor, factor); + mResult.mDLFogOffset = lerp(current.mDLFogOffset, other.mDLFogOffset, factor); mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 84a6c5105..4555a9d2a 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -73,6 +73,8 @@ namespace MWWorld const Fallback::Map& fallback, float stormWindSpeed, float rainSpeed, + float dlFactor, + float dlOffset, const std::string& particleEffect); std::string mCloudTexture; @@ -102,6 +104,12 @@ namespace MWWorld // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; + // Fog factor and offset used with distant land rendering. + struct { + float FogFactor; + float FogOffset; + } mDL; + // Sound effect // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) std::string mAmbientLoopSoundID; @@ -293,6 +301,7 @@ namespace MWWorld void addWeather(const std::string& name, const Fallback::Map& fallback, + float dlFactor, float dlOffset, const std::string& particleEffect = ""); void importRegions(); From 4caa7c9674339e23d48ab076a425e272d7427c71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Sep 2017 16:35:36 -0700 Subject: [PATCH 019/321] Workaround older MSVC quirk --- apps/openmw/mwworld/weather.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index bde4c4c22..601379f08 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -131,7 +131,6 @@ Weather::Weather(const std::string& name, , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) - , mDL{dlFactor, dlOffset} , mIsStorm(mWindSpeed > stormWindSpeed) , mRainSpeed(rainSpeed) , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) @@ -145,6 +144,8 @@ Weather::Weather(const std::string& name, , mFlashDecrement(fallback.getFallbackFloat("Weather_" + name + "_Flash_Decrement")) , mFlashBrightness(0.0f) { + mDL.FogFactor = dlFactor; + mDL.FogOffset = dlOffset; mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0"); mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); From 41669467aee26fb0f1e99d10b9120a0831bfcc2d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Sep 2017 17:34:44 -0700 Subject: [PATCH 020/321] Make settings for distant fog parameters --- apps/openmw/mwrender/renderingmanager.cpp | 54 +++++++++++++---------- apps/openmw/mwrender/renderingmanager.hpp | 1 + files/settings-default.cfg | 22 +++++++++ 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ea0fef197..b3fee20b5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -53,16 +53,13 @@ namespace { - // These values are what MGE XE uses by default when distant land is enabled, and are specified - // in cells (8192 units each). Should make them settings somewhere? Or wait to expose them - // "properly"? - const float DLRenderDistance = 5.0f; - const float DLLandFogStart = 2.0f; - const float DLLandFogEnd = 5.0f; - const float DLUnderwaterFogStart = -0.5f; - const float DLUnderwaterFogEnd = 0.3f; - const float DLInteriorFogStart = 0.0f; - const float DLInteriorFogEnd = 2.0f; + float DLRenderDistance; + float DLLandFogStart; + float DLLandFogEnd; + float DLUnderwaterFogStart; + float DLUnderwaterFogEnd; + float DLInteriorFogStart; + float DLInteriorFogEnd; } namespace MWRender @@ -195,6 +192,7 @@ namespace MWRender , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) + , mDistantFog(false) , mDistantTerrain(false) , mFieldOfViewOverridden(false) , mFieldOfViewOverride(0.f) @@ -233,6 +231,15 @@ namespace MWRender mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); + DLRenderDistance = Settings::Manager::getFloat("distant viewing distance", "Camera"); + DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog"); + DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog"); + DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog"); + DLUnderwaterFogEnd = Settings::Manager::getFloat("distant underwater fog end", "Fog"); + DLInteriorFogStart = Settings::Manager::getFloat("distant interior fog start", "Fog"); + DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog"); + + mDistantFog = Settings::Manager::getBool("use distant fog", "Fog"); mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), @@ -305,7 +312,7 @@ namespace MWRender mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); mStateUpdater->setFogEnd(mViewDistance); - mFarClip = mDistantTerrain ? DLRenderDistance*8192.0f : mViewDistance; + mFarClip = mDistantTerrain ? DLRenderDistance : mViewDistance; mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mFarClip)); @@ -498,13 +505,13 @@ namespace MWRender { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); - if(mDistantTerrain) + if(mDistantFog) { float density = std::max(0.2f, cell->mAmbi.mFogDensity); - mLandFogStart = (DLInteriorFogEnd*(1.0f-density) + DLInteriorFogStart*density) * 8192.0f; - mLandFogEnd = DLInteriorFogEnd * 8192.0f; - mUnderwaterFogStart = DLUnderwaterFogStart * 8192.0f; - mUnderwaterFogEnd = DLUnderwaterFogEnd * 8192.0f; + mLandFogStart = (DLInteriorFogEnd*(1.0f-density) + DLInteriorFogStart*density); + mLandFogEnd = DLInteriorFogEnd; + mUnderwaterFogStart = DLUnderwaterFogStart; + mUnderwaterFogEnd = DLUnderwaterFogEnd; mFogColor = color; } else @@ -513,12 +520,12 @@ namespace MWRender void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color) { - if(mDistantTerrain) + if(mDistantFog) { - mLandFogStart = dlFactor * (DLLandFogStart - dlOffset*DLLandFogEnd) * 8192.0f; - mLandFogEnd = dlFactor * (1.0f-dlOffset) * DLLandFogEnd * 8192.0f; - mUnderwaterFogStart = DLUnderwaterFogStart * 8192.0f; - mUnderwaterFogEnd = DLUnderwaterFogEnd * 8192.0f; + mLandFogStart = dlFactor * (DLLandFogStart - dlOffset*DLLandFogEnd); + mLandFogEnd = dlFactor * (1.0f-dlOffset) * DLLandFogEnd; + mUnderwaterFogStart = DLUnderwaterFogStart; + mUnderwaterFogEnd = DLUnderwaterFogEnd; } else { @@ -1002,11 +1009,10 @@ namespace MWRender { mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); if(!mDistantTerrain) - { mFarClip = mViewDistance; + if(!mDistantFog) mStateUpdater->setFogEnd(mViewDistance); - updateProjectionMatrix(); - } + updateProjectionMatrix(); } else if (it->first == "General" && (it->second == "texture filter" || it->second == "texture mipmap" || diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d44266e97..da79fba98 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -256,6 +256,7 @@ namespace MWRender float mNearClip; float mFarClip; float mViewDistance; + bool mDistantFog : 1; bool mDistantTerrain : 1; bool mFieldOfViewOverridden : 1; float mFieldOfViewOverride; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 63afa4438..c1d269e6f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -25,6 +25,10 @@ small feature culling pixel size = 2.0 # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 +# Maximum visible distance for distant terrain. Caution: setting this too high +# can increase the chance for Z-fighting (flickering artifacts). +distant viewing distance = 40960 + # Camera field of view in degrees (e.g. 30.0 to 110.0). # Does not affect the player's hands in the first person camera. field of view = 55.0 @@ -90,6 +94,24 @@ pointers cache size = 40 # If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells distant terrain = false +[Fog] + +# If true, use extended fog parameters for distant terrain not controlled by +# viewing distance. If false, use the standard fog calculations. +use distant fog = false + +distant land fog start = 16384 + +distant land fog end = 40960 + +distant underwater fog start = -4096 + +distant underwater fog end = 2457.6 + +distant interior fog start = 0 + +distant interior fog end = 16384 + [Map] # Size of each exterior cell in pixels in the world map. (e.g. 12 to 24). From 01dbac7b1589e0c2458d5160c27bad1b212d1d31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 11:37:11 -0800 Subject: [PATCH 021/321] Don't use a different setting for distant viewing distance --- apps/openmw/mwrender/renderingmanager.cpp | 14 ++++---------- apps/openmw/mwrender/renderingmanager.hpp | 1 - files/settings-default.cfg | 4 ---- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b3fee20b5..6f0ddba3a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -53,7 +53,6 @@ namespace { - float DLRenderDistance; float DLLandFogStart; float DLLandFogEnd; float DLUnderwaterFogStart; @@ -231,7 +230,6 @@ namespace MWRender mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); - DLRenderDistance = Settings::Manager::getFloat("distant viewing distance", "Camera"); DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog"); DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog"); DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog"); @@ -312,10 +310,8 @@ namespace MWRender mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); mStateUpdater->setFogEnd(mViewDistance); - mFarClip = mDistantTerrain ? DLRenderDistance : mViewDistance; - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mFarClip)); + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); @@ -680,7 +676,7 @@ namespace MWRender rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); - rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mFarClip); + rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); rttCamera->setViewport(0, 0, w, h); @@ -945,10 +941,10 @@ namespace MWRender float fov = mFieldOfView; if (mFieldOfViewOverridden) fov = mFieldOfViewOverride; - mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mFarClip); + mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); mUniformNear->set(mNearClip); - mUniformFar->set(mFarClip); + mUniformFar->set(mViewDistance); } void RenderingManager::updateTextureFiltering() @@ -1008,8 +1004,6 @@ namespace MWRender else if (it->first == "Camera" && it->second == "viewing distance") { mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - if(!mDistantTerrain) - mFarClip = mViewDistance; if(!mDistantFog) mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index da79fba98..1c689d29f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -254,7 +254,6 @@ namespace MWRender float mNightEyeFactor; float mNearClip; - float mFarClip; float mViewDistance; bool mDistantFog : 1; bool mDistantTerrain : 1; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c1d269e6f..dc770425f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -25,10 +25,6 @@ small feature culling pixel size = 2.0 # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 -# Maximum visible distance for distant terrain. Caution: setting this too high -# can increase the chance for Z-fighting (flickering artifacts). -distant viewing distance = 40960 - # Camera field of view in degrees (e.g. 30.0 to 110.0). # Does not affect the player's hands in the first person camera. field of view = 55.0 From 6c3ac834c43600ae3e3829e6d1f3c6080982de7d Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 5 Mar 2018 19:57:19 -0600 Subject: [PATCH 022/321] Preventing max quicksaves from being saved to settings.cfg if it is unchanged. --- apps/launcher/advancedpage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 0abefcc8f..9b6e5fa8c 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -73,7 +73,10 @@ void Launcher::AdvancedPage::saveSettings() // Saves Settings saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); - mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksavesComboBox->value()); + int maximumQuicksaves = maximumQuicksavesComboBox->value(); + if (maximumQuicksaves != mEngineSettings.getInt("max quicksaves", "Saves")) { + mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves); + } // Other Settings std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString(); From da74ca5ce0242cfd107a98d7934835aba178024f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 5 Mar 2018 21:26:59 -0600 Subject: [PATCH 023/321] Add testing options to the Settings page --- apps/launcher/settingspage.cpp | 42 ++++ apps/launcher/settingspage.hpp | 1 + files/ui/settingspage.ui | 367 ++++++++++++++++++++------------- 3 files changed, 265 insertions(+), 145 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 843b51391..906459c23 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -177,6 +177,28 @@ void Launcher::SettingsPage::on_browseButton_clicked() } } +void Launcher::SettingsPage::on_runScriptAfterStartupBrowseButton_clicked() +{ + QString scriptFile = QFileDialog::getOpenFileName( + this, + QObject::tr("Select script file"), + QDir::currentPath(), + QString(tr("Text file (*.txt)"))); + + + if (scriptFile.isEmpty()) + return; + + QFileInfo info(scriptFile); + + if (!info.exists() || !info.isReadable()) + return; + + const QString path(QDir::toNativeSeparators(info.absoluteFilePath())); + + runScriptAfterStartupField->setText(path); +} + void Launcher::SettingsPage::wizardStarted() { mMain->hide(); // Hide the launcher @@ -260,6 +282,19 @@ void Launcher::SettingsPage::saveSettings() } else { mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252")); } + + // Testing + int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked; + if (skipMenu != mGameSettings.value("skip-menu").toInt()) + mGameSettings.setValue("skip-menu", QString::number(skipMenu)); + + QString startCell = startDefaultCharacterAtField->text(); + if (startCell != mGameSettings.value("start")) { + mGameSettings.setValue("start", startCell); + } + QString scriptRun = runScriptAfterStartupField->text(); + if (scriptRun != mGameSettings.value("script-run")) + mGameSettings.setValue("script-run", scriptRun); } bool Launcher::SettingsPage::loadSettings() @@ -271,5 +306,12 @@ bool Launcher::SettingsPage::loadSettings() if (index != -1) languageComboBox->setCurrentIndex(index); + // Testing + if (mGameSettings.value("skip-menu").toInt() == 1) + skipMenuCheckBox->setCheckState(Qt::Checked); + + startDefaultCharacterAtField->setText(mGameSettings.value("start")); + runScriptAfterStartupField->setText(mGameSettings.value("script-run")); + return true; } diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index ccc2061dd..12539a0fc 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -38,6 +38,7 @@ namespace Launcher void on_wizardButton_clicked(); void on_importerButton_clicked(); void on_browseButton_clicked(); + void on_runScriptAfterStartupBrowseButton_clicked(); void wizardStarted(); void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus); diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index f4f41f839..eed723adb 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -7,7 +7,7 @@ 0 0 514 - 397 + 532 @@ -15,153 +15,230 @@ - - - Morrowind Content Language + + + true - - - - - - 250 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 0 + 0 + 473 + 510 + + + + + + + Morrowind Content Language + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 250 + 0 + + + + + + + + + + + Morrowind Installation Wizard + + + + + + Run &Installation Wizard + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Morrowind Settings Importer + + + + + + + + File to import settings from: + + + + + + + + + + Browse... + + + + + + + + + Import add-on and plugin selection (creates a new Content List) + + + true + + + + + + + + + Run &Settings Importer + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 4 + + + false + + + + + + + + + + Testing + + + + + + Skip menu and generate default character + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Start default character at + + + + + + + default cell + + + + + + + + + Run script after startup: + + + + + + + + + + + + Browse… + + + + + + + + + + - - - - Morrowind Installation Wizard - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Run &Installation Wizard - - - - - - - - - - Morrowind Settings Importer - - - - - - - - File to import settings from: - - - - - - - - - - Browse... - - - - - - - - - Import add-on and plugin selection (creates a new Content List) - - - true - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Run &Settings Importer - - - - - - - - - 4 - - - false - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - From 082e166faefd2daa149d3af49657c98bbb67db5f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 5 Mar 2018 21:41:29 -0600 Subject: [PATCH 024/321] Making "start default character at" field enabled or disabled by the previous checkbox --- apps/launcher/settingspage.cpp | 55 ++++++++++++++++++++-------------- apps/launcher/settingspage.hpp | 4 ++- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 906459c23..ec784c9d3 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -177,28 +177,6 @@ void Launcher::SettingsPage::on_browseButton_clicked() } } -void Launcher::SettingsPage::on_runScriptAfterStartupBrowseButton_clicked() -{ - QString scriptFile = QFileDialog::getOpenFileName( - this, - QObject::tr("Select script file"), - QDir::currentPath(), - QString(tr("Text file (*.txt)"))); - - - if (scriptFile.isEmpty()) - return; - - QFileInfo info(scriptFile); - - if (!info.exists() || !info.isReadable()) - return; - - const QString path(QDir::toNativeSeparators(info.absoluteFilePath())); - - runScriptAfterStartupField->setText(path); -} - void Launcher::SettingsPage::wizardStarted() { mMain->hide(); // Hide the launcher @@ -269,6 +247,33 @@ void Launcher::SettingsPage::updateOkButton(const QString &text) : mProfileDialog->setOkButtonEnabled(true); } +void Launcher::SettingsPage::on_skipMenuCheckBox_stateChanged(int state) { + startDefaultCharacterAtLabel->setEnabled(state == Qt::Checked); + startDefaultCharacterAtField->setEnabled(state == Qt::Checked); +} + +void Launcher::SettingsPage::on_runScriptAfterStartupBrowseButton_clicked() +{ + QString scriptFile = QFileDialog::getOpenFileName( + this, + QObject::tr("Select script file"), + QDir::currentPath(), + QString(tr("Text file (*.txt)"))); + + + if (scriptFile.isEmpty()) + return; + + QFileInfo info(scriptFile); + + if (!info.exists() || !info.isReadable()) + return; + + const QString path(QDir::toNativeSeparators(info.absoluteFilePath())); + + runScriptAfterStartupField->setText(path); +} + void Launcher::SettingsPage::saveSettings() { QString language(languageComboBox->currentText()); @@ -307,8 +312,12 @@ bool Launcher::SettingsPage::loadSettings() languageComboBox->setCurrentIndex(index); // Testing - if (mGameSettings.value("skip-menu").toInt() == 1) + bool skipMenu = mGameSettings.value("skip-menu").toInt() == Qt::Checked; + if (skipMenu) { skipMenuCheckBox->setCheckState(Qt::Checked); + } + startDefaultCharacterAtLabel->setEnabled(skipMenu); + startDefaultCharacterAtField->setEnabled(skipMenu); startDefaultCharacterAtField->setText(mGameSettings.value("start")); runScriptAfterStartupField->setText(mGameSettings.value("script-run")); diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index 12539a0fc..a9de974ff 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -38,7 +38,6 @@ namespace Launcher void on_wizardButton_clicked(); void on_importerButton_clicked(); void on_browseButton_clicked(); - void on_runScriptAfterStartupBrowseButton_clicked(); void wizardStarted(); void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus); @@ -48,6 +47,9 @@ namespace Launcher void updateOkButton(const QString &text); + void on_skipMenuCheckBox_stateChanged(int state); + void on_runScriptAfterStartupBrowseButton_clicked(); + private: Process::ProcessInvoker *mWizardInvoker; From dcc262ed911fa4c0ba3db4e7f47e0d3cb22d80dd Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 5 Mar 2018 23:10:08 -0600 Subject: [PATCH 025/321] Fixing Skip Menu checkbox not working correctly --- apps/launcher/settingspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index ec784c9d3..986aee048 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -312,7 +312,7 @@ bool Launcher::SettingsPage::loadSettings() languageComboBox->setCurrentIndex(index); // Testing - bool skipMenu = mGameSettings.value("skip-menu").toInt() == Qt::Checked; + bool skipMenu = mGameSettings.value("skip-menu").toInt() == 1; if (skipMenu) { skipMenuCheckBox->setCheckState(Qt::Checked); } From 60a663ef58dfed6f84d613942266b397d61cb420 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 6 Mar 2018 16:14:29 +0300 Subject: [PATCH 026/321] Account for all possible count values in getCountString (Bug #4346) --- apps/openmw/mwgui/itemwidget.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index a31eb9c76..e793dbf58 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -16,7 +16,12 @@ namespace { if (count == 1) return ""; - if (count > 9999) + + if (count > 999999999) + return MyGUI::utility::toString(int(count/1000000000.f)) + "b"; + else if (count > 999999) + return MyGUI::utility::toString(int(count/1000000.f)) + "m"; + else if (count > 9999) return MyGUI::utility::toString(int(count/1000.f)) + "k"; else return MyGUI::utility::toString(count); From 3b922d810a01401d8a8d9b138375c5dbaed63beb Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 7 Mar 2018 14:10:58 +0300 Subject: [PATCH 027/321] Don't use floating point arithmetics for formatted count (Bug #4346) --- apps/openmw/mwgui/itemwidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index e793dbf58..6b5be0314 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -18,11 +18,11 @@ namespace return ""; if (count > 999999999) - return MyGUI::utility::toString(int(count/1000000000.f)) + "b"; + return MyGUI::utility::toString(count/1000000000) + "b"; else if (count > 999999) - return MyGUI::utility::toString(int(count/1000000.f)) + "m"; + return MyGUI::utility::toString(count/1000000) + "m"; else if (count > 9999) - return MyGUI::utility::toString(int(count/1000.f)) + "k"; + return MyGUI::utility::toString(count/1000) + "k"; else return MyGUI::utility::toString(count); } From 6931f6cadc14128df681c66ee269cee739aba31c Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 7 Mar 2018 18:37:43 -0600 Subject: [PATCH 028/321] Adding message indicating the purpose of the "Testing" block --- files/ui/settingspage.ui | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index eed723adb..f1b833c60 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -23,9 +23,9 @@ 0 - 0 + -44 473 - 510 + 567 @@ -170,6 +170,23 @@ Testing + + + + These settings are intended for testing mods and may cause issues if used for normal gameplay. + + + true + + + + + + + Qt::Horizontal + + + From dfcd243150243af5f1f0e049309ba1dc6f6acbd1 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 7 Mar 2018 19:57:54 -0600 Subject: [PATCH 029/321] Remove the word "interior" from cell not found message --- apps/openmw/mwworld/store.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 9279e3fe7..158d3f771 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -592,7 +592,7 @@ namespace MWWorld const ESM::Cell *ptr = search(id); if (ptr == 0) { std::ostringstream msg; - msg << "Interior cell '" << id << "' not found"; + msg << "Cell '" << id << "' not found"; throw std::runtime_error(msg.str()); } return ptr; From d3b623b5d32e8eba6c135ba62acfe049840040a4 Mon Sep 17 00:00:00 2001 From: Harald H Date: Thu, 8 Mar 2018 21:23:24 +0100 Subject: [PATCH 030/321] http to https for supported urls (#1625) * http to https for supported urls * http to https * http to https * http to https * http to https * http to https * http to https * http to https * http tp https * http to https * http to https * http to https * http to https * http to https * http to https * http to https * http to https * some url fixes * http to https --- CI/before_script.msvc.sh | 16 +- CMakeLists.txt | 4 +- CONTRIBUTING.md | 2 +- LICENSE | 8 +- README.md | 6 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/pathgrid.cpp | 2 +- apps/openmw/mwsound/alext.h | 2 +- apps/openmw/mwsound/ffmpeg_decoder.hpp | 2 +- cmake/FindFreetype.cmake | 2 +- cmake/FindLIBUNSHIELD.cmake | 2 +- cmake/FindOpenGLES.cmake | 2 +- components/bsa/bsa_file.cpp | 4 +- components/bsa/bsa_file.hpp | 4 +- components/nif/controlled.hpp | 4 +- components/nif/controller.hpp | 4 +- components/nif/data.hpp | 4 +- components/nif/effect.hpp | 4 +- components/nif/extra.hpp | 4 +- components/nif/niftypes.hpp | 4 +- components/nif/property.hpp | 4 +- components/nif/record.hpp | 4 +- components/settings/settings.cpp | 2 +- docs/Doxyfile.cmake | 53 +++--- docs/DoxyfilePages.cmake | 16 +- .../openmw-cs/files-and-directories.rst | 6 +- docs/source/manuals/openmw-cs/tour.rst | 32 ++-- .../modding/convert_bump_mapped_mods.rst | 24 +-- docs/source/reference/modding/font.rst | 4 +- extern/oics/tinyxmlparser.cpp | 153 +++++++++--------- files/mac/openmw-Info.plist.in | 2 +- files/mac/openmw-cs-Info.plist.in | 2 +- files/openmw.appdata.xml | 6 +- files/settings-default.cfg | 2 +- files/shaders/water_fragment.glsl | 20 +-- 36 files changed, 205 insertions(+), 209 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index ee48c1f68..2a052912a 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -303,25 +303,25 @@ if [ -z $SKIP_DOWNLOAD ]; then # Boost if [ -z $APPVEYOR ]; then download "Boost 1.61.0" \ - "http://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \ + "https://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \ "boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe" fi # Bullet download "Bullet 2.86" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" \ "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" # FFmpeg download "FFmpeg 3.2.4" \ - "http://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.2.4-win${BITS}-shared.zip" \ + "https://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.2.4-win${BITS}-shared.zip" \ "ffmpeg-3.2.4-win${BITS}.zip" \ - "http://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.2.4-win${BITS}-dev.zip" \ + "https://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.2.4-win${BITS}-dev.zip" \ "ffmpeg-3.2.4-dev-win${BITS}.zip" # MyGUI download "MyGUI 3.2.2" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \ "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" # OpenAL @@ -331,7 +331,7 @@ if [ -z $SKIP_DOWNLOAD ]; then # OSG download "OpenSceneGraph 3.4.1-scrawl" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" # Qt @@ -343,9 +343,9 @@ if [ -z $SKIP_DOWNLOAD ]; then fi download "Qt 5.7.2" \ - "http://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \ + "https://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \ "qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \ "qt-5-install.qs" fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 2923612fb..7c1f961f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -505,8 +505,8 @@ if(WIN32) SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") - SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") - SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") + SET(CPACK_NSIS_HELP_LINK "https:\\\\\\\\www.openmw.org") + SET(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe") SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c82d1dfd..b5543d11e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ How to contribute to OpenMW Not sure what to do with all your free time? Pick out a task from here: -http://bugs.openmw.org/ +https://bugs.openmw.org/ Currently, we are focused on completing the MW game experience and general polishing. Features out of this scope may be approved in some cases, but you should probably start a discussion first. diff --git a/LICENSE b/LICENSE index 9cecc1d46..9d742475f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/README.md b/README.md index 0b5f63f93..368609332 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction * Version: 0.43.0 * License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information) -* Website: http://www.openmw.org +* Website: https://www.openmw.org * IRC: #openmw on irc.freenode.net Font Licenses: @@ -30,8 +30,8 @@ Getting Started * [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup) * [Testing the game](https://wiki.openmw.org/index.php?title=Testing) * [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) -* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! -* [Known issues](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) +* [Report a bug](https://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! +* [Known issues](https://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path ------------- diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 134bbf943..974a08c11 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -406,7 +406,7 @@ namespace MWClass // store ptr.getRefData().setCustomData (data.release()); - getInventoryStore(ptr).autoEquip(ptr); + getInventoryStore(ptr).autoEquip(ptr); } } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 676f01922..f88b20a10 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see - * http://www.gnu.org/licenses/ . + * https://www.gnu.org/licenses/ . */ #include "character.hpp" diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index c0122a861..ea4c973b7 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -8,7 +8,7 @@ namespace { - // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html + // See https://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html // // One of the smallest cost in Seyda Neen is between points 77 & 78: // pt x y diff --git a/apps/openmw/mwsound/alext.h b/apps/openmw/mwsound/alext.h index 4b9a15537..7162fa955 100644 --- a/apps/openmw/mwsound/alext.h +++ b/apps/openmw/mwsound/alext.h @@ -15,7 +15,7 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html + * Or go to https://www.gnu.org/copyleft/lgpl.html */ #ifndef AL_ALEXT_H diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index e06a68d64..2b76e0d7d 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -21,7 +21,7 @@ extern "C" // From version 54.56 binkaudio encoding format changed from S16 to FLTP. See: // https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d -// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 +// https://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 #include } diff --git a/cmake/FindFreetype.cmake b/cmake/FindFreetype.cmake index 3d28613ae..3b7586835 100644 --- a/cmake/FindFreetype.cmake +++ b/cmake/FindFreetype.cmake @@ -1,7 +1,7 @@ #------------------------------------------------------------------- # This file is part of the CMake build system for OGRE # (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ +# For the latest info, see https://www.ogre3d.org/ # # The contents of this file are placed in the public domain. Feel # free to make use of it in any way you like. diff --git a/cmake/FindLIBUNSHIELD.cmake b/cmake/FindLIBUNSHIELD.cmake index 285740b63..ee6414646 100644 --- a/cmake/FindLIBUNSHIELD.cmake +++ b/cmake/FindLIBUNSHIELD.cmake @@ -4,7 +4,7 @@ # LIBUNSHIELD_FOUND, if false, do not try to link to LibUnshield # LIBUNSHIELD_INCLUDE_DIRS, where to find the headers # -# Created by Tom Mason (wheybags) for OpenMW (http://openmw.org), based on FindMPG123.cmake +# Created by Tom Mason (wheybags) for OpenMW (https://openmw.org), based on FindMPG123.cmake # # Ripped off from other sources. In fact, this file is so generic (I # just did a search and replace on another file) that I wonder why the diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake index 7ee2c07f1..6a0466409 100644 --- a/cmake/FindOpenGLES.cmake +++ b/cmake/FindOpenGLES.cmake @@ -1,7 +1,7 @@ #------------------------------------------------------------------- # This file is part of the CMake build system for OGRE # (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ +# For the latest info, see https://www.ogre3d.org/ # # The contents of this file are placed in the public domain. Feel # free to make use of it in any way you like. diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index c4be428b3..8905a86a1 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (bsa_file.cpp) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 5ff86ef65..196dc30fb 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (bsa_file.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 5601474ac..be48e912e 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (controlled.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 0861dfa6b..527bb74af 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (controller.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 9b4a3a67c..6b7aa579b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (data.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 015809a68..453e4b04c 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (effect.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 1e5a8616d..d935add55 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (extra.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 5827448fd..778625717 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (nif_types.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 96156c6d8..f46f8ef27 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (property.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 605c4d76e..b8597f7d1 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (record.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 2e7b5a8ae..15a222d31 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -292,7 +292,7 @@ public: ostream << "# to its default, simply remove it from this file. For available" << std::endl; ostream << "# settings, see the file 'settings-default.cfg' or the documentation at:" << std::endl; ostream << "#" << std::endl; - ostream << "# http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html" << std::endl; + ostream << "# https://openmw.readthedocs.io/en/master/reference/modding/settings/index.html" << std::endl; } // We still have one more thing to do before we're completely done writing the file. diff --git a/docs/Doxyfile.cmake b/docs/Doxyfile.cmake index 38ad84165..71ce32069 100644 --- a/docs/Doxyfile.cmake +++ b/docs/Doxyfile.cmake @@ -20,7 +20,7 @@ # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# built into libc) for the transcoding. See https://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. @@ -295,7 +295,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -328,7 +328,7 @@ BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -687,7 +687,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See @@ -772,7 +772,7 @@ INPUT = @OpenMW_SOURCE_DIR@/apps \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. @@ -993,7 +993,7 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: @@ -1136,7 +1136,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1194,7 +1194,7 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# environment (see: https://developer.apple.com/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in @@ -1239,7 +1239,7 @@ DOCSET_PUBLISHER_NAME = OpenMW # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1315,7 +1315,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1323,8 +1323,7 @@ QHP_NAMESPACE = org.openmw # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1332,23 +1331,21 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1453,7 +1450,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1465,7 +1462,7 @@ USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# https://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1480,11 +1477,11 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1495,7 +1492,7 @@ MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: https://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1542,7 +1539,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1555,7 +1552,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1726,7 +1723,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1882,7 +1879,7 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of +# Definitions (see http://autogen.sourceforge.net) file that captures the structure of # the code including all documentation. Note that this feature is still # experimental and incomplete at the moment. # The default value is: NO. @@ -2093,7 +2090,7 @@ HIDE_UNDOC_RELATIONS = NO # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: YES. diff --git a/docs/DoxyfilePages.cmake b/docs/DoxyfilePages.cmake index d50a043d6..f3454c9d0 100644 --- a/docs/DoxyfilePages.cmake +++ b/docs/DoxyfilePages.cmake @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -581,7 +581,7 @@ INPUT = @OpenMW_SOURCE_DIR@/apps \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -753,7 +753,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -928,30 +928,30 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. +# Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. -# Qt Help Project / Filter Attributes. +# Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = diff --git a/docs/source/manuals/openmw-cs/files-and-directories.rst b/docs/source/manuals/openmw-cs/files-and-directories.rst index 77593dece..ae39082d7 100644 --- a/docs/source/manuals/openmw-cs/files-and-directories.rst +++ b/docs/source/manuals/openmw-cs/files-and-directories.rst @@ -145,7 +145,7 @@ and a place where OpenMW CS looks for already existing files. Resource files ============== -.. TODO This paragraph sounds weird +.. TODO This paragraph sounds weird Unless we are talking about a fully text based game, like Zork or Rogue, one would expect that a video game is using some media files: 3D models with @@ -219,6 +219,6 @@ files for textures. .. Hyperlink targets for the entire document -.. _FFmpeg: http://ffmpeg.org +.. _FFmpeg: https://ffmpeg.org .. _Vorbis: http://www.vorbis.com -.. _Theora: http://www.theora.org +.. _Theora: https://www.theora.org diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index 645c18453..83b7aae27 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -3,7 +3,7 @@ A Tour through OpenMW CS: making a magic ring In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision -effect while being worn. You do not need previous Morrowind modding experience, +effect while being worn. You do not need previous Morrowind modding experience, but you should be familiar with the game itself. There will be no scripting necessary, we can achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly @@ -133,7 +133,7 @@ the filter directly into the filter field rather than the name of an existing filter. To signify that we are using an instant filter the have to use `!` as the first character. Type the following into the field: -.. code:: +.. code:: !string("id", ".*ring.*") @@ -217,20 +217,20 @@ actually modify the contents of the game. Adding to an NPC ================ -The simplest way is probably to add it to the inventory of a shopkeeper. +The simplest way is probably to add it to the inventory of a shopkeeper. An obvious candidate is Arrille in Seyda Neen - he's quick to find in a new game and he's easy to find in the CS as his name comes early alphabetically. .. figure:: _static/images/chapter-1/Ring_to_Arrille.png :alt: Putting the ring into Arrille's inventory - -Open the CS and open the *Objects* table (*World* → *Objects*). + +Open the CS and open the *Objects* table (*World* → *Objects*). Scroll down to Arrille, or use a filter like !string("ID","arrille"). -Open another pane to edit him - either right click and select edit or use the +Open another pane to edit him - either right click and select edit or use the shortcut (default is shift double-click). Scroll down to the inventory section -and right click to add a new row. Type in the id of the ring (or find it in the -object pane, and drag and drop). Set the number of rings for him to stock - with +and right click to add a new row. Type in the id of the ring (or find it in the +object pane, and drag and drop). Set the number of rings for him to stock - with a negative number indicating that he will restock again to maintain that level. However, it's an attractive item, so he will probably wear it rather than sell it. @@ -241,7 +241,7 @@ Fargoth to give it to the player in exchange for his healing ring. .. figure:: _static/images/chapter-1/Ring_to_Fargoth_1.png :alt: Editing Fargoth to give ring to player - + Open the *Topicinfo* Table (*Characters* → *Topic Infos*). Use a filter !string(Topic,ring) and select the row with a response starting with "You found it!". Edit the record, firstly by adding a bit more to the response, then by adding a line to the script @@ -297,7 +297,7 @@ Placing in plain sight ===================== Let's hide the Ring of Night vision in the cabin of the [Ancient Shipwreck] -(http://en.uesp.net/wiki/Morrowind:Ancient_Shipwreck), a derelict vessel +(https://en.uesp.net/wiki/Morrowind:Ancient_Shipwreck), a derelict vessel southeast of Dagon Fel. Open the list of Cells (*World* → *Cells*) and find "Ancient Shipwreck, Cabin". @@ -333,8 +333,8 @@ This is probably a suitable place to start talking about how navigation differs in vanilla Morrowind. There is advice in Scripting for Dummies, the definitive manual for Morrowind Scripting: -"If you give your scripts a common tag, that will make it easier to jump between the -different scripts of your project, e.g. start every script name with AA_Scriptname +"If you give your scripts a common tag, that will make it easier to jump between the +different scripts of your project, e.g. start every script name with AA_Scriptname this will put them right at the beginning of the list and keep them neatly together." This is valid for the rather poorer navigation facilities there, but it's not sensible for @@ -359,12 +359,12 @@ the base game. "Modified" status will cover items from the base game which have been modified in this addon. -Click on the top of the column to toggle between ascending and descending order - thus between "Added" -and "Modified" at the top. Or put your desired modified status into a filter then sort alpabetically +Click on the top of the column to toggle between ascending and descending order - thus between "Added" +and "Modified" at the top. Or put your desired modified status into a filter then sort alpabetically on a different column. - + Checking your new addon ======================= @@ -372,4 +372,4 @@ Launch OpenMW and in the launcher under *Data Files* check your addon, if it's n already checked. Load a game and make your way to Seyda Neen - or start a new game. Check whether Arrille has one (or more) for sale, and whether Fargoth give you one -when you return his healing ring. \ No newline at end of file +when you return his healing ring. diff --git a/docs/source/reference/modding/convert_bump_mapped_mods.rst b/docs/source/reference/modding/convert_bump_mapped_mods.rst index 71ac29468..1891b5c4d 100644 --- a/docs/source/reference/modding/convert_bump_mapped_mods.rst +++ b/docs/source/reference/modding/convert_bump_mapped_mods.rst @@ -20,7 +20,7 @@ General introduction to normal map conversion :Authors: Joakim (Lysol) Berg :Updated: 2016-11-11 -This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. +This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. *Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope. There are binaries available for Windows, but not for Mac or Linux. Reports say that NifSkope versions 1.X will compile on Linux as long as you have Qt packages installed, while the later 2.X versions will not compile. @@ -179,24 +179,24 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Remove all these tags by selecting them one at a time and press right click>Block>Remove Branch. (Ctrl-Del) #. Repeat this on all the affected models. #. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. -#. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. +#. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. #. OpenMW detects normal maps if they have the same name as the base diffuse texture, but with a *_n.dds* suffix. In this mod, the normal maps has a suffix of *_nm.dds*. Change all the files that ends with *_nm.dds* to instead end with *_n.dds*. #. Finally, `we are done`_! Since these models have one or two textures applied to them, the fix was not that time-consuming. It gets worse when you have to fix a model that uses loads of textures. The principle is the same, it just requires more manual work which is annoying and takes time. -.. _`Netch Bump mapped`: http://www.nexusmods.com/morrowind/mods/42851/? -.. _`Hlaalu Bump mapped`: http://www.nexusmods.com/morrowind/mods/42396/? +.. _`Netch Bump mapped`: https://www.nexusmods.com/morrowind/mods/42851/? +.. _`Hlaalu Bump mapped`: https://www.nexusmods.com/morrowind/mods/42396/? .. _`On the Rocks`: http://mw.modhistory.com/download-44-14107 .. _`texture modding`: https://wiki.openmw.org/index.php?title=TextureModding -.. _`MGE XE`: http://www.nexusmods.com/morrowind/mods/26348/? -.. _PeterBitt: http://www.nexusmods.com/morrowind/users/4381248/? -.. _`PBR Scamp Replacer`: http://www.nexusmods.com/morrowind/mods/44314/? +.. _`MGE XE`: https://www.nexusmods.com/morrowind/mods/26348/? +.. _PeterBitt: https://www.nexusmods.com/morrowind/users/4381248/? +.. _`PBR Scamp Replacer`: https://www.nexusmods.com/morrowind/mods/44314/? .. _settings.cfg: https://wiki.openmw.org/index.php?title=Settings .. _`Multiple data folders`: https://wiki.openmw.org/index.php?title=Mod_installation -.. _`Various Things - Sacks`: http://www.nexusmods.com/morrowind/mods/42558/? -.. _Lead: http://imgur.com/bwpcYlc +.. _`Various Things - Sacks`: https://www.nexusmods.com/morrowind/mods/42558/? +.. _Lead: https://imgur.com/bwpcYlc .. _NifSkope: http://niftools.sourceforge.net/wiki/NifSkope -.. _Blocks: http://imgur.com/VmQC0WG -.. _`no longer have shiny models`: http://imgur.com/vu1k7n1 -.. _`we are done`: http://imgur.com/yyZxlTw +.. _Blocks: https://imgur.com/VmQC0WG +.. _`no longer have shiny models`: https://imgur.com/vu1k7n1 +.. _`we are done`: https://imgur.com/yyZxlTw diff --git a/docs/source/reference/modding/font.rst b/docs/source/reference/modding/font.rst index 5f01b12d9..80d01c27f 100644 --- a/docs/source/reference/modding/font.rst +++ b/docs/source/reference/modding/font.rst @@ -15,7 +15,7 @@ Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. Th - To replace the primary "Magic Cards" font: - #. Download `Pelagiad `_ by Isak Larborn (aka Isaskar). + #. Download `Pelagiad `_ by Isak Larborn (aka Isaskar). #. Install the ``openmw_font.xml`` file into ``resources/mygui/openmw_font.xml`` in your OpenMW installation. #. Copy ``Pelagiad.ttf`` into ``resources/mygui/`` as well. #. If desired, you can now delete the original ``Magic_Cards.*`` files from your Data Files/Fonts directory. @@ -74,4 +74,4 @@ Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. Th Bitmap fonts ------------ -Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because of no Unicode support. MyGUI has its own format for bitmap fonts. An example can be seen by using the --export-fonts command line option (see above), which converts Morrowind ``.fnt`` to a MyGUI bitmap font. This is the recommended format to use if you wish to edit Morrowind's bitmap font or create a new bitmap font. \ No newline at end of file +Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because of no Unicode support. MyGUI has its own format for bitmap fonts. An example can be seen by using the --export-fonts command line option (see above), which converts Morrowind ``.fnt`` to a MyGUI bitmap font. This is the recommended format to use if you wish to edit Morrowind's bitmap font or create a new bitmap font. diff --git a/extern/oics/tinyxmlparser.cpp b/extern/oics/tinyxmlparser.cpp index 253cd93ff..d5bda8fee 100644 --- a/extern/oics/tinyxmlparser.cpp +++ b/extern/oics/tinyxmlparser.cpp @@ -2,23 +2,23 @@ www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source +3. This notice may not be removed or altered from any source distribution. */ @@ -39,8 +39,8 @@ distribution. // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, @@ -50,20 +50,20 @@ TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = }; // Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html +// https://www.unicode.org/faq/utf_bom.html // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: +// Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be -// ef bf bf +// ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; -const int TiXmlBase::utf8ByteTable[256] = +const int TiXmlBase::utf8ByteTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 @@ -75,9 +75,9 @@ const int TiXmlBase::utf8ByteTable[256] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte @@ -91,7 +91,7 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - if (input < 0x80) + if (input < 0x80) *length = 1; else if ( input < 0x800 ) *length = 2; @@ -105,22 +105,22 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng output += *length; // Scary scary fall throughs. - switch (*length) + switch (*length) { case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 1: - --output; + --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); } } @@ -130,7 +130,7 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very + // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) @@ -151,7 +151,7 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very + // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) @@ -224,7 +224,7 @@ void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) case '\r': // bump down to the next line ++row; - col = 0; + col = 0; // Eat the character ++p; @@ -266,11 +266,11 @@ void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) // In these cases, don't advance the column. These are // 0-width spaces. if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; + p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; + p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; + p += 3; else { p +=3; ++col; } // A normal character. } @@ -322,10 +322,10 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) while ( *p ) { const unsigned char* pU = (const unsigned char*)p; - + // Skip the stupid Microsoft UTF-8 Byte order marks if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) { p += 3; @@ -413,12 +413,12 @@ const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncodi // After that, they can be letters, underscores, numbers, // hyphens, or colons. (Colons are valid ony for namespaces, // but tinyxml can't tell namespaces from names.) - if ( p && *p + if ( p && *p && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) { const char* start = p; while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) + && ( IsAlphaNum( (unsigned char ) *p, encoding ) || *p == '_' || *p == '-' || *p == '.' @@ -469,7 +469,7 @@ const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXml ucs += mult * (*q - 'a' + 10); else if ( *q >= 'A' && *q <= 'F' ) ucs += mult * (*q - 'A' + 10 ); - else + else return 0; mult *= 16; --q; @@ -492,7 +492,7 @@ const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXml { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); - else + else return 0; mult *= 10; --q; @@ -571,10 +571,10 @@ bool TiXmlBase::StringEqual( const char* p, return false; } -const char* TiXmlBase::ReadText( const char* p, - TIXML_STRING * text, - bool trimWhiteSpace, - const char* endTag, +const char* TiXmlBase::ReadText( const char* p, + TIXML_STRING * text, + bool trimWhiteSpace, + const char* endTag, bool caseInsensitive, TiXmlEncoding encoding ) { @@ -631,7 +631,7 @@ const char* TiXmlBase::ReadText( const char* p, } } } - if ( p ) + if ( p ) p += strlen( endTag ); return p; } @@ -647,7 +647,7 @@ void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. - if ( !StreamTo( in, '<', tag ) ) + if ( !StreamTo( in, '<', tag ) ) { SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return; @@ -669,7 +669,7 @@ void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) if ( in->good() ) { - // We now have something we presume to be a node of + // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); @@ -778,7 +778,7 @@ const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiX encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else + else encoding = TIXML_ENCODING_LEGACY; } @@ -796,7 +796,7 @@ const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiX } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ +{ // The first error in a chain is more accurate - don't set again! if ( error ) return; @@ -833,7 +833,7 @@ TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) return 0; } - // What is this thing? + // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: - + org.openmw.desktop CC0-1.0 - GPL-3.0 and MIT + GPL-3.0 and MIT OpenMW Unofficial open source engine re-implementation of the game Morrowind @@ -20,7 +20,6 @@ Copyright 2017 Bret Curtis You will still need the original game data to play OpenMW.

- https://wiki.openmw.org/images/b/b2/Openmw_0.11.1_launcher_1.png @@ -34,7 +33,18 @@ Copyright 2017 Bret Curtis https://wiki.openmw.org/images/5/5b/Screenshot_Vivec_seen_from_Ebonheart_0.35.png Vivec seen from Ebonheart on OpenMW + + http://wiki.openmw.org/images/a/a3/0.40_Screenshot-Balmora_3.png + Balmora at morning on OpenMW + + + Game + RolePlaying + + + + https://openmw.org https://bugs.openmw.org/ https://openmw.org/faq/ From 55a6344fb0dca253c2177a1bacd8e5c51ec989ba Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 22 Apr 2018 15:41:07 +0000 Subject: [PATCH 087/321] Revert log spam --- components/fallback/fallback.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/fallback/fallback.cpp b/components/fallback/fallback.cpp index ce6cba313..edc3f2678 100644 --- a/components/fallback/fallback.cpp +++ b/components/fallback/fallback.cpp @@ -1,7 +1,5 @@ #include "fallback.hpp" -#include - #include @@ -19,7 +17,6 @@ namespace Fallback std::map::const_iterator it; if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) { - std::cerr << "Warning: fallback value " << fall << " not found." << std::endl; return ""; } return it->second; From b69e812a52827d5e6e24af9fcd76335abff505f8 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 22 Apr 2018 22:31:56 +0300 Subject: [PATCH 088/321] Utilize inventory character preview lighting color fallback settings --- apps/openmw/mwrender/characterpreview.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index f7219959a..622728c22 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "../mwbase/environment.hpp" @@ -161,11 +162,18 @@ namespace MWRender lightmodel->setAmbientIntensity(osg::Vec4(0.25, 0.25, 0.25, 1.0)); stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); - /// \todo Read the fallback values from INIImporter (Inventory:Directional*) ? osg::ref_ptr light = new osg::Light; + const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback(); + float diffuseR = fallback->getFallbackFloat("Inventory_DirectionalDiffuseR"); + float diffuseG = fallback->getFallbackFloat("Inventory_DirectionalDiffuseG"); + float diffuseB = fallback->getFallbackFloat("Inventory_DirectionalDiffuseB"); + float ambientR = fallback->getFallbackFloat("Inventory_DirectionalAmbientR"); + float ambientG = fallback->getFallbackFloat("Inventory_DirectionalAmbientG"); + float ambientB = fallback->getFallbackFloat("Inventory_DirectionalAmbientB"); + /// \todo Read DirectionalRotationX/DirectionalRotationY light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0)); - light->setDiffuse(osg::Vec4(1,1,1,1)); - light->setAmbient(osg::Vec4(0,0,0,1)); + light->setDiffuse(osg::Vec4(diffuseR,diffuseG,diffuseB,1)); + light->setAmbient(osg::Vec4(ambientR,ambientG,ambientB,1)); light->setSpecular(osg::Vec4(0,0,0,0)); light->setLightNum(0); light->setConstantAttenuation(1.f); From 9073e4d4baf1cf5116c4ab456a5a42ecc321fb01 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 21 Apr 2018 22:20:07 +0300 Subject: [PATCH 089/321] Initialize playlist file list in playPlaylist (fixes #4134) --- apps/openmw/mwsound/soundmanagerimp.cpp | 53 +++++++++++++------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a798d350c..db02bb482 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -393,32 +393,8 @@ namespace MWSound void SoundManager::startRandomTitle() { - std::vector filelist; + const std::vector &filelist = mMusicFiles[mCurrentPlaylist]; auto &tracklist = mMusicToPlay[mCurrentPlaylist]; - if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) - { - const std::map& index = mVFS->getIndex(); - - std::string pattern = "Music/" + mCurrentPlaylist; - mVFS->normalizeFilename(pattern); - - std::map::const_iterator found = index.lower_bound(pattern); - while (found != index.end()) - { - if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) - filelist.push_back(found->first); - else - break; - ++found; - } - - mMusicFiles[mCurrentPlaylist] = filelist; - } - else - filelist = mMusicFiles[mCurrentPlaylist]; - - if(filelist.empty()) - return; // Do a Fisher-Yates shuffle @@ -454,6 +430,33 @@ namespace MWSound void SoundManager::playPlaylist(const std::string &playlist) { + if (mCurrentPlaylist == playlist) + return; + + if (mMusicFiles.find(playlist) == mMusicFiles.end()) + { + std::vector filelist; + const std::map& index = mVFS->getIndex(); + + std::string pattern = "Music/" + playlist; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) + { + if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) + filelist.push_back(found->first); + else + break; + ++found; + } + + mMusicFiles[playlist] = filelist; + } + + if (mMusicFiles[playlist].empty()) + return; + mCurrentPlaylist = playlist; startRandomTitle(); } From bfcdf660f2052dc40dacd9f50a61d64ce14e22d0 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 23 Apr 2018 21:17:25 +0300 Subject: [PATCH 090/321] Utilize inventory character preview lighting rotation fallback settings --- apps/openmw/mwrender/characterpreview.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 622728c22..b3f672f31 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,5 +1,6 @@ #include "characterpreview.hpp" +#include #include #include @@ -170,8 +171,12 @@ namespace MWRender float ambientR = fallback->getFallbackFloat("Inventory_DirectionalAmbientR"); float ambientG = fallback->getFallbackFloat("Inventory_DirectionalAmbientG"); float ambientB = fallback->getFallbackFloat("Inventory_DirectionalAmbientB"); - /// \todo Read DirectionalRotationX/DirectionalRotationY - light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0)); + float azimuth = osg::DegreesToRadians(180.f - fallback->getFallbackFloat("Inventory_DirectionalRotationX")); + float altitude = osg::DegreesToRadians(fallback->getFallbackFloat("Inventory_DirectionalRotationY")); + float positionX = std::cos(azimuth) * std::sin(altitude); + float positionY = std::sin(azimuth) * std::sin(altitude); + float positionZ = std::cos(altitude); + light->setPosition(osg::Vec4(positionX,positionY,positionZ, 0.0)); light->setDiffuse(osg::Vec4(diffuseR,diffuseG,diffuseB,1)); light->setAmbient(osg::Vec4(ambientR,ambientG,ambientB,1)); light->setSpecular(osg::Vec4(0,0,0,0)); From 4cc65239ff1c33269a1e56c15038b02503af808e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 25 Apr 2018 10:21:58 +0000 Subject: [PATCH 091/321] Add section on dealing with regressions --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b2b4dfdd..4805bff3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -103,6 +103,10 @@ To be able to merge PRs, commit priviledges are required. If you do not have the The person to merge the PR may either use github's Merge button or if using the command line, use the ```--no-ff``` flag (so a merge commit is created, just like with Github's merge button) and include the pull request number in the commit description. +Dealing with regressions +======================== + +The master branch should always be in a working state that is not worse than the previous release in any way. If a regression is found, the first and foremost priority should be to get the regression fixed quickly, either by reverting the change that caused it or finding a better solution. Please avoid leaving the project in the 'broken' state for an extensive period of time while proper solutions are found. If the solution takes more than a day or so then it is usually better to revert the offending change first and reapply it later when fixed. Other resources =============== From 6b47f729591d01e9d6bd7d0f1fa1f31fda46863b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 25 Apr 2018 15:31:49 +0300 Subject: [PATCH 092/321] Set character preview scene ambient to 0, 0, 0 --- apps/openmw/mwrender/characterpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b3f672f31..faaa3799e 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -160,7 +160,7 @@ namespace MWRender stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); osg::ref_ptr lightmodel = new osg::LightModel; - lightmodel->setAmbientIntensity(osg::Vec4(0.25, 0.25, 0.25, 1.0)); + lightmodel->setAmbientIntensity(osg::Vec4(0.0, 0.0, 0.0, 1.0)); stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); osg::ref_ptr light = new osg::Light; From 5afcc5686062a7c2cab90186a25cc5e9dbfada29 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 29 Apr 2018 09:24:13 +0400 Subject: [PATCH 093/321] Handle NiLookAtController (feature #4407) --- components/nif/controller.cpp | 12 ++++++++++++ components/nif/controller.hpp | 9 +++++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 3 ++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index f39132543..ddfa02a09 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -101,6 +101,18 @@ namespace Nif data.post(nif); } + void NiLookAtController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiLookAtController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + void NiPathController::read(NIFStream *nif) { Controller::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 527bb74af..ce8bff041 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -99,6 +99,15 @@ public: void post(NIFFile *nif); }; +class NiLookAtController : public Controller +{ +public: + NiKeyframeDataPtr data; + + void read(NIFStream *nif); + void post(NIFFile *nif); +}; + class NiUVController : public Controller { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index b4b1caefc..4061247b5 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -108,6 +108,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiSequenceStreamHelper", &construct , RC_NiSequenceStreamHelper )); newFactory.insert(makeEntry("NiSourceTexture", &construct , RC_NiSourceTexture )); newFactory.insert(makeEntry("NiSkinInstance", &construct , RC_NiSkinInstance )); + newFactory.insert(makeEntry("NiLookAtController", &construct , RC_NiLookAtController )); return newFactory; } diff --git a/components/nif/record.hpp b/components/nif/record.hpp index b8597f7d1..ee4d508ab 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -93,7 +93,8 @@ enum RecordType RC_NiSourceTexture, RC_NiSkinInstance, RC_RootCollisionNode, - RC_NiSphericalCollider + RC_NiSphericalCollider, + RC_NiLookAtController }; /// Base class for all records From d967983f5c186818f1030871814dc0f04db0e50e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 25 Apr 2018 00:20:57 +0300 Subject: [PATCH 094/321] Assume Morrowind.esm dependency for dependency-less content addons (fixes #2829) --- components/contentselector/model/contentmodel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index a7ac29b46..41407ec88 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -512,7 +512,9 @@ void ContentSelectorModel::ContentModel::sortFiles() //dependencies appear. for (int j = i + 1; j < fileCount; j++) { - if (gamefiles.contains(mFiles.at(j)->fileName(), Qt::CaseInsensitive)) + if (gamefiles.contains(mFiles.at(j)->fileName(), Qt::CaseInsensitive) + || (!mFiles.at(i)->isGameFile() && gamefiles.isEmpty() + && mFiles.at(j)->fileName().compare("Morrowind.esm", Qt::CaseInsensitive) == 0)) // Hack: implicit dependency on Morrowind.esm for dependency-less files { mFiles.move(j, i); From 22fb1f3403b7f97c9f381001580bebd457b0276d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 30 Apr 2018 14:26:36 +0400 Subject: [PATCH 095/321] Play spellcasting effects from objects --- apps/openmw/mwbase/world.hpp | 7 +- apps/openmw/mwmechanics/character.cpp | 9 +++ apps/openmw/mwmechanics/spellcasting.cpp | 83 ++++++++++++++++++++--- apps/openmw/mwrender/animation.cpp | 14 ++-- apps/openmw/mwrender/animation.hpp | 3 +- apps/openmw/mwrender/effectmanager.cpp | 9 ++- apps/openmw/mwrender/effectmanager.hpp | 1 + apps/openmw/mwrender/objects.cpp | 8 +++ apps/openmw/mwrender/objects.hpp | 2 + apps/openmw/mwrender/renderingmanager.cpp | 13 +++- apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwscript/miscextensions.cpp | 2 + apps/openmw/mwworld/worldimp.cpp | 9 ++- apps/openmw/mwworld/worldimp.hpp | 4 +- 14 files changed, 143 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 47502fd71..68d4ac85d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -5,6 +5,9 @@ #include #include +#include +#include + #include #include "../mwworld/ptr.hpp" @@ -534,7 +537,7 @@ namespace MWBase /// Spawn a blood effect for \a ptr at \a worldPosition virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) = 0; virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, @@ -576,6 +579,8 @@ namespace MWBase /// Preload VFX associated with this effect list virtual void preloadEffects(const ESM::EffectList* effectList) = 0; + + virtual osg::ref_ptr getInstance (const std::string& modelName) = 0; }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2ef5e07d7..7e3744c30 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -833,6 +833,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); mAnimation->runAnimation(0.f); + mAnimation->updateEffects(0.f); unpersistAnimationState(); } @@ -1997,6 +1998,13 @@ void CharacterController::update(float duration) } osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); + + // treat player specifically since he is not in rendering mObjects + if (mPtr == getPlayer()) + { + mAnimation->updateEffects(mSkipAnim ? 0.f : duration); + } + if(duration > 0.0f) moved /= duration; else @@ -2192,6 +2200,7 @@ void CharacterController::forceStateUpdate() } mAnimation->runAnimation(0.f); + mAnimation->updateEffects(0.f); } CharacterController::KillResult CharacterController::kill() diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 7570cb9ba..802020b0e 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -6,8 +6,12 @@ #include +#include +#include + #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -24,6 +28,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwrender/animation.hpp" +#include "../mwrender/vismask.hpp" #include "npcstats.hpp" #include "actorutil.hpp" @@ -996,11 +1001,13 @@ namespace MWMechanics return true; } - void CastSpell::playSpellCastingEffects(const std::string &spellid){ - + void CastSpell::playSpellCastingEffects(const std::string &spellid) + { const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Spell *spell = store.get().find(spellid); + std::vector addedEffects; + for (std::vector::const_iterator iter = spell->mEffects.mList.begin(); iter != spell->mEffects.mList.end(); ++iter) { @@ -1009,18 +1016,72 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); - if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL) + const ESM::Static* castStatic; + + if (!effect->mCasting.empty()) + castStatic = store.get().find (effect->mCasting); + else + castStatic = store.get().find ("VFX_DefaultCast"); + + // check if the effect was already added + if (std::find(addedEffects.begin(), addedEffects.end(), "meshes\\" + castStatic->mModel) != addedEffects.end()) + continue; + + std::string texture = effect->mParticle; + + float scale = 1.0f; + osg::Vec3f pos (mCaster.getRefData().getPosition().asVec3()); + + if (animation && mCaster.getClass().isNpc()) { - const ESM::Static* castStatic; + // For NOC we should take race height as scaling factor + const ESM::NPC *npc = mCaster.get()->mBase; + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); - if (!effect->mCasting.empty()) - castStatic = store.get().find (effect->mCasting); - else - castStatic = store.get().find ("VFX_DefaultCast"); + const ESM::Race *race = + esmStore.get().find(npc->mRace); - std::string texture = effect->mParticle; + scale = npc->isMale() ? race->mData.mHeight.mMale : race->mData.mHeight.mFemale; + } + else + { + std::string casterModel = mCaster.getClass().getModel(mCaster); + osg::ref_ptr model = MWBase::Environment::get().getWorld()->getInstance(casterModel); - animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); + osg::ComputeBoundsVisitor computeBoundsVisitor; + computeBoundsVisitor.setTraversalMask(~(MWRender::Mask_ParticleSystem|MWRender::Mask_Effect)); + model->accept(computeBoundsVisitor); + osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); + + if (bounds.valid()) + { + float meshSizeX = std::abs(bounds.xMax() - bounds.xMin()); + float meshSizeY = std::abs(bounds.yMax() - bounds.yMin()); + float meshSizeZ = std::abs(bounds.zMax() - bounds.zMin()); + + // TODO: take a size of particle or NPC with height and weight = 1.0 as scale = 1.0 + float scaleX = meshSizeX/60.f; + float scaleY = meshSizeY/60.f; + float scaleZ = meshSizeZ/120.f; + + scale = std::max({ scaleX, scaleY, scaleZ }); + + //pos = bounds.center(); + //pos[2] = bounds.zMin(); + } + } + + // If the caster has no animation, add the effect directly to the effectManager + if (animation) + { + animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture, scale); + } + else + { + // We should set scale for effect manager manually + float meshScale = !mCaster.getClass().isActor() ? mCaster.getCellRef().getScale() : 1.0f; + MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + castStatic->mModel, effect->mParticle, pos, scale * meshScale); } if (animation && !mCaster.getClass().isActor()) @@ -1030,6 +1091,8 @@ namespace MWMechanics "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; + addedEffects.push_back("meshes\\" + castStatic->mModel); + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mCastSound.empty()) sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1bd839ead..1b508e593 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -1115,8 +1117,6 @@ namespace MWRender ++stateiter; } - updateEffects(duration); - if (mHeadController) { const float epsilon = 0.001f; @@ -1366,7 +1366,7 @@ namespace MWRender useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); } - void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture) + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture, float scale) { if (!mObjectRoot.get()) return; @@ -1417,7 +1417,13 @@ namespace MWRender overrideFirstRootTexture(texture, mResourceSystem, node); - // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. + osg::Vec3f scale3f (scale, scale, scale); + + osg::ref_ptr trans = new osg::PositionAttitudeTransform; + trans->setScale(scale3f); + trans->addChild(node); + parentNode->removeChild(node); + parentNode->addChild(trans); mEffects.push_back(params); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cff98a4b7..74224c6bd 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -364,7 +364,7 @@ public: * @param texture override the texture specified in the model's materials - if empty, do not override * @note Will not add an effect twice. */ - void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = ""); + void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "", float scale = 1.0f); void removeEffect (int effectId); void getLoopingEffects (std::vector& out) const; @@ -446,7 +446,6 @@ public: void setLoopingEnabled(const std::string &groupname, bool enabled); - /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); /// Return a node with the specified name, or NULL if not existing. diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 3e785a769..c44c5428a 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -26,6 +26,13 @@ EffectManager::~EffectManager() } void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) +{ + osg::Vec3f scale3f (scale, scale, scale); + + addEffect(model, textureOverride, worldPosition, scale3f, isMagicVFX); +} + +void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, const osg::Vec3f &scale, bool isMagicVFX) { osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(model); @@ -40,7 +47,7 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu osg::ref_ptr trans = new osg::PositionAttitudeTransform; trans->setPosition(worldPosition); - trans->setScale(osg::Vec3f(scale, scale, scale)); + trans->setScale(scale); trans->addChild(node); SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime); diff --git a/apps/openmw/mwrender/effectmanager.hpp b/apps/openmw/mwrender/effectmanager.hpp index 5873c00dd..cc1c1b42e 100644 --- a/apps/openmw/mwrender/effectmanager.hpp +++ b/apps/openmw/mwrender/effectmanager.hpp @@ -33,6 +33,7 @@ namespace MWRender /// Add an effect. When it's finished playing, it will be removed automatically. void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true); + void addEffect (const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, const osg::Vec3f &scale3f, bool isMagicVFX); void update(float dt); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f0a3d2e38..523f1774c 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -138,6 +138,14 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr) return false; } +void Objects::updateEffects(float duration) +{ + for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) + { + iter->second->updateEffects(duration); + ++iter; + } +} void Objects::removeCell(const MWWorld::CellStore* store) { diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 659853763..e97395213 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -88,6 +88,8 @@ public: bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? + void updateEffects(float duration); + void removeCell(const MWWorld::CellStore* store); /// Updates containing cell for object rendering data diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6f0ddba3a..e5933a72a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -557,6 +557,7 @@ namespace MWRender mEffectManager->update(dt); mSky->update(dt); mWater->update(dt); + mObjects->updateEffects(dt); } mCamera->update(dt, paused); @@ -841,9 +842,11 @@ namespace MWRender mObjects->updatePtr(old, updated); } - void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) + void RenderingManager::spawnEffect(const std::string &model, const std::string& texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) { - mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX); + osg::Vec3f scale3f (scale, scale, scale); + + mEffectManager->addEffect(model, texture, worldPosition, scale3f, isMagicVFX); } void RenderingManager::notifyWorldSpaceChanged() @@ -1122,6 +1125,12 @@ namespace MWRender updateProjectionMatrix(); } } + + osg::ref_ptr RenderingManager::getInstance(const std::string& modelName) + { + return mResourceSystem->getSceneManager()->getInstance(modelName); + } + void RenderingManager::exportSceneGraph(const MWWorld::Ptr &ptr, const std::string &filename, const std::string &format) { osg::Node* node = mViewer->getSceneData(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1c689d29f..7a570f249 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -205,6 +205,8 @@ namespace MWRender LandManager* getLandManager() const; + osg::ref_ptr getInstance(const std::string& modelName); + private: void updateProjectionMatrix(); void updateTextureFiltering(); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 59f2cc9c6..243ba7b7e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -14,6 +14,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/world.hpp" @@ -1051,6 +1052,7 @@ namespace MWScript MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false); MWMechanics::CastSpell cast(ptr, target); + cast.playSpellCastingEffects(spell); cast.mHitPosition = target.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 13bfc32b3..bd3ff6e5f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1535,6 +1535,11 @@ namespace MWWorld } } + osg::ref_ptr World::getInstance (const std::string& modelName) + { + return mRendering->getInstance(modelName); + } + const ESM::Potion *World::createRecord (const ESM::Potion& record) { return mStore.insert(record); @@ -3324,9 +3329,9 @@ namespace MWWorld mRendering->spawnEffect(model, texture, worldPosition, 1.0f, false); } - void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos) + void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos, float scale, bool isMagicVFX) { - mRendering->spawnEffect(model, textureOverride, worldPos); + mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX); } void World::explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const Ptr& caster, const Ptr& ignore, ESM::RangeType rangeType, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 40a22af5d..c366e51d0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -640,7 +640,7 @@ namespace MWWorld /// Spawn a blood effect for \a ptr at \a worldPosition void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; + void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) override; void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, @@ -680,6 +680,8 @@ namespace MWWorld /// Preload VFX associated with this effect list void preloadEffects(const ESM::EffectList* effectList) override; + + osg::ref_ptr getInstance (const std::string& modelName); }; } From 6cc740519461e326f95da8f04432712378817d77 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 30 Apr 2018 18:29:26 +0400 Subject: [PATCH 096/321] Remove unnecessary command from QuadTreeWorld destructor (bug #4408) --- components/terrain/quadtreeworld.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f31064805..cd51efe69 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -246,7 +246,6 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour QuadTreeWorld::~QuadTreeWorld() { - ensureQuadTreeBuilt(); mViewDataMap->clear(); } From 4872edc5edd396bbb4ee0ba29bc14df8c87bb7f7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 1 May 2018 16:21:58 +0400 Subject: [PATCH 097/321] Prevent PlaySound overlapping --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++------ apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +++ 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 8a9eb2ea6..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -337,7 +337,7 @@ namespace MWBase /// Cycle to next or previous weapon virtual void cycleWeapon(bool next) = 0; - virtual void playSound(const std::string& soundId, bool preventOverlapping = false, float volume = 1.f, float pitch = 1.f) = 0; + virtual void playSound(const std::string& soundId, float volume = 1.f, float pitch = 1.f) = 0; // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path) = 0; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index cb902cadf..c18548dad 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -200,7 +200,7 @@ namespace MWGui { if ((mCurrentPage+1)*2 < mPages.size()) { - MWBase::Environment::get().getWindowManager()->playSound("book page2", true); + MWBase::Environment::get().getWindowManager()->playSound("book page2"); ++mCurrentPage; @@ -211,7 +211,7 @@ namespace MWGui { if (mCurrentPage > 0) { - MWBase::Environment::get().getWindowManager()->playSound("book page", true); + MWBase::Environment::get().getWindowManager()->playSound("book page"); --mCurrentPage; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c103f60ad..b1e18209a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1919,16 +1919,12 @@ namespace MWGui mInventoryWindow->cycle(next); } - void WindowManager::playSound(const std::string& soundId, bool preventOverlapping, float volume, float pitch) + void WindowManager::playSound(const std::string& soundId, float volume, float pitch) { if (soundId.empty()) return; - MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); - if (preventOverlapping && sndmgr->getSoundPlaying(MWWorld::Ptr(), soundId)) - return; - - sndmgr->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } void WindowManager::updateSpellWindow() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 56ccea33b..1d250f6d4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -366,7 +366,7 @@ namespace MWGui /// Cycle to next or previous weapon virtual void cycleWeapon(bool next); - virtual void playSound(const std::string& soundId, bool preventOverlapping = false, float volume = 1.f, float pitch = 1.f); + virtual void playSound(const std::string& soundId, float volume = 1.f, float pitch = 1.f); // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index db02bb482..ba8ac1bba 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -577,6 +577,9 @@ namespace MWSound Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); if(!sfx) return nullptr; + // Only one copy of given sound can be played at time, so stop previous copy + stopSound(soundId); + Sound *sound = getSoundRef(); sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); if(!mOutput->playSound(sound, sfx->mHandle, offset)) From e4e225f4e7002d3b98c9f5b4206e7d20bd7bfb93 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 3 May 2018 14:32:15 +0300 Subject: [PATCH 098/321] Add topic, journal and related -info icons. --- apps/opencs/model/world/universalid.cpp | 8 ++++---- files/opencs/dialogue-topic-infos.png | Bin 0 -> 306 bytes files/opencs/dialogue-topics.png | Bin 0 -> 282 bytes files/opencs/journal-topic-infos.png | Bin 0 -> 300 bytes files/opencs/journal-topics.png | Bin 0 -> 273 bytes files/opencs/resources.qrc | 4 ++++ 6 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 files/opencs/dialogue-topic-infos.png create mode 100644 files/opencs/dialogue-topics.png create mode 100644 files/opencs/journal-topic-infos.png create mode 100644 files/opencs/journal-topics.png diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index ebeea0184..8d7a7761e 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -75,10 +75,10 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":./region.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":./birthsign.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 }, - { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 }, - { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", ":./dialogue-topics.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", ":./journal-topics.png" }, + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", ":./dialogue-topic-infos.png" }, + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", ":./journal-topic-infos.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", 0 }, diff --git a/files/opencs/dialogue-topic-infos.png b/files/opencs/dialogue-topic-infos.png new file mode 100644 index 0000000000000000000000000000000000000000..6242eddf4f0858ab3300580784fc9ef193e42c11 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkQ1FST zi(`m|;L;#NzC#8)IZUq(o!NXTf5S(yBPaAH+4OK4DhR&o>A7UK)-ht$8>{E1Ew{Z+ zIBXzN^;~9d=2DJ5&G$JXIM1BoT3~ux%beSpqjgn9@VTFs%nA>qJYDk1=oix!i_xbJlLj`N(U)D7#Qcs-tSlrx}w> zIDfDi6f?2Za_oq-Dwn&UA%9=?q1+PlyLR(5!#Ef|G3*havwUje67@fE56gZ0%O7jc z)UaFp?ZMvn$vumuihcHozUnIwKUOa}r6*7QCU@zL`0JSyyE=jXW$<+Mb6Mw<&;$VZ CHFqQc literal 0 HcmV?d00001 diff --git a/files/opencs/dialogue-topics.png b/files/opencs/dialogue-topics.png new file mode 100644 index 0000000000000000000000000000000000000000..caa6d7e7cb15c81562831671e9c04d5e06a4a284 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkQ1FbW zi(`m|;N4(PzC#8)K3v=9Rfc`y^V`E(=w!3_rxeFZ_Cr2LUEVDd>5JI(#>6<;ys)On z(0a!Ad5N2!+FY13`9Rt-#!0)cM>%a14t2bQh$+S(6oCEG2WVCo7-OPbundXxZ0Wukc_xTgUSQI~(jL$`u^ouiG5)jz7G| zaV9VSL6bLgAKLDD8pU)bb#)4(!#)N3L(w5`cCV8zT(!O7o4-Q*!|zL1uHkApVeT|h d`t!=YjE_44d}XR8wE_Lb;OXk;vd$@?2>>MvZcYFI literal 0 HcmV?d00001 diff --git a/files/opencs/journal-topic-infos.png b/files/opencs/journal-topic-infos.png new file mode 100644 index 0000000000000000000000000000000000000000..4cc4464897026d9042d46c8051d636549f86aeaf GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkQ1G6o zi(`m|U~e!d-(dxw>>D3)7W6&Vn4;wLa9&W>tfPtd zS8aS>ExmC{;Ki6+sTUlIIa7A@Z(Q>Ai-xn8XVJO*C7dN*)-_Y+Dl}VKy9#dj+~BbL z;ln#ux2jp~DTrR4{PK;~`xZ|=12#b$%VS?70$EaSI~zV_I4Qku!3L-AU7Vlv*?X)f zM?uqfcy)1SS8^OY3XRXXoXXn!62%etxQq4ojuyVy<4PH%>7;_I}2_J=z_9{}X#o%~lUn1NxM~)78&qol`;+01)we2mk;8 literal 0 HcmV?d00001 diff --git a/files/opencs/journal-topics.png b/files/opencs/journal-topics.png new file mode 100644 index 0000000000000000000000000000000000000000..d4e58a288503ea273e85169fceede9099d0c32e9 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkQ1Gy) zi(`m|;N8iu`3@=Yw1%72T33WWczdPcd4d<44|9F)rYTPP@sSgGAI&*^Mak)FXpvst zSD9~dJlVO`L9xeLe`N(8=1o51*8AR^>C@LK?mdA5KMvfKeSNx2#J0si#A1rV(j#Uq z=X`D*zP$ea;=2L`%^h#v_ncaiKD$nfmvPmb0yBjjYnC~t-xc`47v}o^5O3oj?knC- zF$Y=g1XUw~^-szROsOlZTz~Ue>4Go1Q#w~4JCgmx;blVQdwb#THHTlE6WYsoSGw$B TaB+Gs&^rvCu6{1-oD!Mdialogue-greeting.png dialogue-persuasion.png dialogue-voice.png + dialogue-topics.png + dialogue-topic-infos.png + journal-topic-infos.png + journal-topics.png door.png enchantment.png faction.png From 85b7aa4f09d3ebd7bad3bec4dd6f1540e08d9379 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 3 May 2018 19:47:39 +0300 Subject: [PATCH 099/321] Uncomment is_pod test in fixed string tests --- apps/openmw_test_suite/esm/test_fixed_string.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw_test_suite/esm/test_fixed_string.cpp b/apps/openmw_test_suite/esm/test_fixed_string.cpp index 59dd7fe66..598e8daad 100644 --- a/apps/openmw_test_suite/esm/test_fixed_string.cpp +++ b/apps/openmw_test_suite/esm/test_fixed_string.cpp @@ -66,10 +66,8 @@ TEST(EsmFixedString, struct_size) TEST(EsmFixedString, DISABLED_is_pod) { - /* TODO: enable in C++11 - * ASSERT_TRUE(std::is_pod::value); - * ASSERT_TRUE(std::is_pod::value); - * ASSERT_TRUE(std::is_pod::value); - * ASSERT_TRUE(std::is_pod::value); - */ + ASSERT_TRUE(std::is_pod::value); + ASSERT_TRUE(std::is_pod::value); + ASSERT_TRUE(std::is_pod::value); + ASSERT_TRUE(std::is_pod::value); } From 8be93b4a12f634c7e31d13b4039f2de16077907e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 3 May 2018 19:56:01 +0300 Subject: [PATCH 100/321] Initialize mandatoryIds vector C++11-way --- apps/opencs/model/tools/tools.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 3b2c80263..445db53af 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -61,12 +61,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int))); - std::vector mandatoryIds; // I want C++11, damn it! - mandatoryIds.push_back ("Day"); - mandatoryIds.push_back ("DaysPassed"); - mandatoryIds.push_back ("GameHour"); - mandatoryIds.push_back ("Month"); - mandatoryIds.push_back ("PCRace"); + std::vector mandatoryIds {"Day", "DaysPassed", "GameHour", "Month", "PCRace"}; mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); From 9ac9f9463851fc54de742c3c74db02fdf245b1c7 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 4 May 2018 20:00:58 +0300 Subject: [PATCH 101/321] Rename "Model" column to "Model/Animation" (feature #2694) --- apps/opencs/model/world/columns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index ec010ba36..7c0fbff4b 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -66,7 +66,7 @@ namespace CSMWorld { ColumnId_SleepForbidden, "Sleep Forbidden" }, { ColumnId_InteriorWater, "Interior Water" }, { ColumnId_InteriorSky, "Interior Sky" }, - { ColumnId_Model, "Model" }, + { ColumnId_Model, "Model/Animation" }, { ColumnId_Script, "Script" }, { ColumnId_Icon, "Icon" }, { ColumnId_Weight, "Weight" }, From f5b7a230fc1fcf69deb0ecd7e73b45f0488f95e2 Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Sat, 5 May 2018 13:30:45 +0300 Subject: [PATCH 102/321] ESMReader::close now clears mHeader --- components/esm/esmreader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2a716427e..67b9d6a38 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -57,6 +57,7 @@ void ESMReader::close() mCtx.subCached = false; mCtx.recName.clear(); mCtx.subName.clear(); + mHeader.blank(); } void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) From 1dd36329a34e1cf2d5b7412472d5a83f6907d98d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 May 2018 10:37:55 +0400 Subject: [PATCH 103/321] Load default markers definitions (bug #4410) --- apps/openmw/mwworld/esmstore.cpp | 1 + apps/openmw/mwworld/store.cpp | 28 ++++++++++++++++++++++++++++ components/esm/loadstat.hpp | 16 +++++++++++++--- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 4a1763d0a..2fe9ebcad 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -141,6 +141,7 @@ void ESMStore::setUp() mMagicEffects.setUp(); mAttributes.setUp(); mDialogs.setUp(); + mStatics.setUp(); } int ESMStore::countSavedGameRecords() const diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 158d3f771..e9968c38f 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1053,6 +1053,34 @@ namespace MWWorld } } + template<> + void Store::setUp() + { + // Load default marker definitions, if game files do not have them for some reason + std::pair markers[] = { + std::make_pair("divinemarker", "marker_divine.nif"), + std::make_pair("doormarker", "marker_arrow.nif"), + std::make_pair("northmarker", "marker_north.nif"), + std::make_pair("templemarker", "marker_temple.nif"), + std::make_pair("travelmarker", "marker_travel.nif") + }; + + for (const std::pair marker : markers) + { + if (search(marker.first) == 0) + { + ESM::Static newMarker = ESM::Static(marker.first, marker.second); + mStatic.insert(std::make_pair(marker.first, newMarker)); + + std::map::iterator found = mStatic.find(marker.first); + if (found != mStatic.end()) + { + mShared.push_back(&found->second); + } + } + } + } + template <> inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 930cdb849..f80875b65 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -26,13 +26,23 @@ struct Static /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "Static"; } - std::string mId, mModel; + std::string mId, mModel; - void load(ESMReader &esm, bool &isDeleted); - void save(ESMWriter &esm, bool isDeleted = false) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). + + Static(const std::string id, const std::string &model) + : mId(id) + , mModel(model) + { + } + + Static() + { + } }; } #endif From 3d3bef94cd0b7c8d0840798eff1a2f43ad9e7f9e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 5 May 2018 16:29:01 +0300 Subject: [PATCH 104/321] Use range-based for loop --- apps/opencs/view/world/table.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 34ecd57d0..986717cb2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -764,10 +764,8 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const QModelIndexList selectedRows = selectionModel()->selectedRows(); std::vector idToDrag; - foreach (QModelIndex it, selectedRows) //I had a dream. Dream where you could use C++11 in OpenMW. - { + for (QModelIndex& it : selectedRows) idToDrag.push_back (getUniversalId (it.row())); - } return idToDrag; } From 3636cf20150476b491387251f2918aeef52168fa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 4 May 2018 12:56:28 +0400 Subject: [PATCH 105/321] Do not apply queue movement for standing actors --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwmechanics/aiwander.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 3 ++- apps/openmw/mwphysics/actor.cpp | 7 +++++- apps/openmw/mwphysics/actor.hpp | 8 +++++++ apps/openmw/mwphysics/physicssystem.cpp | 29 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwscript/miscextensions.cpp | 2 ++ apps/openmw/mwstate/statemanagerimp.cpp | 5 ++++- apps/openmw/mwworld/worldimp.cpp | 7 ++++-- apps/openmw/mwworld/worldimp.hpp | 1 + 11 files changed, 62 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 47502fd71..86e2a0281 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -388,6 +388,7 @@ namespace MWBase virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const = 0; virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; + virtual bool isIdle(const MWWorld::Ptr &ptr) const = 0; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8199170dc..511a47a49 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -866,8 +866,7 @@ namespace MWMechanics } // place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be underground. - // Adding 20 in adjustPosition() is not enough. - dest.mZ += 60; + dest.mZ += 80; ToWorldCoordinates(dest, actor.getCell()->getCell()); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2ef5e07d7..d7a038b9e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2029,7 +2029,8 @@ void CharacterController::update(float duration) moved.z() = 1.0; // Update movement - if(mMovementAnimationControlled && mPtr.getClass().isActor()) + // We should not apply movement for standing actors + if(mMovementAnimationControlled && mPtr.getClass().isActor() && (movement.length2() > 0.f || !world->isIdle(mPtr))) world->queueMovement(mPtr, moved); mSkipAnim = false; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 79c6dcabf..6de0d1984 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -18,7 +18,7 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) - , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) + , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false), mIdle(true) , mInternalCollisionMode(true) , mExternalCollisionMode(true) , mCollisionWorld(world) @@ -195,6 +195,11 @@ void Actor::setOnSlope(bool slope) mOnSlope = slope; } +void Actor::setIdle(bool idle) +{ + mIdle = idle; +} + bool Actor::isWalkingOnWater() const { return mWalkingOnWater; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 8ec94200f..bdafc1235 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -139,6 +139,13 @@ namespace MWPhysics return mInternalCollisionMode && mOnSlope; } + void setIdle(bool idle); + + bool getIdle() const + { + return mIdle; + } + btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); @@ -179,6 +186,7 @@ namespace MWPhysics osg::Vec3f mForce; bool mOnGround; bool mOnSlope; + bool mIdle; bool mInternalCollisionMode; bool mExternalCollisionMode; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f3c34bc4e..1cff6b522 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -683,6 +683,7 @@ namespace MWPhysics , mWaterEnabled(false) , mParentNode(parentNode) , mPhysicsDt(1.f / 60.f) + , mIdleUpdateTimer(0) { mResourceSystem->addResourceManager(mShapeManager.get()); @@ -739,6 +740,18 @@ namespace MWPhysics delete mBroadphase; } + void PhysicsSystem::updateIdle() + { + for (ActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it) + { + osg::Vec3f pos(it->second->getCollisionObjectPosition()); + + RayResult result = castRay(pos, pos - osg::Vec3f(0, 0, it->second->getHalfExtents().z() + 2), it->second->getPtr(), std::vector(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); + + it->second->setIdle(result.mHit); + } + } + void PhysicsSystem::setUnrefQueue(SceneUtil::UnrefQueue *unrefQueue) { mUnrefQueue = unrefQueue; @@ -1045,6 +1058,11 @@ namespace MWPhysics return physactor && physactor->getOnGround(); } + bool PhysicsSystem::isIdle(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + return physactor && physactor->getIdle(); + } bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel) { const Actor* physicActor = getActor(actor); @@ -1337,6 +1355,10 @@ namespace MWPhysics cmode = !cmode; found->second->enableCollisionMode(cmode); found->second->enableCollisionBody(cmode); + + if (cmode) + queueObjectMovement(MWMechanics::getPlayer(), osg::Vec3f(0, 0, -0.1f)); + return cmode; } @@ -1456,6 +1478,13 @@ namespace MWPhysics for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) (*it)->animateCollisionShapes(mCollisionWorld); + mIdleUpdateTimer -= dt; + if (mIdleUpdateTimer <= 0.f) + { + mIdleUpdateTimer = 0.5f; + updateIdle(); + } + #ifndef BT_NO_PROFILE CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 3ef9990f5..fe2433ce0 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -124,6 +124,7 @@ namespace MWPhysics bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; bool isOnGround (const MWWorld::Ptr& actor); + bool isIdle (const MWWorld::Ptr& actor); bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel); @@ -173,6 +174,7 @@ namespace MWPhysics private: void updateWater(); + void updateIdle(); osg::ref_ptr mUnrefQueue; @@ -221,6 +223,7 @@ namespace MWPhysics osg::ref_ptr mParentNode; float mPhysicsDt; + float mIdleUpdateTimer; PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 59f2cc9c6..83ecaff33 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -700,6 +700,8 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + MWWorld::Ptr ptr = R()(runtime); + MWBase::Environment::get().getWorld()->queueMovement(ptr, osg::Vec3f(0, 0, -0.1f)); } }; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index c1bb589e8..911e0ebdc 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -506,7 +506,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - MWWorld::ConstPtr ptr = MWMechanics::getPlayer(); + const MWWorld::Ptr ptr = MWMechanics::getPlayer(); if (ptr.isInCell()) { @@ -538,6 +538,9 @@ void MWState::StateManager::loadGame (const Character *character, const std::str // Since we passed "changeEvent=false" to changeCell, we shouldn't have triggered the cell change flag. // But make sure the flag is cleared anyway in case it was set from an earlier game. MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + + // Workaround to fix camera position upon game load + MWBase::Environment::get().getWorld()->queueMovement(ptr, osg::Vec3f(0, 0, 0)); } catch (const std::exception& e) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 13bfc32b3..5b11dd370 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1314,8 +1314,6 @@ namespace MWWorld if (pos.z() < terrainHeight) pos.z() = terrainHeight; - pos.z() += 20; // place slightly above. will snap down to ground with code below - if (force || !isFlying(ptr)) { osg::Vec3f traced = mPhysics->traceDown(ptr, pos, 500); @@ -2157,6 +2155,11 @@ namespace MWWorld return mPhysics->isOnGround(ptr); } + bool World::isIdle(const MWWorld::Ptr &ptr) const + { + return mPhysics->isIdle(ptr); + } + void World::togglePOV() { mRendering->togglePOV(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 40a22af5d..133e6d8fe 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -489,6 +489,7 @@ namespace MWWorld bool isWading(const MWWorld::ConstPtr &object) const override; bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; bool isOnGround(const MWWorld::Ptr &ptr) const override; + bool isIdle(const MWWorld::Ptr &ptr) const override; osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; From e22409c266ecb953c64d12faecbdcab243248467 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 6 May 2018 00:13:09 +0300 Subject: [PATCH 106/321] Fix sound range warning message --- apps/opencs/model/tools/soundcheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 6a059bee2..3dbd3ef11 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -27,7 +27,7 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); if (sound.mData.mMinRange>sound.mData.mMaxRange) - messages.push_back (std::make_pair (id, "Maximum range larger than minimum range")); + messages.push_back (std::make_pair (id, "Minimum range larger than maximum range")); /// \todo check, if the sound file exists } From 91b97a27ea0a2c19cf9e6c2adea4fb77b595aa61 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 6 May 2018 00:14:14 +0300 Subject: [PATCH 107/321] Remove empty class description warning --- apps/opencs/model/tools/classcheck.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index e4964d4e3..316fc0ce5 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -32,9 +32,6 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) if (class_.mName.empty()) messages.push_back (std::make_pair (id, class_.mId + " has an empty name")); - if (class_.mDescription.empty()) - messages.push_back (std::make_pair (id, class_.mId + " has an empty description")); - // test for invalid attributes for (int i=0; i<2; ++i) if (class_.mData.mAttribute[i]==-1) From 2502d538167e503bcfae6e1f1ada1bb2360f3e94 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 6 May 2018 00:23:05 +0300 Subject: [PATCH 108/321] Object record verifier updates Removed light 0 duration warning Spelling fixes --- .../opencs/model/tools/referenceablecheck.cpp | 41 ++----------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 4dd3e1edf..750c3ceb4 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -239,9 +239,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Book& book = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Book, book.mId); @@ -260,9 +258,7 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Activator& activator = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Activator, activator.mId); @@ -283,9 +279,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Potion& potion = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId); @@ -306,9 +300,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Apparatus& apparatus = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Apparatus, apparatus.mId); @@ -329,9 +321,7 @@ void CSMTools::ReferenceableCheckStage::armorCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Armor& armor = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Armor, armor.mId); @@ -358,9 +348,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Clothing& clothing = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Clothing, clothing.mId); @@ -378,9 +366,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Container& container = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Container, container.mId); @@ -512,9 +498,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Ingredient& ingredient = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Ingredient, ingredient.mId); @@ -577,13 +561,8 @@ void CSMTools::ReferenceableCheckStage::lightCheck( messages.push_back (std::make_pair (id, light.mId + " has negative light radius")); if (light.mData.mFlags & ESM::Light::Carry) - { inventoryItemCheck(light, messages, id.toString()); - if (light.mData.mTime == 0) - messages.push_back (std::make_pair (id, light.mId + " has zero duration")); - } - // Check that mentioned scripts exist scriptCheck(light, messages, id.toString()); } @@ -596,9 +575,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Lockpick& lockpick = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Lockpick, lockpick.mId); @@ -619,9 +596,7 @@ void CSMTools::ReferenceableCheckStage::miscCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Miscellaneous& miscellaneous = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Miscellaneous, miscellaneous.mId); @@ -706,22 +681,14 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( messages.push_back (std::make_pair (id, npc.mId + " has any empty name")); if (npc.mClass.empty()) - { - messages.push_back (std::make_pair (id, npc.mId + " has any empty class")); - } + messages.push_back (std::make_pair (id, npc.mId + " has an empty class")); else if (mClasses.searchId (npc.mClass) == -1) - { messages.push_back (std::make_pair (id, npc.mId + " has invalid class")); - } if (npc.mRace.empty()) - { - messages.push_back (std::make_pair (id, npc.mId + " has any empty race")); - } + messages.push_back (std::make_pair (id, npc.mId + " has an empty race")); else if (mRaces.searchId (npc.mRace) == -1) - { messages.push_back (std::make_pair (id, npc.mId + " has invalid race")); - } if (disposition < 0) messages.push_back (std::make_pair (id, npc.mId + " has negative disposition")); @@ -823,7 +790,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( { //checking of health if (weapon.mData.mHealth <= 0) - messages.push_back (std::make_pair (id, weapon.mId + " has non-positivie health")); + messages.push_back (std::make_pair (id, weapon.mId + " has non-positive health")); if (weapon.mData.mReach < 0) messages.push_back (std::make_pair (id, weapon.mId + " has negative reach")); @@ -842,9 +809,7 @@ void CSMTools::ReferenceableCheckStage::probeCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Probe& probe = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Probe, probe.mId); From 17222eb8219b546db7ec948e6a16616d2cb5ac76 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 6 May 2018 16:42:05 +0400 Subject: [PATCH 109/321] Get rid of unnecessary find --- apps/openmw/mwworld/store.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index e9968c38f..6f0a1b49f 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1070,12 +1070,10 @@ namespace MWWorld if (search(marker.first) == 0) { ESM::Static newMarker = ESM::Static(marker.first, marker.second); - mStatic.insert(std::make_pair(marker.first, newMarker)); - - std::map::iterator found = mStatic.find(marker.first); - if (found != mStatic.end()) + std::pair ret = mStatic.insert(std::make_pair(marker.first, newMarker)); + if (ret.first != mStatic.end()) { - mShared.push_back(&found->second); + mShared.push_back(&ret.first->second); } } } From 9b971caddc677eba4c496060c7c112c5eb4990c7 Mon Sep 17 00:00:00 2001 From: Alf Henrik Sauge Date: Sun, 6 May 2018 16:43:49 +0200 Subject: [PATCH 110/321] CSVTools::ReportTable should now have case insensitive sorting --- apps/opencs/view/tools/reporttable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 4d1456cd9..a970af168 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -156,6 +156,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setSelectionMode (QAbstractItemView::ExtendedSelection); mProxyModel = new QSortFilterProxyModel (this); + mProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); mProxyModel->setSourceModel (mModel); mProxyModel->setSortRole(Qt::UserRole); From a2745683e6c56dbf9a02b13abce751f44b92c268 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 6 May 2018 22:30:01 +0300 Subject: [PATCH 111/321] new run icon --- files/opencs/resources.qrc | 2 +- files/opencs/run-game.png | Bin 0 -> 642 bytes files/opencs/scene-play.png | Bin 3601 -> 0 bytes 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 files/opencs/run-game.png delete mode 100644 files/opencs/scene-play.png diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 7a6624ba3..bfa256faf 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -89,7 +89,7 @@ camera-first-person.png camera-free.png camera-orbit.png - scene-play.png + run-game.png scene-view-instance.png scene-view-terrain.png scene-view-water.png diff --git a/files/opencs/run-game.png b/files/opencs/run-game.png new file mode 100644 index 0000000000000000000000000000000000000000..f5038654fa1a3238be2f3124e12c06e75e206773 GIT binary patch literal 642 zcmV-|0)737P)e5SHDZcKoowLq~M@~ICt?c(50iZn{;z2E~1kPPC5%Z zI_RRKh@*dmx=4jiPNIvmIw%Nj?#}PhL{m&lle=6fT;P(+{d(W`<-NNXB6m3joB~b( zr+`zyDKMc5)XzSrs)p`q0buMKBsR3x(45S4=GV`^Bx62F5x!uZ)z{6Lw$6G*=4ull zDI>eg4@mN`gO>(~ghjvG|&9nJxE-j)Fz5R0#@>#ijNlJqYDxT zNxO-sv0Z3vFrH5&_#4JAW4C%3d)|!sbBK>NzJ`jAh0JkdHrgi;1N)5+ zFX({8AxfdNq%s1Dz&OR#w!4p8p|r$)3?#@ip3K8(-cL)`5Fd9LL;f{Y{sjgRMQO<_ z+NKBFhrb2GyDauF=qQE2DZT^cPxDx=m;fUd)JTTiD}YvRlRF8lj6j^d-T?eMfIsC? zJw4Vwf&M|JQtuXkU#7tnsoNvKu;EFhtAcOm_4850tPnsl2gQ500MZ0_l|~r5N+l5Q z>m7hs?(%31b!wq<2=x72;!slC;z`P$@v2z@%FhW!@Ld2uHjXx9L1P5|{9LX8{6~hZ zQkt|0;3q}>2fxG5m&)?>B_84W3Cv zK~!ko)tcFF99MS6f9KY%r8lnPBFWk%YnNqs>~V~VXKas+00}Vj2L#D;{-?YJ0fIav z2oN9(Fdi$4SFMy~E!0L)lteA0*c*GPs(bQK)y-~-@)!t^Xb7~rL>9Zg?|k1`?g8bm z{;BrYz;0j?hyV`|Ue7NDQlJg20E<>M-3=TDW`Po5UvmNp&;*tNtPv)2@VkIA;QtX2 zsOK1;TZ4;o;ALRskAOg&UzdQ$8l0Eg#vgdS&IHKuTEMfS+5;<_Uaa5#2Q=J8IQ=#@ zEWR!zhHzRd?v;0r%1!>_y<42Q{5u|{pAl_4i46;{l_VB*KdRV?V?X2Qn_X_q|BlZu ze$KM{HPO^DY!JO31f*}Pt+i5@u-5sUgNNSa$f2EFpZ`yOfAI^J`Gn%s5j;P5eF zv0jN|Ck}G#=mb}<|0`#%lv$OJDNP^1c=q)nkgB4ZpsFCCD2gL-O&Xo6SX1KE$paie zGQyP~{)MwwMyUoLQ=Zy~@x1>V0%oA%tLjTR;55Oh!>FLR+;B2P#4}~yKE00E1PNRDbYs>un-8VRO%;Vzsf6w`wJL#4_qB6N-D0-U#|EL7!4_N4>YUE|#OEtl% zVseYQ{F4PRxv2z$pa_Df5=)J^dkq^__~8AWoI0*toclX2-+P0!{1KJO?JpDA4BGst z1ZZv->*{L`+5i1rO&@;Q#`@F7BHOt84ehn3_=N(6*~1hjcY>IWRCRG*fgTAF0TIL) zB&Q)Lk^?9I4*8W!tHfy)TPpL*U+(1esSfAQ&vEBQndXBQBN`*4+cAC_eA|EiPpU$# z+h_4e>8jAUcY!obDNODrsBB}sx`1=zIG5)B&q(yAznqMS^da~E&1b|xtEA}~ak55O zF7vBj@8PY}EiRtF!0q`3WN|k}Anvw^ruP#}AEYq8v;VtseTBy38&vPlk+z!@r}t8R z;{1bQdR1 zH~8ki&T@Uu;_Ea?bCvF`?+C}XGqURhFYcZrZmbempGqLuiltp!WcAVl))<5KrFVcw zIq#-xi6PA`w0Y(pnrl@zh~?KqRk^1^o^P68r>;sTUZXTx;m>}1hQ;Y9@6i|1|+K}h(S}y2n_oERSKx~BR^=H9;wZZ zvPVLJPEw^EuTh$)@Y!$nvAkU6!hg@Rd~b|WxPvGv(3_eSvyoqFu&Rp6Mj0H6wUd4l zZ;ra=m97swC(&1-7x^u!oNgkdIgvE3($O_WCdz#Jo82rws&et`A6Qx1MkU%#7>0=U z@-Q23tmb?aLHli~S68&JfH5W`G7xp$1iS}&&^oeJ@f)zx5Q!d3uD0ZJUoFX&lZ^2WBa4TP!4PXTsBAlr}WV+qK_CnDU!yP`T13D ze4TLpQiCWgad7|kelIFSA#3$EHVOj@p^&C2*REZmnInP^1k0PR^Y0BAi7jOzj1grT&vUh_qhE6x;%Jmye9ViSb&`;RS zw%PpNi~cLDq?%2zo{3QPS-ex@_C*id+{f(5HtdYx95{6xIk+EV;PSO=oIG+EGw_*C z!J52mE-c(eQO=&b0Kn0M2XN6toVrYbO(k@z#x>M|H(5ys#!YJ?P@f0)>)gF$F!jC6 zj7;NCTAVu6Wk=VZ#SZP=2f#O%F6XB(%gy;8IB@VNc4e(jnx@2waQgTOD&-Qs^)O<% z-*`ysk_`n0qR-~WH4yzlB?jkY&x8m85AWBw@I{lLb%5PF_7hH8)MfM5!^e-gb@v`l z9s76hX8ZIMin4##ZuaclNn^duT5X+$2TN3|b!@x6jx~nS(Q)P%pQ0|MR4A}##}q1x zQ-&=x2zbErFGar(TkuSTk&xx38s~n$!ph<}u3Mtje85;~l8Lb~RF$R2kGOH`He(aB zc*bM?-U4yA!`S!)_m`fr)>ubGhyu&Di3#F3#?DTTfM$MDRpKXLGu*j%kI_>nP*v_fctB-z ziejORB8*SWaR2cN3(GYsrI4LdqxgR24w3A+ws(rlnux;)jE@wk6hofHOX#2iTP5$N z%45Xfc?GN~^887i+m}{pFVAxQQjMd(_;Y;Ur`c!{*Y9BBE>E7`C5aOhrCO`AbJuLv zI8hqSHsXcMPE-i|{E(&Da;Nu9JKX&?vRjN08V^-7Y@t^UZ-Q@2_+FWnXLZh>xrbjr zz<4x6r4kbQ4*)}Ry@QH}S3X42X`p(CBNe&Omn&j27Y|k;UaJ3wz?KNS3acwku3oIMym**L->>r7pY8x4NwNrc;{+p6 zDHmzCySTCAu=rhH0RWdKG@5N7a{?IDWmt5er1d6e+hg4eztUS^<;vt1+6-L85ZE%2 zKgNrd20zTLvAl4Ea`|n>MhiUm&lAV-P{;MHN2eRJT3gQoCE3~`NxRt^M}&H#MdBRW zMvFP7Z10in3QT`;Mzal-?GI9DKan%+lIMny4p|5ye}vEtnEd?^(~ZVdBy=%L*P{? z2HU9DTU?pD&z%dFZs$1L_I|?5$qr5m)S3kXzDb!I8EXl)q0C+ zqmwB>ra-X}(2Wzi@y2Gh-AQP78Utfd2BuIb(CNm+Ns3pTp*Ve-#?v{<1&i?vA{p?F z-L0r*Lzb$lIz+8HO;t5PiBT83EDr>Qk!TvHj&?Vp9UF=}KEx}|prWcJRkhtXk$NizuSjv~B&NIzAT%fgjlUA)sxeyQqHv3x%k)|Tc zsIFL5UCa~rd77qCt=aVwi6opniC^9Wrnfd14A5-FtUr9w-`)*=RZ1a~<0S+kbxP=a zL*x?YNILGNdy~`=`W{bK>QrmZtcVy7uX2D=aW6?@k>=WUTJ3eMl)_Ye+cvlrkj4K2 XE>yyZSdFAp00000NkvXXu0mjfgA3Z> From f5f8f62e8e6b424e61b76ab573e313c9d94ad8a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 7 May 2018 09:34:46 +0200 Subject: [PATCH 112/321] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index f6cc51181..715bbfb90 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -15,6 +15,7 @@ Programmers Adam Hogan (aurix) Aesylwinn aegis + AHSauge Aleksandar Jovanov Alex Haddad (rainChu) Alex McKibben From 57ee5f9b533cffc1d9f1caa68d488d50a215dc01 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 7 May 2018 09:51:09 +0200 Subject: [PATCH 113/321] updated credits file --- AUTHORS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 715bbfb90..3b8088c7e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -157,6 +157,7 @@ Programmers terrorfisch thegriglat Thomas Luppi (Digmaster) + unelsson Will Herrmann (Thunderforge) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) @@ -226,7 +227,7 @@ Artwork Necrod - OpenMW Logo Mickey Lyle (raevol) - Wordpress Theme - Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons + Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel, Lamoot - OpenMW Editor Icons Inactive Contributors --------------------- From 53b6ef6f8ce122ae558000c5cd3de46cee99062c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 7 May 2018 09:54:42 +0200 Subject: [PATCH 114/321] minor code cleanup --- apps/openmw/mwstate/quicksavemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp index 9f522d7eb..59658ce6e 100644 --- a/apps/openmw/mwstate/quicksavemanager.cpp +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -3,8 +3,8 @@ MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, unsigned int maxSaves) : mSaveName(saveName) , mMaxSaves(maxSaves) - , mOldestSlotVisited(NULL) , mSlotsVisited(0) + , mOldestSlotVisited(nullptr) { } From 905cde10dbefa4ac43ed3ea3921173a847ea523a Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Mon, 23 Apr 2018 22:21:23 +0300 Subject: [PATCH 115/321] Smart-sorting in iniimporter (time + dependency) --- apps/mwiniimporter/importer.cpp | 98 +++++++++++++++++++++++++++++---- apps/mwiniimporter/importer.hpp | 9 ++- 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 24646b844..66b56f8a6 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -824,33 +825,73 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { - std::vector > contentFiles; +void MwIniImporter::dependencySortStep(std::string& el, MwIniImporter::deplist& src, std::vector& ret) +{ + auto it = std::find_if(src.begin(), src.end(), [&el](std::pair< std::string, std::vector >& o) + { + return o.first == el; + }); + if (it != src.end()) + { + auto o = std::move(*it); + src.erase(it); + for (auto name : o.second) + { + MwIniImporter::dependencySortStep(name, src, ret); + } + ret.push_back(std::move(o.first)); + } +} + +std::vector MwIniImporter::dependencySort(MwIniImporter::deplist src) +{ + std::vector ret; + while (!src.empty()) + { + MwIniImporter::dependencySortStep(src.begin()->first, src, ret); + } + return ret; +} + +std::vector::iterator MwIniImporter::findString(std::vector& v, const std::string& s) +{ + return std::find_if(v.begin(), v.end(), [&s](const std::string& str) + { + return Misc::StringUtils::ciEqual(str, s); + }); +} + +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const +{ + std::vector> contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); std::time_t defaultTime = 0; + ToUTF8::Utf8Encoder encoder(mEncoding); // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); - for(int i=0; it != ini.end(); i++) { + for (int i=0; it != ini.end(); i++) + { gameFile = baseGameFile; gameFile.append(this->numberToString(i)); it = ini.find(gameFile); - if(it == ini.end()) { + if(it == ini.end()) break; - } - for(std::vector::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { + for(std::vector::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) + { std::string filetype(entry->substr(entry->length()-3)); Misc::StringUtils::lowerCaseInPlace(filetype); - if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { + if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) + { boost::filesystem::path filepath(gameFilesDir); filepath /= *entry; - contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry)); + contentFiles.push_back({lastWriteTime(filepath, defaultTime), filepath}); } } } @@ -858,11 +899,46 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co cfg.erase("content"); cfg.insert( std::make_pair("content", std::vector() ) ); - // this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed. + // sort by timestamp sort(contentFiles.begin(), contentFiles.end()); - for(std::vector >::const_iterator iter=contentFiles.begin(); iter!=contentFiles.end(); ++iter) { - cfg["content"].push_back(iter->second); + + MwIniImporter::deplist unsortedFiles; + + ESM::ESMReader reader; + reader.setEncoder(&encoder); + for (auto& file : contentFiles) + { + reader.open(file.second.string()); + std::vector deps; + for (auto& depFile : reader.getGameFiles()) + { + deps.push_back(depFile.name); + } + unsortedFiles.emplace_back(boost::filesystem::path(reader.getName()).filename().string(), deps); + reader.close(); + } + + auto sortedFiles = dependencySort(unsortedFiles); + + // hard-coded dependency Morrowind - Tribunal - Bloodmoon + if(findString(sortedFiles, "Morrowind.esm") != sortedFiles.end()) + { + auto foundTribunal = findString(sortedFiles, "Tribunal.esm"); + auto foundBloodmoon = findString(sortedFiles, "Bloodmoon.esm"); + + if (foundBloodmoon != sortedFiles.end() && foundTribunal != sortedFiles.end()) + { + size_t dstBloodmoon = std::distance(sortedFiles.begin(), foundBloodmoon); + size_t dstTribunal = std::distance(sortedFiles.begin(), foundTribunal); + if (dstBloodmoon < dstTribunal) + dstTribunal++; + sortedFiles.insert(foundBloodmoon, *foundTribunal); + sortedFiles.erase(sortedFiles.begin() + dstTribunal); + } } + + for (auto& file : sortedFiles) + cfg["content"].push_back(file); } void MwIniImporter::writeToFile(std::ostream &out, const multistrmap &cfg) { diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index c73cc65b5..44b2af83c 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -14,6 +14,7 @@ class MwIniImporter { public: typedef std::map strmap; typedef std::map > multistrmap; + typedef std::vector< std::pair< std::string, std::vector > > deplist; MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); @@ -22,12 +23,17 @@ class MwIniImporter { static multistrmap loadCfgFile(const boost::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; - void importGameFiles(multistrmap &cfg, const multistrmap &ini, + void importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); + static std::vector dependencySort(MwIniImporter::deplist src); + private: + static void dependencySortStep(std::string& el, MwIniImporter::deplist& src, std::vector& ret); + static std::vector::iterator findString(std::vector& v, const std::string& s); + static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); @@ -40,5 +46,4 @@ class MwIniImporter { ToUTF8::FromType mEncoding; }; - #endif From b15bed8e2270c7a4f2d475921bcd10472c1cf0c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 7 May 2018 20:40:53 +0400 Subject: [PATCH 116/321] Avoid excessive loadSound calls --- apps/openmw/mwsound/soundmanagerimp.cpp | 40 +++++++++++++------------ apps/openmw/mwsound/soundmanagerimp.hpp | 3 ++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ba8ac1bba..0dd95f773 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -20,9 +20,9 @@ #include "../mwmechanics/actorutil.hpp" -#include "sound_output.hpp" #include "sound_buffer.hpp" #include "sound_decoder.hpp" +#include "sound_output.hpp" #include "sound.hpp" #include "openal_output.hpp" @@ -578,7 +578,7 @@ namespace MWSound if(!sfx) return nullptr; // Only one copy of given sound can be played at time, so stop previous copy - stopSound(soundId); + stopSound(sfx, MWWorld::ConstPtr()); Sound *sound = getSoundRef(); sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); @@ -614,7 +614,7 @@ namespace MWSound return nullptr; // Only one copy of given sound can be played at time on ptr, so stop previous copy - stopSound3D(ptr, soundId); + stopSound(sfx, ptr); bool played; Sound *sound = getSoundRef(); @@ -681,12 +681,11 @@ namespace MWSound mOutput->finishSound(sound); } - void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId) + void SoundManager::stopSound(Sound_Buffer *sfx, const MWWorld::ConstPtr &ptr) { SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); for(SoundBufferRefPair &snd : snditer->second) { if(snd.second == sfx) @@ -695,6 +694,22 @@ namespace MWSound } } + void SoundManager::stopSound(const std::string& soundId) + { + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if (!sfx) return; + + stopSound(sfx, MWWorld::ConstPtr()); + } + + void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId) + { + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if (!sfx) return; + + stopSound(sfx, ptr); + } + void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr) { SoundMap::iterator snditer = mActiveSounds.find(ptr); @@ -718,6 +733,7 @@ namespace MWSound mOutput->finishSound(sndbuf.first); } } + for(SaySoundMap::value_type &snd : mActiveSaySounds) { if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell) @@ -725,20 +741,6 @@ namespace MWSound } } - void SoundManager::stopSound(const std::string& soundId) - { - SoundMap::iterator snditer = mActiveSounds.find(MWWorld::ConstPtr()); - if(snditer != mActiveSounds.end()) - { - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - for(SoundBufferRefPair &sndbuf : snditer->second) - { - if(sndbuf.second == sfx) - mOutput->finishSound(sndbuf.first); - } - } - } - void SoundManager::fadeOutSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, float duration) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e31a0e575..4064a05af 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -145,6 +145,9 @@ namespace MWSound DecoderPtr getDecoder(); friend class OpenAL_Output; + void stopSound(Sound_Buffer *sfx, const MWWorld::ConstPtr &ptr); + ///< Stop the given object from playing given sound buffer. + public: SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound); virtual ~SoundManager(); From 2f89080b36e4b2ddbb33c15db7b670608d981a9a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 7 May 2018 22:32:04 +0400 Subject: [PATCH 117/321] Load default markers definitions in editor --- apps/opencs/model/world/data.cpp | 26 ++++++++++++++++++++++++++ apps/opencs/model/world/data.hpp | 2 ++ 2 files changed, 28 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 2216d5ca6..053754943 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -962,6 +962,29 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base return mReader->getRecordCount(); } +void CSMWorld::Data::loadFallbackEntries() +{ + // Load default marker definitions, if game files do not have them for some reason + std::pair markers[] = { + std::make_pair("divinemarker", "marker_divine.nif"), + std::make_pair("doormarker", "marker_arrow.nif"), + std::make_pair("northmarker", "marker_north.nif"), + std::make_pair("templemarker", "marker_temple.nif"), + std::make_pair("travelmarker", "marker_travel.nif") + }; + + for (const std::pair marker : markers) + { + if (mReferenceables.searchId (marker.first)==-1) + { + CSMWorld::Record record; + record.mBase = ESM::Static(marker.first, marker.second); + record.mState = CSMWorld::RecordBase::State_BaseOnly; + mReferenceables.appendRecord (record, CSMWorld::UniversalId::Type_Static); + } + } +} + bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { if (!mReader) @@ -983,6 +1006,9 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) mReader = 0; mDialogue = 0; + + loadFallbackEntries(); + return true; } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8a3667ea1..1b975f430 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -144,6 +144,8 @@ namespace CSMWorld static int count (RecordBase::State state, const CollectionBase& collection); + void loadFallbackEntries(); + public: Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, From 103a07b7441fd3635be6fd42dfdfa669239e9dbe Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Tue, 8 May 2018 18:32:06 +0300 Subject: [PATCH 118/321] Less cryptic abbreviations --- apps/mwiniimporter/importer.cpp | 70 +++++++++++++++++---------------- apps/mwiniimporter/importer.hpp | 8 ++-- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 66b56f8a6..74c21da29 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -825,39 +825,43 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } } -void MwIniImporter::dependencySortStep(std::string& el, MwIniImporter::deplist& src, std::vector& ret) +void MwIniImporter::dependencySortStep(std::string& element, MwIniImporter::dependencyList& source, std::vector& result) { - auto it = std::find_if(src.begin(), src.end(), [&el](std::pair< std::string, std::vector >& o) - { - return o.first == el; - }); - if (it != src.end()) + auto iter = std::find_if( + source.begin(), + source.end(), + [&element](std::pair< std::string, std::vector >& sourceElement) + { + return sourceElement.first == element; + } + ); + if (iter != source.end()) { - auto o = std::move(*it); - src.erase(it); - for (auto name : o.second) + auto foundElement = std::move(*iter); + source.erase(iter); + for (auto name : foundElement.second) { - MwIniImporter::dependencySortStep(name, src, ret); + MwIniImporter::dependencySortStep(name, source, result); } - ret.push_back(std::move(o.first)); + result.push_back(std::move(foundElement.first)); } } -std::vector MwIniImporter::dependencySort(MwIniImporter::deplist src) +std::vector MwIniImporter::dependencySort(MwIniImporter::dependencyList source) { - std::vector ret; - while (!src.empty()) + std::vector result; + while (!source.empty()) { - MwIniImporter::dependencySortStep(src.begin()->first, src, ret); + MwIniImporter::dependencySortStep(source.begin()->first, source, result); } - return ret; + return result; } -std::vector::iterator MwIniImporter::findString(std::vector& v, const std::string& s) +std::vector::iterator MwIniImporter::findString(std::vector& source, const std::string& string) { - return std::find_if(v.begin(), v.end(), [&s](const std::string& str) + return std::find_if(source.begin(), source.end(), [&string](const std::string& sourceString) { - return Misc::StringUtils::ciEqual(str, s); + return Misc::StringUtils::ciEqual(sourceString, string); }); } @@ -902,19 +906,19 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co // sort by timestamp sort(contentFiles.begin(), contentFiles.end()); - MwIniImporter::deplist unsortedFiles; + MwIniImporter::dependencyList unsortedFiles; ESM::ESMReader reader; reader.setEncoder(&encoder); for (auto& file : contentFiles) { reader.open(file.second.string()); - std::vector deps; - for (auto& depFile : reader.getGameFiles()) + std::vector dependencies; + for (auto& gameFile : reader.getGameFiles()) { - deps.push_back(depFile.name); + dependencies.push_back(gameFile.name); } - unsortedFiles.emplace_back(boost::filesystem::path(reader.getName()).filename().string(), deps); + unsortedFiles.emplace_back(boost::filesystem::path(reader.getName()).filename().string(), dependencies); reader.close(); } @@ -923,17 +927,17 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co // hard-coded dependency Morrowind - Tribunal - Bloodmoon if(findString(sortedFiles, "Morrowind.esm") != sortedFiles.end()) { - auto foundTribunal = findString(sortedFiles, "Tribunal.esm"); - auto foundBloodmoon = findString(sortedFiles, "Bloodmoon.esm"); + auto tribunalIter = findString(sortedFiles, "Tribunal.esm"); + auto bloodmoonIter = findString(sortedFiles, "Bloodmoon.esm"); - if (foundBloodmoon != sortedFiles.end() && foundTribunal != sortedFiles.end()) + if (bloodmoonIter != sortedFiles.end() && tribunalIter != sortedFiles.end()) { - size_t dstBloodmoon = std::distance(sortedFiles.begin(), foundBloodmoon); - size_t dstTribunal = std::distance(sortedFiles.begin(), foundTribunal); - if (dstBloodmoon < dstTribunal) - dstTribunal++; - sortedFiles.insert(foundBloodmoon, *foundTribunal); - sortedFiles.erase(sortedFiles.begin() + dstTribunal); + size_t bloodmoonIndex = std::distance(sortedFiles.begin(), bloodmoonIter); + size_t tribunalIndex = std::distance(sortedFiles.begin(), tribunalIter); + if (bloodmoonIndex < tribunalIndex) + tribunalIndex++; + sortedFiles.insert(bloodmoonIter, *tribunalIter); + sortedFiles.erase(sortedFiles.begin() + tribunalIndex); } } diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 44b2af83c..e1595ad96 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -14,7 +14,7 @@ class MwIniImporter { public: typedef std::map strmap; typedef std::map > multistrmap; - typedef std::vector< std::pair< std::string, std::vector > > deplist; + typedef std::vector< std::pair< std::string, std::vector > > dependencyList; MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); @@ -28,11 +28,11 @@ class MwIniImporter { void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); - static std::vector dependencySort(MwIniImporter::deplist src); + static std::vector dependencySort(MwIniImporter::dependencyList source); private: - static void dependencySortStep(std::string& el, MwIniImporter::deplist& src, std::vector& ret); - static std::vector::iterator findString(std::vector& v, const std::string& s); + static void dependencySortStep(std::string& element, MwIniImporter::dependencyList& source, std::vector& result); + static std::vector::iterator findString(std::vector& source, const std::string& string); static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); From feeee50a88ca6172c841e480a2851a7ac4fd535d Mon Sep 17 00:00:00 2001 From: Alf Henrik Sauge Date: Wed, 9 May 2018 00:25:07 +0200 Subject: [PATCH 119/321] Dropping a separate NPDTstruct12 object and instead use NPDTstruct52 NPDTstruct12 is now only used when loading and saving. Turning auto calc on and off now no longer switches between to different set of values --- apps/esmtool/record.cpp | 62 ++++++++-------- apps/essimporter/converter.hpp | 2 +- apps/essimporter/importer.cpp | 2 +- .../opencs/model/tools/referenceablecheck.cpp | 36 +++++----- apps/opencs/model/world/refidadapterimp.cpp | 72 +++++++++---------- apps/openmw/mwclass/npc.cpp | 45 ++++++------ .../mwmechanics/mechanicsmanagerimp.cpp | 22 +++--- components/esm/loadnpc.cpp | 70 +++++++++++------- components/esm/loadnpc.hpp | 10 ++- 9 files changed, 171 insertions(+), 150 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index c123ace44..089a25c93 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1040,45 +1040,47 @@ void Record::print() if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) { - std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl; - std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl; - std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl; - std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl; - std::cout << " Unknown1: " - << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; - std::cout << " Unknown2: " - << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; - std::cout << " Unknown3: " - << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; - std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl; + std::cout << " Level: " << mData.mNpdt.mLevel << std::endl; + std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl; + std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl; + std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl; + //Why do we want to print these fields? They are padding in the struct and contain + // nothing of real value. Now we don't deal with NPDTstruct12 in runtime either... + //std::cout << " Unknown1: " + // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; + //std::cout << " Unknown2: " + // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; + //std::cout << " Unknown3: " + // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; + std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } else { - std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl; - std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl; - std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl; - std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl; - std::cout << " FactionID: " << (int)mData.mNpdt52.mFactionID << std::endl; + std::cout << " Level: " << mData.mNpdt.mLevel << std::endl; + std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl; + std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl; + std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl; + std::cout << " FactionID: " << (int)mData.mNpdt.mFactionID << std::endl; std::cout << " Attributes:" << std::endl; - std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl; - std::cout << " Intelligence: " << (int)mData.mNpdt52.mIntelligence << std::endl; - std::cout << " Willpower: " << (int)mData.mNpdt52.mWillpower << std::endl; - std::cout << " Agility: " << (int)mData.mNpdt52.mAgility << std::endl; - std::cout << " Speed: " << (int)mData.mNpdt52.mSpeed << std::endl; - std::cout << " Endurance: " << (int)mData.mNpdt52.mEndurance << std::endl; - std::cout << " Personality: " << (int)mData.mNpdt52.mPersonality << std::endl; - std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl; + std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl; + std::cout << " Intelligence: " << (int)mData.mNpdt.mIntelligence << std::endl; + std::cout << " Willpower: " << (int)mData.mNpdt.mWillpower << std::endl; + std::cout << " Agility: " << (int)mData.mNpdt.mAgility << std::endl; + std::cout << " Speed: " << (int)mData.mNpdt.mSpeed << std::endl; + std::cout << " Endurance: " << (int)mData.mNpdt.mEndurance << std::endl; + std::cout << " Personality: " << (int)mData.mNpdt.mPersonality << std::endl; + std::cout << " Luck: " << (int)mData.mNpdt.mLuck << std::endl; std::cout << " Skills:" << std::endl; for (int i = 0; i != ESM::Skill::Length; i++) std::cout << " " << skillLabel(i) << ": " - << (int)(mData.mNpdt52.mSkills[i]) << std::endl; + << (int)(mData.mNpdt.mSkills[i]) << std::endl; - std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl; - std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl; - std::cout << " Fatigue: " << mData.mNpdt52.mFatigue << std::endl; - std::cout << " Unknown: " << (int)mData.mNpdt52.mUnknown << std::endl; - std::cout << " Gold: " << mData.mNpdt52.mGold << std::endl; + std::cout << " Health: " << mData.mNpdt.mHealth << std::endl; + std::cout << " Magicka: " << mData.mNpdt.mMana << std::endl; + std::cout << " Fatigue: " << mData.mNpdt.mFatigue << std::endl; + std::cout << " Unknown: " << (int)mData.mNpdt.mUnknown << std::endl; + std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } std::vector::iterator cit; diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 621b85709..1772e0e2d 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -122,7 +122,7 @@ public: } else { - mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; + mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt.mLevel; mContext->mPlayerBase = npc; ESM::SpellState::SpellParams empty; // FIXME: player start spells and birthsign spells aren't listed here, diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 73b15baae..4538d4e63 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -377,7 +377,7 @@ namespace ESSImport profile.mPlayerClassName = context.mCustomPlayerClassName; else profile.mPlayerClassId = context.mPlayerBase.mClass; - profile.mPlayerLevel = context.mPlayerBase.mNpdt52.mLevel; + profile.mPlayerLevel = context.mPlayerBase.mNpdt.mLevel; profile.mPlayerName = header.mGameData.mPlayerName.toString(); writeScreenshot(header, profile); diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 750c3ceb4..1e86dfe37 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -619,12 +619,12 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( const ESM::NPC& npc = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId); - short level(npc.mNpdt52.mLevel); - char disposition(npc.mNpdt52.mDisposition); - char reputation(npc.mNpdt52.mReputation); - char rank(npc.mNpdt52.mRank); + short level(npc.mNpdt.mLevel); + char disposition(npc.mNpdt.mDisposition); + char reputation(npc.mNpdt.mReputation); + char rank(npc.mNpdt.mRank); //Don't know what unknown is for - int gold(npc.mNpdt52.mGold); + int gold(npc.mNpdt.mGold); //Detect if player is present if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl? @@ -638,36 +638,36 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( return; } - level = npc.mNpdt12.mLevel; - disposition = npc.mNpdt12.mDisposition; - reputation = npc.mNpdt12.mReputation; - rank = npc.mNpdt12.mRank; - gold = npc.mNpdt12.mGold; + level = npc.mNpdt.mLevel; + disposition = npc.mNpdt.mDisposition; + reputation = npc.mNpdt.mReputation; + rank = npc.mNpdt.mRank; + gold = npc.mNpdt.mGold; } else { - if (npc.mNpdt52.mAgility == 0) + if (npc.mNpdt.mAgility == 0) messages.push_back (std::make_pair (id, npc.mId + " agility has zero value")); - if (npc.mNpdt52.mEndurance == 0) + if (npc.mNpdt.mEndurance == 0) messages.push_back (std::make_pair (id, npc.mId + " endurance has zero value")); - if (npc.mNpdt52.mIntelligence == 0) + if (npc.mNpdt.mIntelligence == 0) messages.push_back (std::make_pair (id, npc.mId + " intelligence has zero value")); - if (npc.mNpdt52.mLuck == 0) + if (npc.mNpdt.mLuck == 0) messages.push_back (std::make_pair (id, npc.mId + " luck has zero value")); - if (npc.mNpdt52.mPersonality == 0) + if (npc.mNpdt.mPersonality == 0) messages.push_back (std::make_pair (id, npc.mId + " personality has zero value")); - if (npc.mNpdt52.mStrength == 0) + if (npc.mNpdt.mStrength == 0) messages.push_back (std::make_pair (id, npc.mId + " strength has zero value")); - if (npc.mNpdt52.mSpeed == 0) + if (npc.mNpdt.mSpeed == 0) messages.push_back (std::make_pair (id, npc.mId + " speed has zero value")); - if (npc.mNpdt52.mWillpower == 0) + if (npc.mNpdt.mWillpower == 0) messages.push_back (std::make_pair (id, npc.mId + " willpower has zero value")); } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index ba67b4e14..352384c73 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -914,7 +914,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col ESM::NPC npc = record.get(); // store the whole struct - npc.mNpdt52 = + npc.mNpdt = static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); @@ -928,7 +928,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab // return the whole struct std::vector wrap; - wrap.push_back(record.get().mNpdt52); + wrap.push_back(record.get().mNpdt); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); } @@ -939,7 +939,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn * const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); - const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt; if (subColIndex == 0) return subRowIndex; @@ -966,7 +966,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedData (const RefIdColumn *colu Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); ESM::NPC npc = record.get(); - ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt; if (subColIndex == 1) switch(subRowIndex) @@ -1021,7 +1021,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column, ESM::NPC npc = record.get(); // store the whole struct - npc.mNpdt52 = + npc.mNpdt = static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); @@ -1035,7 +1035,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable ( // return the whole struct std::vector wrap; - wrap.push_back(record.get().mNpdt52); + wrap.push_back(record.get().mNpdt); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); } @@ -1046,7 +1046,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); - const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) throw std::runtime_error ("index out of range"); @@ -1065,7 +1065,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column, Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); ESM::NPC npc = record.get(); - ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) throw std::runtime_error ("index out of range"); @@ -1130,30 +1130,30 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column if (autoCalc) switch (subColIndex) { - case 0: return static_cast(record.get().mNpdt12.mLevel); + case 0: return static_cast(record.get().mNpdt.mLevel); case 1: return QVariant(QVariant::UserType); case 2: return QVariant(QVariant::UserType); case 3: return QVariant(QVariant::UserType); case 4: return QVariant(QVariant::UserType); - case 5: return static_cast(record.get().mNpdt12.mDisposition); - case 6: return static_cast(record.get().mNpdt12.mReputation); - case 7: return static_cast(record.get().mNpdt12.mRank); - case 8: return record.get().mNpdt12.mGold; + case 5: return static_cast(record.get().mNpdt.mDisposition); + case 6: return static_cast(record.get().mNpdt.mReputation); + case 7: return static_cast(record.get().mNpdt.mRank); + case 8: return record.get().mNpdt.mGold; case 9: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } else switch (subColIndex) { - case 0: return static_cast(record.get().mNpdt52.mLevel); - case 1: return static_cast(record.get().mNpdt52.mFactionID); - case 2: return static_cast(record.get().mNpdt52.mHealth); - case 3: return static_cast(record.get().mNpdt52.mMana); - case 4: return static_cast(record.get().mNpdt52.mFatigue); - case 5: return static_cast(record.get().mNpdt52.mDisposition); - case 6: return static_cast(record.get().mNpdt52.mReputation); - case 7: return static_cast(record.get().mNpdt52.mRank); - case 8: return record.get().mNpdt52.mGold; + case 0: return static_cast(record.get().mNpdt.mLevel); + case 1: return static_cast(record.get().mNpdt.mFactionID); + case 2: return static_cast(record.get().mNpdt.mHealth); + case 3: return static_cast(record.get().mNpdt.mMana); + case 4: return static_cast(record.get().mNpdt.mFatigue); + case 5: return static_cast(record.get().mNpdt.mDisposition); + case 6: return static_cast(record.get().mNpdt.mReputation); + case 7: return static_cast(record.get().mNpdt.mRank); + case 8: return record.get().mNpdt.mGold; case 9: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } @@ -1171,30 +1171,30 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, if (autoCalc) switch(subColIndex) { - case 0: npc.mNpdt12.mLevel = static_cast(value.toInt()); break; + case 0: npc.mNpdt.mLevel = static_cast(value.toInt()); break; case 1: return; case 2: return; case 3: return; case 4: return; - case 5: npc.mNpdt12.mDisposition = static_cast(value.toInt()); break; - case 6: npc.mNpdt12.mReputation = static_cast(value.toInt()); break; - case 7: npc.mNpdt12.mRank = static_cast(value.toInt()); break; - case 8: npc.mNpdt12.mGold = value.toInt(); break; + case 5: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt.mGold = value.toInt(); break; case 9: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } else switch(subColIndex) { - case 0: npc.mNpdt52.mLevel = static_cast(value.toInt()); break; - case 1: npc.mNpdt52.mFactionID = static_cast(value.toInt()); break; - case 2: npc.mNpdt52.mHealth = static_cast(value.toInt()); break; - case 3: npc.mNpdt52.mMana = static_cast(value.toInt()); break; - case 4: npc.mNpdt52.mFatigue = static_cast(value.toInt()); break; - case 5: npc.mNpdt52.mDisposition = static_cast(value.toInt()); break; - case 6: npc.mNpdt52.mReputation = static_cast(value.toInt()); break; - case 7: npc.mNpdt52.mRank = static_cast(value.toInt()); break; - case 8: npc.mNpdt52.mGold = value.toInt(); break; + case 0: npc.mNpdt.mLevel = static_cast(value.toInt()); break; + case 1: npc.mNpdt.mFactionID = static_cast(value.toInt()); break; + case 2: npc.mNpdt.mHealth = static_cast(value.toInt()); break; + case 3: npc.mNpdt.mMana = static_cast(value.toInt()); break; + case 4: npc.mNpdt.mFatigue = static_cast(value.toInt()); break; + case 5: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt.mGold = value.toInt(); break; case 9: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 974a08c11..f3f763897 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -312,40 +312,40 @@ namespace MWClass int gold=0; if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) { - gold = ref->mBase->mNpdt52.mGold; + gold = ref->mBase->mNpdt.mGold; for (unsigned int i=0; i< ESM::Skill::Length; ++i) - data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt52.mSkills[i]); + data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt.mSkills[i]); - data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt52.mStrength); - data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt52.mIntelligence); - data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt52.mWillpower); - data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt52.mAgility); - data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt52.mSpeed); - data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt52.mEndurance); - data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt52.mPersonality); - data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt52.mLuck); + data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength); + data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence); + data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt.mWillpower); + data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt.mAgility); + data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt.mSpeed); + data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt.mEndurance); + data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt.mPersonality); + data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt.mLuck); - data->mNpcStats.setHealth (ref->mBase->mNpdt52.mHealth); - data->mNpcStats.setMagicka (ref->mBase->mNpdt52.mMana); - data->mNpcStats.setFatigue (ref->mBase->mNpdt52.mFatigue); + data->mNpcStats.setHealth (ref->mBase->mNpdt.mHealth); + data->mNpcStats.setMagicka (ref->mBase->mNpdt.mMana); + data->mNpcStats.setFatigue (ref->mBase->mNpdt.mFatigue); - data->mNpcStats.setLevel(ref->mBase->mNpdt52.mLevel); - data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); - data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation); + data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation); data->mNpcStats.setNeedRecalcDynamicStats(false); } else { - gold = ref->mBase->mNpdt12.mGold; + gold = ref->mBase->mNpdt.mGold; for (int i=0; i<3; ++i) data->mNpcStats.setDynamic (i, 10); - data->mNpcStats.setLevel(ref->mBase->mNpdt12.mLevel); - data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); - data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation); autoCalculateAttributes(ref->mBase, data->mNpcStats); autoCalculateSkills(ref->mBase, data->mNpcStats, ptr); @@ -1327,10 +1327,7 @@ namespace MWClass int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); - if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) - return ref->mBase->mNpdt52.mGold; - else - return ref->mBase->mNpdt12.mGold; + return ref->mBase->mNpdt.mGold; } bool Npc::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1de608a1f..df93d875d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -79,21 +79,21 @@ namespace MWMechanics const ESM::NPC *player = ptr.get()->mBase; // reset - creatureStats.setLevel(player->mNpdt52.mLevel); + creatureStats.setLevel(player->mNpdt.mLevel); creatureStats.getSpells().clear(); creatureStats.modifyMagicEffects(MagicEffects()); for (int i=0; i<27; ++i) - npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]); - - creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt52.mStrength); - creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt52.mIntelligence); - creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt52.mWillpower); - creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt52.mAgility); - creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt52.mSpeed); - creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt52.mEndurance); - creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt52.mPersonality); - creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt52.mLuck); + npcStats.getSkill (i).setBase (player->mNpdt.mSkills[i]); + + creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength); + creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence); + creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt.mWillpower); + creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt.mAgility); + creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt.mSpeed); + creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt.mEndurance); + creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt.mPersonality); + creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt.mLuck); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index a68c97a6a..8609ab65a 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -62,12 +62,23 @@ namespace ESM if (esm.getSubSize() == 52) { mNpdtType = NPC_DEFAULT; - esm.getExact(&mNpdt52, 52); + esm.getExact(&mNpdt, 52); } else if (esm.getSubSize() == 12) { + //Reading into temporary NPDTstruct12 object + NPDTstruct12 npdt12; mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - esm.getExact(&mNpdt12, 12); + esm.getExact(&npdt12, 12); + + //Clearing the mNdpt struct to initialize all values + blankNpdt(); + //Swiching to an internal representation + mNpdt.mLevel = npdt12.mLevel; + mNpdt.mDisposition = npdt12.mDisposition; + mNpdt.mReputation = npdt12.mReputation; + mNpdt.mRank = npdt12.mRank; + mNpdt.mGold = npdt12.mGold; } else esm.fail("NPC_NPDT must be 12 or 52 bytes long"); @@ -135,9 +146,19 @@ namespace ESM esm.writeHNOCString("SCRI", mScript); if (mNpdtType == NPC_DEFAULT) - esm.writeHNT("NPDT", mNpdt52, 52); + { + esm.writeHNT("NPDT", mNpdt, 52); + } else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) - esm.writeHNT("NPDT", mNpdt12, 12); + { + NPDTstruct12 npdt12; + npdt12.mLevel = mNpdt.mLevel; + npdt12.mDisposition = mNpdt.mDisposition; + npdt12.mReputation = mNpdt.mReputation; + npdt12.mRank = mNpdt.mRank; + npdt12.mGold = mNpdt.mGold; + esm.writeHNT("NPDT", npdt12, 12); + } esm.writeHNT("FLAG", mFlags); @@ -171,25 +192,7 @@ namespace ESM void NPC::blank() { mNpdtType = NPC_DEFAULT; - mNpdt52.mLevel = 0; - mNpdt52.mStrength = mNpdt52.mIntelligence = mNpdt52.mWillpower = mNpdt52.mAgility = - mNpdt52.mSpeed = mNpdt52.mEndurance = mNpdt52.mPersonality = mNpdt52.mLuck = 0; - for (int i=0; i< Skill::Length; ++i) mNpdt52.mSkills[i] = 0; - mNpdt52.mReputation = 0; - mNpdt52.mHealth = mNpdt52.mMana = mNpdt52.mFatigue = 0; - mNpdt52.mDisposition = 0; - mNpdt52.mFactionID = 0; - mNpdt52.mRank = 0; - mNpdt52.mUnknown = 0; - mNpdt52.mGold = 0; - mNpdt12.mLevel = 0; - mNpdt12.mDisposition = 0; - mNpdt12.mReputation = 0; - mNpdt12.mRank = 0; - mNpdt12.mUnknown1 = 0; - mNpdt12.mUnknown2 = 0; - mNpdt12.mUnknown3 = 0; - mNpdt12.mGold = 0; + blankNpdt(); mFlags = 0; mInventory.mList.clear(); mSpells.mList.clear(); @@ -207,14 +210,27 @@ namespace ESM mHead.clear(); } + void NPC::blankNpdt() + { + mNpdt.mLevel = 0; + mNpdt.mStrength = mNpdt.mIntelligence = mNpdt.mWillpower = mNpdt.mAgility = + mNpdt.mSpeed = mNpdt.mEndurance = mNpdt.mPersonality = mNpdt.mLuck = 0; + for (int i=0; i< Skill::Length; ++i) mNpdt.mSkills[i] = 0; + mNpdt.mReputation = 0; + mNpdt.mHealth = mNpdt.mMana = mNpdt.mFatigue = 0; + mNpdt.mDisposition = 0; + mNpdt.mFactionID = 0; + mNpdt.mRank = 0; + mNpdt.mUnknown = 0; + mNpdt.mGold = 0; + } + int NPC::getFactionRank() const { if (mFaction.empty()) return -1; - else if (mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) - return mNpdt12.mRank; - else // NPC_DEFAULT - return mNpdt52.mRank; + else + return mNpdt.mRank; } const std::vector& NPC::getTransport() const diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index d7f30e079..5f567d999 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -95,6 +95,8 @@ struct NPC int mGold; }; // 52 bytes + //Structure for autocalculated characters. + // This is only used for load and save operations. struct NPDTstruct12 { short mLevel; @@ -106,8 +108,9 @@ struct NPC #pragma pack(pop) unsigned char mNpdtType; - NPDTstruct52 mNpdt52; - NPDTstruct12 mNpdt12; //for autocalculated characters + //Worth noting when saving the struct: + // Although we might read a NPDTstruct12 in, we use NPDTstruct52 internally + NPDTstruct52 mNpdt; int getFactionRank() const; /// wrapper for mNpdt*, -1 = no rank @@ -141,6 +144,9 @@ struct NPC void blank(); ///< Set record to default state (does not touch the ID). + + /// Resets the mNpdt object + void blankNpdt(); }; } #endif From 32d71de2f5196ee60b0729cb3b1c024022ece119 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 9 May 2018 07:33:45 +0300 Subject: [PATCH 120/321] Update MapWindow every frame, not just when it's open (bug #4279) --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c103f60ad..04c8e8a7d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -913,6 +913,9 @@ namespace MWGui updateMap(); + if (!mMap->isVisible()) + mMap->onFrame(frameDuration); + mHud->onFrame(frameDuration); mDebugWindow->onFrame(frameDuration); From d4f278a1136972e7cd2642f51c0ad5f39fb61686 Mon Sep 17 00:00:00 2001 From: Alf Henrik Sauge Date: Wed, 9 May 2018 18:02:02 +0200 Subject: [PATCH 121/321] Replacing tab with spaces --- components/esm/loadnpc.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 8609ab65a..dd34934ad 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -66,8 +66,8 @@ namespace ESM } else if (esm.getSubSize() == 12) { - //Reading into temporary NPDTstruct12 object - NPDTstruct12 npdt12; + //Reading into temporary NPDTstruct12 object + NPDTstruct12 npdt12; mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; esm.getExact(&npdt12, 12); @@ -147,17 +147,17 @@ namespace ESM if (mNpdtType == NPC_DEFAULT) { - esm.writeHNT("NPDT", mNpdt, 52); + esm.writeHNT("NPDT", mNpdt, 52); } else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) { - NPDTstruct12 npdt12; - npdt12.mLevel = mNpdt.mLevel; - npdt12.mDisposition = mNpdt.mDisposition; - npdt12.mReputation = mNpdt.mReputation; - npdt12.mRank = mNpdt.mRank; + NPDTstruct12 npdt12; + npdt12.mLevel = mNpdt.mLevel; + npdt12.mDisposition = mNpdt.mDisposition; + npdt12.mReputation = mNpdt.mReputation; + npdt12.mRank = mNpdt.mRank; npdt12.mGold = mNpdt.mGold; - esm.writeHNT("NPDT", npdt12, 12); + esm.writeHNT("NPDT", npdt12, 12); } esm.writeHNT("FLAG", mFlags); From 4ae75d1d20e6b3ef1de43cab5f9f29d281865af5 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 15 Apr 2018 14:47:31 +0300 Subject: [PATCH 122/321] Terrain texture brush frame --- apps/opencs/CMakeLists.txt | 2 +- .../view/render/pagedworldspacewidget.cpp | 3 +- .../opencs/view/render/terraintexturemode.cpp | 214 ++++++++++++++++++ .../opencs/view/render/terraintexturemode.hpp | 108 +++++++++ apps/opencs/view/render/worldspacewidget.cpp | 3 + apps/opencs/view/widget/scenetoolmode.cpp | 9 + apps/opencs/view/widget/scenetoolmode.hpp | 4 + files/opencs/resources.qrc | 8 +- 8 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/view/render/terraintexturemode.cpp create mode 100644 apps/opencs/view/render/terraintexturemode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f07b518a9..f8dd1fe2d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -88,7 +88,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller - cellwater + cellwater terraintexturemode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 4a745195b..1d1a7cd17 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -21,6 +21,7 @@ #include "mask.hpp" #include "cameracontroller.hpp" #include "cellarrow.hpp" +#include "terraintexturemode.hpp" bool CSVRender::PagedWorldspaceWidget::adjustCells() { @@ -136,7 +137,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"), "terrain-shape"); tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain texture editing"), + new TerrainTextureMode (this, tool), "terrain-texture"); tool->addButton ( new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"), diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp new file mode 100644 index 000000000..346ba3136 --- /dev/null +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -0,0 +1,214 @@ +// To-do: Getting Texture Id and Texture Filenames to base class Terraintexturemode +// To-do: Better data handling options for mBrushTexture +// To-do: loading texture bitmaps from virtual file system (vfs) for texture overlay icon + +#include "terraintexturemode.hpp" +#include "editmode.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../widget/modebutton.hpp" +#include "../widget/scenetoolbar.hpp" + +#include "../../model/world/universalid.hpp" +#include "../../model/world/tablemimedata.hpp" + +#include "pagedworldspacewidget.hpp" + + +CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) + : QGroupBox(title, parent) +{ + brushSizeSlider = new QSlider(Qt::Horizontal); + brushSizeSlider->setTickPosition(QSlider::TicksBothSides); + brushSizeSlider->setTickInterval(10); + brushSizeSlider->setSingleStep(1); + + brushSizeSpinBox = new QSpinBox; + brushSizeSpinBox->setRange(1, 100); + brushSizeSpinBox->setSingleStep(1); + + layoutSliderSize = new QHBoxLayout; + layoutSliderSize->addWidget(brushSizeSlider); + layoutSliderSize->addWidget(brushSizeSpinBox); + + connect(brushSizeSlider, SIGNAL(valueChanged(int)), brushSizeSpinBox, SLOT(setValue(int))); + connect(brushSizeSpinBox, SIGNAL(valueChanged(int)), brushSizeSlider, SLOT(setValue(int))); + + setLayout(layoutSliderSize); +} + +CSVRender::TextureBrushButton::TextureBrushButton (const QIcon & icon, const QString & text, QWidget * parent) + : QPushButton(icon, text, parent) +{ +} + +CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent) + : QFrame(parent, Qt::Popup), mWorldspaceWidget (worldspaceWidget) +{ + mBrushTextureLabel = "Brush: " + mBrushTexture; + selectedBrush = new QLabel(QString::fromUtf8(mBrushTextureLabel.c_str()), this); + + const std::string& iconPoint = ":scenetoolbar/brush-point"; + const std::string& iconSquare = ":scenetoolbar/brush-square"; + const std::string& iconCircle = ":scenetoolbar/brush-circle"; + const std::string& iconCustom = ":scenetoolbar/brush-custom"; + + TextureBrushButton *buttonPoint = new TextureBrushButton(QIcon (QPixmap (iconPoint.c_str())), "", this); + TextureBrushButton *buttonSquare = new TextureBrushButton(QIcon (QPixmap (iconSquare.c_str())), "", this); + TextureBrushButton *buttonCircle = new TextureBrushButton(QIcon (QPixmap (iconCircle.c_str())), "", this); + TextureBrushButton *buttonCustom = new TextureBrushButton(QIcon (QPixmap (iconCustom.c_str())), "", this); + + QVBoxLayout *layoutMain = new QVBoxLayout; + layoutMain->setSpacing(0); + + QHBoxLayout *layoutHorizontal = new QHBoxLayout; + layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0)); + layoutHorizontal->setSpacing(0); + + configureButtonInitialSettings(buttonPoint); + configureButtonInitialSettings(buttonSquare); + configureButtonInitialSettings(buttonCircle); + configureButtonInitialSettings(buttonCustom); + + QButtonGroup* brushButtonGroup = new QButtonGroup(this); + brushButtonGroup->addButton(buttonPoint); + brushButtonGroup->addButton(buttonSquare); + brushButtonGroup->addButton(buttonCircle); + brushButtonGroup->addButton(buttonCustom); + + brushButtonGroup->setExclusive(true); + + layoutHorizontal->addWidget(buttonPoint); + layoutHorizontal->addWidget(buttonSquare); + layoutHorizontal->addWidget(buttonCircle); + layoutHorizontal->addWidget(buttonCustom); + + horizontalGroupBox = new QGroupBox(tr("")); + horizontalGroupBox->setLayout(layoutHorizontal); + + BrushSizeControls* sizeSliders = new BrushSizeControls(tr(""), this); + + layoutMain->addWidget(horizontalGroupBox); + layoutMain->addWidget(sizeSliders); + layoutMain->addWidget(selectedBrush); + + setLayout(layoutMain); + + connect(parent, SIGNAL(passBrushTexture(std::string)), this, SLOT(getBrushTexture(std::string))); +} + +void CSVRender::TextureBrushWindow::configureButtonInitialSettings(TextureBrushButton *button) +{ + button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + button->setContentsMargins (QMargins (0, 0, 0, 0)); + button->setIconSize (QSize (48-6, 48-6)); + button->setFixedSize (48, 48); + button->setAcceptDrops(true); + button->setCheckable(true); +} + +void CSVRender::TextureBrushWindow::getBrushTexture(std::string brushTexture) +{ + mBrushTexture = brushTexture; + mBrushTextureLabel = "Brush:" + mBrushTexture; + selectedBrush->setText(QString::fromUtf8(mBrushTextureLabel.c_str())); +} + +CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) +: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent) +, textureBrushWindow(new TextureBrushWindow(worldspaceWidget, this)) +{ + connect(parent, SIGNAL(passEvent(QDragEnterEvent*)), this, SLOT(handleDragEnterEvent(QDragEnterEvent*))); + connect(parent, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); +} + +void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) +{ + EditMode::activate(toolbar); +} + +void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) +{ + EditMode::deactivate(toolbar); +} + +void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) +{ + QPoint position = QCursor::pos(); + textureBrushWindow->move (position); + textureBrushWindow->show(); +} + +void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitResult& hit) +{ +} + +bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) +{ + return false; +} + +bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos) +{ + return false; +} + +bool CSVRender::TerrainTextureMode::primarySelectStartDrag (const QPoint& pos) +{ + return false; +} + +bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos) +{ + return false; +} + +void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) { +} + +void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) { +} + +void CSVRender::TerrainTextureMode::dragAborted() { +} + +void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) {} + +void CSVRender::TerrainTextureMode::handleDragEnterEvent (QDragEnterEvent *event) { + event->accept(); +} + +void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { + const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); + + if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped + return; + + if (mime->holdsType (CSMWorld::UniversalId::Type_LandTexture)) + { + const std::vector ids = mime->getData(); + + for (const CSMWorld::UniversalId& uid : ids) + { + mBrushTexture = uid.getId(); + emit passBrushTexture(mBrushTexture); + } + } +} + +void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { +} diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp new file mode 100644 index 000000000..809816047 --- /dev/null +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -0,0 +1,108 @@ +#ifndef CSV_RENDER_TERRAINTEXTUREMODE_H +#define CSV_RENDER_TERRAINTEXTUREMODE_H + +#include "editmode.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CSVWidget +{ + class SceneToolMode; +} + +namespace CSVRender +{ + class BrushSizeControls : public QGroupBox + { + Q_OBJECT + + public: + BrushSizeControls(const QString &title, QWidget *parent); + + private: + QSlider *brushSizeSlider; + QSpinBox *brushSizeSpinBox; + QHBoxLayout *layoutSliderSize; + }; + + class TextureBrushButton : public QPushButton + { + Q_OBJECT + + public: + TextureBrushButton (const QIcon& icon, const QString& tooltip = "", + QWidget *parent = 0); + }; + + class TextureBrushWindow : public QFrame + { + Q_OBJECT + + public: + TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + void configureButtonInitialSettings(TextureBrushButton *button); + + private: + QLabel *selectedBrush; + QGroupBox *horizontalGroupBox; + int mButtonSize; + int mIconSize; + WorldspaceWidget *mWorldspaceWidget; + std::string mBrushTexture; + std::string mBrushTextureLabel; + + public slots: + void getBrushTexture(std::string brushTexture); + }; + + class TerrainTextureMode : public EditMode + { + Q_OBJECT + + public: + std::string mBrushTexture; + + TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr); + + void primarySelectPressed(const WorldspaceHitResult&); + void secondarySelectPressed(const WorldspaceHitResult&); + + void activate(CSVWidget::SceneToolbar*); + void deactivate(CSVWidget::SceneToolbar*); + + virtual bool primaryEditStartDrag (const QPoint& pos); + virtual bool secondaryEditStartDrag (const QPoint& pos); + virtual bool primarySelectStartDrag (const QPoint& pos); + virtual bool secondarySelectStartDrag (const QPoint& pos); + virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor); + virtual void dragCompleted(const QPoint& pos); + virtual void dragAborted(); + virtual void dragWheel (int diff, double speedFactor); + virtual void dragMoveEvent (QDragMoveEvent *event); + + private: + TextureBrushWindow *textureBrushWindow; + + signals: + + void passBrushTexture(std::string brushTexture); + + public slots: + void handleDragEnterEvent (QDragEnterEvent *event); + void handleDropEvent(QDropEvent *event); + }; +} + + +#endif diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index af53c86f0..f3b781080 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -577,6 +577,9 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); + if (mEditMode->getCurrentId() == "terrain-texture") mEditMode->setAcceptDrops(true); + else mEditMode->setAcceptDrops(false); + mDragging = false; mDragMode = InteractionType_None; } diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 7b2ff64db..80104515b 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -144,6 +144,15 @@ bool CSVWidget::SceneToolMode::event(QEvent* event) return SceneTool::event(event); } +void CSVWidget::SceneToolMode::dragEnterEvent (QDragEnterEvent *event) +{ + emit passEvent(event); +} +void CSVWidget::SceneToolMode::dropEvent (QDropEvent *event) +{ + emit passEvent(event); +} + void CSVWidget::SceneToolMode::selected() { std::map::iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 90f1dc419..84fcf59a7 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -47,6 +47,8 @@ namespace CSVWidget protected: bool event(QEvent* event); + void dragEnterEvent (QDragEnterEvent *event); + void dropEvent (QDropEvent *event); public: @@ -72,6 +74,8 @@ namespace CSVWidget signals: void modeChanged (const std::string& id); + void passEvent (QDragEnterEvent *event); + void passEvent (QDropEvent *event); private slots: diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index bfa256faf..0afd855f9 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -68,7 +68,7 @@ record-preview.png record-clone.png record-add.png - resources-icon.png + resources-icon.png resources-mesh.png resources-music.png resources-sound.png @@ -149,6 +149,10 @@ transform-scale.png selection-mode-cube.png selection-mode-cube-corner.png - selection-mode-cube-sphere.png + selection-mode-cube-sphere.png + brush-point.png + brush-square.png + brush-circle.png + brush-custom.png From 4649d1258c03dcc9f653e011e69859855409157b Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 15 Apr 2018 18:49:33 +0300 Subject: [PATCH 123/321] Direct data terrain editing --- .../opencs/view/render/terraintexturemode.cpp | 146 ++++++++++++++++-- .../opencs/view/render/terraintexturemode.hpp | 33 +++- 2 files changed, 166 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 346ba3136..3d3175b8d 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -25,10 +25,35 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/idtable.hpp" #include "pagedworldspacewidget.hpp" +#include "../../model/doc/document.hpp" +#include "../../model/world/land.hpp" +#include "../../model/world/landtexture.hpp" +//#include "../../model/world/universalid.hpp" +//#include "../../model/world/tablemimedata.hpp" +//#include "../../model/world/idtable.hpp" + +#include "../../model/world/columnbase.hpp" +#include "../../model/world/resourcetable.hpp" +#include "../../model/world/commandmacro.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/commands.hpp" + +//#include +//#include + +//#include +#include +//#include +//#include +//#include + + + CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) : QGroupBox(title, parent) { @@ -62,16 +87,6 @@ CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWi mBrushTextureLabel = "Brush: " + mBrushTexture; selectedBrush = new QLabel(QString::fromUtf8(mBrushTextureLabel.c_str()), this); - const std::string& iconPoint = ":scenetoolbar/brush-point"; - const std::string& iconSquare = ":scenetoolbar/brush-square"; - const std::string& iconCircle = ":scenetoolbar/brush-circle"; - const std::string& iconCustom = ":scenetoolbar/brush-custom"; - - TextureBrushButton *buttonPoint = new TextureBrushButton(QIcon (QPixmap (iconPoint.c_str())), "", this); - TextureBrushButton *buttonSquare = new TextureBrushButton(QIcon (QPixmap (iconSquare.c_str())), "", this); - TextureBrushButton *buttonCircle = new TextureBrushButton(QIcon (QPixmap (iconCircle.c_str())), "", this); - TextureBrushButton *buttonCustom = new TextureBrushButton(QIcon (QPixmap (iconCustom.c_str())), "", this); - QVBoxLayout *layoutMain = new QVBoxLayout; layoutMain->setSpacing(0); @@ -108,6 +123,13 @@ CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWi setLayout(layoutMain); + connect(buttonPoint, SIGNAL(clicked()), this, SLOT(setBrushShape())); + connect(buttonSquare, SIGNAL(clicked()), this, SLOT(setBrushShape())); + connect(buttonCircle, SIGNAL(clicked()), this, SLOT(setBrushShape())); + connect(buttonCustom, SIGNAL(clicked()), this, SLOT(setBrushShape())); + + connect(sizeSliders->brushSizeSlider, SIGNAL(valueChanged(int)), parent, SLOT(setBrushSize(int))); + connect(parent, SIGNAL(passBrushTexture(std::string)), this, SLOT(getBrushTexture(std::string))); } @@ -128,12 +150,29 @@ void CSVRender::TextureBrushWindow::getBrushTexture(std::string brushTexture) selectedBrush->setText(QString::fromUtf8(mBrushTextureLabel.c_str())); } +void CSVRender::TextureBrushWindow::setBrushSize(int brushSize) +{ + mBrushSize = brushSize; + emit passBrushSize(mBrushSize); +} + +void CSVRender::TextureBrushWindow::setBrushShape() +{ + if(buttonPoint->isChecked()) mBrushShape = 0; + if(buttonSquare->isChecked()) mBrushShape = 1; + if(buttonCircle->isChecked()) mBrushShape = 2; + if(buttonCustom->isChecked()) mBrushShape = 3; + emit passBrushShape(mBrushShape); +} + CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent) , textureBrushWindow(new TextureBrushWindow(worldspaceWidget, this)) { connect(parent, SIGNAL(passEvent(QDragEnterEvent*)), this, SLOT(handleDragEnterEvent(QDragEnterEvent*))); connect(parent, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); + connect(textureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); + connect(textureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); } void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) @@ -146,6 +185,83 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) EditMode::deactivate(toolbar); } +void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here +{ + cellId = getWorldspaceWidget().getCellId (hit.worldPos); + std::string hash = "#"; + std::string space = " "; + std::size_t hashlocation = cellId.find(hash); + std::size_t spacelocation = cellId.find(space); + std::string slicedX = cellId.substr (hashlocation+1, spacelocation-hashlocation); + std::string slicedY = cellId.substr (spacelocation+1); + CSMWorld::CellCoordinates mCoordinates(stoi(slicedX), stoi(slicedY)); + + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( +*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + /*CSMWorld::IdTable& ltexTable = dynamic_cast ( +*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));*/ + + int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + + int xInCell {(hit.worldPos.x() - (stoi(slicedX)* cellSize)) * landTextureSize / cellSize}; + int yInCell {(hit.worldPos.y() - (stoi(slicedY)* cellSize)) * landTextureSize / cellSize}; + + hashlocation = mBrushTexture.find(hash); + std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); + int brushInt = stoi(mBrushTexture.substr (hashlocation+1)); + + if (mBrushShape == 0) mNew[yInCell*landTextureSize+xInCell] = brushInt; + if (mBrushShape == 1) + { + for(int i=-mBrushSize/2;i= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15) + mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; + } + } + } + float distance = 0; + if (mBrushShape == 2) + { + float rf = mBrushSize/2; + int r = (mBrushSize/2)+1; + int r2 = r * r; + for(int i = -r; i < r; i++) + { + for(int j = -r; j < r; j++) + { + distance = std::round(sqrt(pow((xInCell+i)-xInCell, 2) + pow((yInCell+j)-yInCell, 2))); + if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15 && distance <= rf) + mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; + } + } + } + if (mBrushShape == 3) + { + // Not implemented + } + + // Modify data, this should be done via command system! + QVariant variant; + variant.setValue(mNew); + landTable.setData(landTable.getModelIndex(cellId, textureColumn), variant); + + // Reference + /*CSMWorld::ModifyLandTexturesCommand::ModifyLandTexturesCommand(IdTable& landTable, + IdTable& ltexTable, QUndoCommand* parent)*/ + + // Reference + /*CSMWorld::DeleteCommand* command = new CSMWorld::DeleteCommand(referencesTable, + static_cast(iter->get())->mObject->getReferenceId()); + + getWorldspaceWidget().getDocument().getUndoStack().push(command);*/ +} + void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) { QPoint position = QCursor::pos(); @@ -212,3 +328,13 @@ void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { } + +void CSVRender::TerrainTextureMode::setBrushSize(int brushSize) +{ + mBrushSize = brushSize; +} + +void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) +{ + mBrushShape = brushShape; +} diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 809816047..fff5b7dae 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -16,6 +16,9 @@ #include #include +#include "../../model/world/data.hpp" +#include "../../model/world/land.hpp" + namespace CSVWidget { class SceneToolMode; @@ -29,9 +32,9 @@ namespace CSVRender public: BrushSizeControls(const QString &title, QWidget *parent); + QSlider *brushSizeSlider; private: - QSlider *brushSizeSlider; QSpinBox *brushSizeSpinBox; QHBoxLayout *layoutSliderSize; }; @@ -53,10 +56,17 @@ namespace CSVRender TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); void configureButtonInitialSettings(TextureBrushButton *button); + TextureBrushButton *buttonPoint = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); + TextureBrushButton *buttonSquare = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); + TextureBrushButton *buttonCircle = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); + TextureBrushButton *buttonCustom = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); + private: QLabel *selectedBrush; QGroupBox *horizontalGroupBox; int mButtonSize; + int mBrushSize = 0; + int mBrushShape = 0; int mIconSize; WorldspaceWidget *mWorldspaceWidget; std::string mBrushTexture; @@ -64,6 +74,12 @@ namespace CSVRender public slots: void getBrushTexture(std::string brushTexture); + void setBrushShape(); + void setBrushSize(int brushSize); + + signals: + void passBrushSize (int brushSize); + void passBrushShape(int brushShape); }; class TerrainTextureMode : public EditMode @@ -71,10 +87,11 @@ namespace CSVRender Q_OBJECT public: - std::string mBrushTexture; TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr); + void primaryEditPressed (const WorldspaceHitResult& hit); + void primarySelectPressed(const WorldspaceHitResult&); void secondarySelectPressed(const WorldspaceHitResult&); @@ -93,14 +110,24 @@ namespace CSVRender private: TextureBrushWindow *textureBrushWindow; + std::string cellId; + std::string mBrushTexture = "#0"; + int mBrushSize = 0; + int mBrushShape = 0; - signals: + const int cellSize {ESM::Land::REAL_SIZE}; + const int landSize {ESM::Land::LAND_SIZE}; + const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; + signals: void passBrushTexture(std::string brushTexture); public slots: void handleDragEnterEvent (QDragEnterEvent *event); void handleDropEvent(QDropEvent *event); + void setBrushSize(int brushSize); + void setBrushShape(int brushShape); + }; } From 316d05bdc4bd10a776b44e1d0cd14776ca175ac4 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 15 Apr 2018 22:17:38 +0300 Subject: [PATCH 124/321] {} to () --- apps/opencs/view/render/terraintexturemode.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 3d3175b8d..76f018177 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -206,8 +206,8 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - int xInCell {(hit.worldPos.x() - (stoi(slicedX)* cellSize)) * landTextureSize / cellSize}; - int yInCell {(hit.worldPos.y() - (stoi(slicedY)* cellSize)) * landTextureSize / cellSize}; + int xInCell ((hit.worldPos.x() - (stoi(slicedX)* cellSize)) * landTextureSize / cellSize); + int yInCell ((hit.worldPos.y() - (stoi(slicedY)* cellSize)) * landTextureSize / cellSize); hashlocation = mBrushTexture.find(hash); std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); @@ -225,12 +225,11 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult } } } - float distance = 0; + float distance = 1; if (mBrushShape == 2) { float rf = mBrushSize/2; - int r = (mBrushSize/2)+1; - int r2 = r * r; + int r = (mBrushSize/2)+1; for(int i = -r; i < r; i++) { for(int j = -r; j < r; j++) From cc415526b0e2eec09f49564fea829ecea2ecb4c7 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 16 Apr 2018 11:42:55 +0300 Subject: [PATCH 125/321] fix texture index +1, better icons --- apps/opencs/view/render/terraintexturemode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 76f018177..1c331f1ec 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -211,7 +211,7 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult hashlocation = mBrushTexture.find(hash); std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); - int brushInt = stoi(mBrushTexture.substr (hashlocation+1)); + int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 if (mBrushShape == 0) mNew[yInCell*landTextureSize+xInCell] = brushInt; if (mBrushShape == 1) @@ -225,7 +225,7 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult } } } - float distance = 1; + float distance = 0; if (mBrushShape == 2) { float rf = mBrushSize/2; From a54a1b994013a03633e2e04b479452dc6c59cea3 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 17 Apr 2018 17:11:43 +0300 Subject: [PATCH 126/321] Command system and undo --- .../opencs/view/render/terraintexturemode.cpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 1c331f1ec..8933b5038 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -199,8 +199,8 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult CSMDoc::Document& document = getWorldspaceWidget().getDocument(); CSMWorld::IdTable& landTable = dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); - /*CSMWorld::IdTable& ltexTable = dynamic_cast ( -*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));*/ + CSMWorld::IdTable& ltexTable = dynamic_cast ( +*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value(); @@ -245,20 +245,16 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult // Not implemented } - // Modify data, this should be done via command system! QVariant variant; variant.setValue(mNew); - landTable.setData(landTable.getModelIndex(cellId, textureColumn), variant); - // Reference - /*CSMWorld::ModifyLandTexturesCommand::ModifyLandTexturesCommand(IdTable& landTable, - IdTable& ltexTable, QUndoCommand* parent)*/ + CSMWorld::CommandMacro macro (document.getUndoStack(), "Edit texture records"); + QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); - // Reference - /*CSMWorld::DeleteCommand* command = new CSMWorld::DeleteCommand(referencesTable, - static_cast(iter->get())->mObject->getReferenceId()); - - getWorldspaceWidget().getDocument().getUndoStack().push(command);*/ + CSMWorld::TouchLandCommand* ltexTouch = new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId); + CSMWorld::ModifyCommand* ltexModify = new CSMWorld::ModifyCommand(landTable, index, variant); + macro.push (ltexTouch); + macro.push (ltexModify); } void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) From 3327d6f7c47639fb951e3dc98b6cc9bec830bfe5 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 17 Apr 2018 20:48:58 +0300 Subject: [PATCH 127/321] Drag terrain painting, code cleanup --- .../opencs/view/render/terraintexturemode.cpp | 177 +++++++++--------- .../opencs/view/render/terraintexturemode.hpp | 4 +- 2 files changed, 88 insertions(+), 93 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 8933b5038..79973b806 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -1,7 +1,3 @@ -// To-do: Getting Texture Id and Texture Filenames to base class Terraintexturemode -// To-do: Better data handling options for mBrushTexture -// To-do: loading texture bitmaps from virtual file system (vfs) for texture overlay icon - #include "terraintexturemode.hpp" #include "editmode.hpp" @@ -23,35 +19,25 @@ #include "../widget/modebutton.hpp" #include "../widget/scenetoolbar.hpp" -#include "../../model/world/universalid.hpp" -#include "../../model/world/tablemimedata.hpp" -#include "../../model/world/idtable.hpp" - #include "pagedworldspacewidget.hpp" - +#include "mask.hpp" +#include "object.hpp" // Something small needed regarding pointers from here () +#include "worldspacewidget.hpp" #include "../../model/doc/document.hpp" -#include "../../model/world/land.hpp" -#include "../../model/world/landtexture.hpp" -//#include "../../model/world/universalid.hpp" -//#include "../../model/world/tablemimedata.hpp" -//#include "../../model/world/idtable.hpp" - #include "../../model/world/columnbase.hpp" -#include "../../model/world/resourcetable.hpp" #include "../../model/world/commandmacro.hpp" -#include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/land.hpp" +#include "../../model/world/landtexture.hpp" +#include "../../model/world/resourcetable.hpp" +#include "../../model/world/tablemimedata.hpp" +#include "../../model/world/universalid.hpp" -//#include -//#include -//#include #include -//#include -//#include -//#include - CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) @@ -187,74 +173,7 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here { - cellId = getWorldspaceWidget().getCellId (hit.worldPos); - std::string hash = "#"; - std::string space = " "; - std::size_t hashlocation = cellId.find(hash); - std::size_t spacelocation = cellId.find(space); - std::string slicedX = cellId.substr (hashlocation+1, spacelocation-hashlocation); - std::string slicedY = cellId.substr (spacelocation+1); - CSMWorld::CellCoordinates mCoordinates(stoi(slicedX), stoi(slicedY)); - - CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - CSMWorld::IdTable& landTable = dynamic_cast ( -*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); - CSMWorld::IdTable& ltexTable = dynamic_cast ( -*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); - - int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - - int xInCell ((hit.worldPos.x() - (stoi(slicedX)* cellSize)) * landTextureSize / cellSize); - int yInCell ((hit.worldPos.y() - (stoi(slicedY)* cellSize)) * landTextureSize / cellSize); - - hashlocation = mBrushTexture.find(hash); - std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); - int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 - - if (mBrushShape == 0) mNew[yInCell*landTextureSize+xInCell] = brushInt; - if (mBrushShape == 1) - { - for(int i=-mBrushSize/2;i= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15) - mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; - } - } - } - float distance = 0; - if (mBrushShape == 2) - { - float rf = mBrushSize/2; - int r = (mBrushSize/2)+1; - for(int i = -r; i < r; i++) - { - for(int j = -r; j < r; j++) - { - distance = std::round(sqrt(pow((xInCell+i)-xInCell, 2) + pow((yInCell+j)-yInCell, 2))); - if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15 && distance <= rf) - mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; - } - } - } - if (mBrushShape == 3) - { - // Not implemented - } - - QVariant variant; - variant.setValue(mNew); - - CSMWorld::CommandMacro macro (document.getUndoStack(), "Edit texture records"); - QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); - - CSMWorld::TouchLandCommand* ltexTouch = new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId); - CSMWorld::ModifyCommand* ltexModify = new CSMWorld::ModifyCommand(landTable, index, variant); - macro.push (ltexTouch); - macro.push (ltexModify); + editTerrainTextureGrid(hit); } void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) @@ -270,6 +189,8 @@ void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitRe bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) { + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + editTerrainTextureGrid(hit); return false; } @@ -321,6 +242,78 @@ void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { } } +void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit) +{ + mCellId = getWorldspaceWidget().getCellId (hit.worldPos); + std::string hash = "#"; + std::string space = " "; + std::size_t hashlocation = mCellId.find(hash); + std::size_t spacelocation = mCellId.find(space); + std::string slicedX = mCellId.substr (hashlocation+1, spacelocation-hashlocation); + std::string slicedY = mCellId.substr (spacelocation+1); + CSMWorld::CellCoordinates mCoordinates(stoi(slicedX), stoi(slicedY)); + + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + + int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + + int xInCell ((hit.worldPos.x() - (stoi(slicedX)* cellSize)) * landTextureSize / cellSize); + int yInCell ((hit.worldPos.y() - (stoi(slicedY)* cellSize)) * landTextureSize / cellSize); + + hashlocation = mBrushTexture.find(hash); + std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); + int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 + + if (mBrushShape == 0) mNew[yInCell*landTextureSize+xInCell] = brushInt; + if (mBrushShape == 1) + { + for(int i=-mBrushSize/2;i= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15) + mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; + } + } + } + float distance = 0; + if (mBrushShape == 2) + { + float rf = mBrushSize/2; + int r = (mBrushSize/2)+1; + for(int i = -r; i < r; i++) + { + for(int j = -r; j < r; j++) + { + distance = std::round(sqrt(pow((xInCell+i)-xInCell, 2) + pow((yInCell+j)-yInCell, 2))); + if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15 && distance <= rf) + mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; + } + } + } + if (mBrushShape == 3) + { + // Not implemented + } + + QVariant changedLand; + changedLand.setValue(mNew); + + CSMWorld::CommandMacro macro (document.getUndoStack(), "Edit texture records"); + QModelIndex index(landTable.getModelIndex (mCellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); + + CSMWorld::TouchLandCommand* ltexTouch = new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId); + CSMWorld::ModifyCommand* ltexModify = new CSMWorld::ModifyCommand(landTable, index, changedLand); + macro.push (ltexTouch); + macro.push (ltexModify); +} + void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { } diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index fff5b7dae..6b6eb6c63 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -108,9 +108,11 @@ namespace CSVRender virtual void dragWheel (int diff, double speedFactor); virtual void dragMoveEvent (QDragMoveEvent *event); + void editTerrainTextureGrid (const WorldspaceHitResult& hit); + private: TextureBrushWindow *textureBrushWindow; - std::string cellId; + std::string mCellId; std::string mBrushTexture = "#0"; int mBrushSize = 0; int mBrushShape = 0; From 1c113eca9cec97c691f3be36307e3fd2c53af018 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 17 Apr 2018 21:34:40 +0300 Subject: [PATCH 128/321] 15 to landTextureSize-1 --- apps/opencs/view/render/terraintexturemode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 79973b806..77d850861 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -277,7 +277,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { for(int j=-mBrushSize/2;j= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15) + if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= landTextureSize - 1 && yInCell+j <= landTextureSize - 1) mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; } } @@ -292,7 +292,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe for(int j = -r; j < r; j++) { distance = std::round(sqrt(pow((xInCell+i)-xInCell, 2) + pow((yInCell+j)-yInCell, 2))); - if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= 15 && yInCell+j <= 15 && distance <= rf) + if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= landTextureSize - 1 && yInCell+j <= landTextureSize - 1 && distance <= rf) mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; } } From 1ca2710a2ae9f78fdcaa56c2e63a4203f4cf3d0c Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 18 Apr 2018 13:12:11 +0300 Subject: [PATCH 129/321] Formatting, fixes --- .../opencs/view/render/terraintexturemode.cpp | 59 ++++++++++--------- .../opencs/view/render/terraintexturemode.hpp | 14 ++--- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 77d850861..0ce0bcd9b 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -1,7 +1,7 @@ #include "terraintexturemode.hpp" -#include "editmode.hpp" #include +#include #include #include @@ -16,14 +16,11 @@ #include #include +#include + #include "../widget/modebutton.hpp" #include "../widget/scenetoolbar.hpp" -#include "pagedworldspacewidget.hpp" -#include "mask.hpp" -#include "object.hpp" // Something small needed regarding pointers from here () -#include "worldspacewidget.hpp" - #include "../../model/doc/document.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/commandmacro.hpp" @@ -36,8 +33,11 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" - -#include +#include "editmode.hpp" +#include "pagedworldspacewidget.hpp" +#include "mask.hpp" +#include "object.hpp" // Something small needed regarding pointers from here () +#include "worldspacewidget.hpp" CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) @@ -68,7 +68,10 @@ CSVRender::TextureBrushButton::TextureBrushButton (const QIcon & icon, const QSt } CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent) - : QFrame(parent, Qt::Popup), mWorldspaceWidget (worldspaceWidget) + : QFrame(parent, Qt::Popup), + mWorldspaceWidget (worldspaceWidget), + mBrushSize(0), + mBrushShape(0) { mBrushTextureLabel = "Brush: " + mBrushTexture; selectedBrush = new QLabel(QString::fromUtf8(mBrushTextureLabel.c_str()), this); @@ -116,7 +119,7 @@ CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWi connect(sizeSliders->brushSizeSlider, SIGNAL(valueChanged(int)), parent, SLOT(setBrushSize(int))); - connect(parent, SIGNAL(passBrushTexture(std::string)), this, SLOT(getBrushTexture(std::string))); + connect(parent, SIGNAL(passBrushTexture(std::string)), this, SLOT(setBrushTexture(std::string))); } void CSVRender::TextureBrushWindow::configureButtonInitialSettings(TextureBrushButton *button) @@ -129,7 +132,7 @@ void CSVRender::TextureBrushWindow::configureButtonInitialSettings(TextureBrushB button->setCheckable(true); } -void CSVRender::TextureBrushWindow::getBrushTexture(std::string brushTexture) +void CSVRender::TextureBrushWindow::setBrushTexture(std::string brushTexture) { mBrushTexture = brushTexture; mBrushTextureLabel = "Brush:" + mBrushTexture; @@ -152,8 +155,11 @@ void CSVRender::TextureBrushWindow::setBrushShape() } CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) -: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent) -, textureBrushWindow(new TextureBrushWindow(worldspaceWidget, this)) +: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent), + textureBrushWindow(new TextureBrushWindow(worldspaceWidget, this)), + mBrushTexture("#0"), + mBrushSize(0), + mBrushShape(0) { connect(parent, SIGNAL(passEvent(QDragEnterEvent*)), this, SLOT(handleDragEnterEvent(QDragEnterEvent*))); connect(parent, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); @@ -245,13 +251,12 @@ void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit) { mCellId = getWorldspaceWidget().getCellId (hit.worldPos); - std::string hash = "#"; - std::string space = " "; - std::size_t hashlocation = mCellId.find(hash); - std::size_t spacelocation = mCellId.find(space); - std::string slicedX = mCellId.substr (hashlocation+1, spacelocation-hashlocation); - std::string slicedY = mCellId.substr (spacelocation+1); - CSMWorld::CellCoordinates mCoordinates(stoi(slicedX), stoi(slicedY)); + + std::istringstream streamCoord (mCellId); + char ignore; + int cellX = 0; + int cellY = 0; + streamCoord >> ignore >> cellX >> cellY; CSMDoc::Document& document = getWorldspaceWidget().getDocument(); CSMWorld::IdTable& landTable = dynamic_cast ( @@ -263,10 +268,10 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - int xInCell ((hit.worldPos.x() - (stoi(slicedX)* cellSize)) * landTextureSize / cellSize); - int yInCell ((hit.worldPos.y() - (stoi(slicedY)* cellSize)) * landTextureSize / cellSize); + int xInCell ((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize); + int yInCell ((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize); - hashlocation = mBrushTexture.find(hash); + std::size_t hashlocation = mBrushTexture.find("#"); std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 @@ -307,11 +312,9 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe CSMWorld::CommandMacro macro (document.getUndoStack(), "Edit texture records"); QModelIndex index(landTable.getModelIndex (mCellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); - - CSMWorld::TouchLandCommand* ltexTouch = new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId); - CSMWorld::ModifyCommand* ltexModify = new CSMWorld::ModifyCommand(landTable, index, changedLand); - macro.push (ltexTouch); - macro.push (ltexModify); + + macro.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); + macro.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); } void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 6b6eb6c63..7e991a8f0 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -64,16 +64,14 @@ namespace CSVRender private: QLabel *selectedBrush; QGroupBox *horizontalGroupBox; - int mButtonSize; - int mBrushSize = 0; - int mBrushShape = 0; - int mIconSize; WorldspaceWidget *mWorldspaceWidget; + int mBrushSize; + int mBrushShape; std::string mBrushTexture; std::string mBrushTextureLabel; public slots: - void getBrushTexture(std::string brushTexture); + void setBrushTexture(std::string brushTexture); void setBrushShape(); void setBrushSize(int brushSize); @@ -113,9 +111,9 @@ namespace CSVRender private: TextureBrushWindow *textureBrushWindow; std::string mCellId; - std::string mBrushTexture = "#0"; - int mBrushSize = 0; - int mBrushShape = 0; + std::string mBrushTexture; + int mBrushSize; + int mBrushShape; const int cellSize {ESM::Land::REAL_SIZE}; const int landSize {ESM::Land::LAND_SIZE}; From 9f742d5b1fe68a340db13b128c393645d18df542 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 19 Apr 2018 18:00:47 +0300 Subject: [PATCH 130/321] Brush affects adjancent cells --- .../opencs/view/render/terraintexturemode.cpp | 147 ++++++++++++++---- .../opencs/view/render/terraintexturemode.hpp | 7 + 2 files changed, 127 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 0ce0bcd9b..baaae55be 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -252,11 +252,16 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { mCellId = getWorldspaceWidget().getCellId (hit.worldPos); - std::istringstream streamCoord (mCellId); - char ignore; - int cellX = 0; - int cellY = 0; - streamCoord >> ignore >> cellX >> cellY; + std::pair cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (mCellId); + + int cellX = cellCoordinates_pair.first.getX(); + int cellY = cellCoordinates_pair.first.getY(); + + // The coordinates of hit in mCellId + int xHitInCell ((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize); + int yHitInCell ((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize); + + std::string iteratedCellId; CSMDoc::Document& document = getWorldspaceWidget().getDocument(); CSMWorld::IdTable& landTable = dynamic_cast ( @@ -265,40 +270,123 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - - int xInCell ((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize); - int yInCell ((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize); std::size_t hashlocation = mBrushTexture.find("#"); std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 - if (mBrushShape == 0) mNew[yInCell*landTextureSize+xInCell] = brushInt; + float rf = mBrushSize/2; + int r = (mBrushSize/2)+1; + float distance = 0; + + if (mBrushShape == 0) + { + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt; + pushEditToCommand(mNew, document, landTable, ltexTable, mCellId); + } + if (mBrushShape == 1) { - for(int i=-mBrushSize/2;i landTextureSize - 1) lowerrightCellX++; + if (yHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellY++; + + for(int i_cell = upperLeftCellX; i_cell <= lowerrightCellX; i_cell++) { - for(int j=-mBrushSize/2;j= 0 && yInCell+j >= 0 && xInCell+i <= landTextureSize - 1 && yInCell+j <= landTextureSize - 1) - mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; + iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + for(int i = 0; i < landTextureSize; i++) + { + for(int j = 0; j < landTextureSize; j++) + { + + if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + { + mNew[j*landTextureSize+i] = brushInt; + } + else + { + int distanceX(0); + int distanceY(0); + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize + i - 1; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize + j - 1; + if (i_cell == cellX) distanceX = abs(i-xHitInCell); + if (j_cell == cellY) distanceY = abs(j-yHitInCell); + if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt; + } + } + } + pushEditToCommand(mNew, document, landTable, ltexTable, iteratedCellId); } } } - float distance = 0; + if (mBrushShape == 2) { - float rf = mBrushSize/2; - int r = (mBrushSize/2)+1; - for(int i = -r; i < r; i++) + int upperLeftCellX = cellX - std::floor(r / landTextureSize); + int upperLeftCellY = cellY - std::floor(r / landTextureSize); + if (xHitInCell - (r % landTextureSize) < 0) upperLeftCellX--; + if (yHitInCell - (r % landTextureSize) < 0) upperLeftCellY--; + + int lowerrightCellX = cellX + std::floor(r / landTextureSize); + int lowerrightCellY = cellY + std::floor(r / landTextureSize); + if (xHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellX++; + if (yHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellY++; + + for(int i_cell = upperLeftCellX; i_cell <= lowerrightCellX; i_cell++) { - for(int j = -r; j < r; j++) + for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { - distance = std::round(sqrt(pow((xInCell+i)-xInCell, 2) + pow((yInCell+j)-yInCell, 2))); - if (xInCell+i >= 0 && yInCell+j >= 0 && xInCell+i <= landTextureSize - 1 && yInCell+j <= landTextureSize - 1 && distance <= rf) - mNew[(yInCell+j)*landTextureSize+(xInCell+i)] = brushInt; + iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + for(int i = 0; i < landTextureSize; i++) + { + for(int j = 0; j < landTextureSize; j++) + { + + if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + { + int distanceX(0); + int distanceY(0); + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize + i - 1; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize + j - 1; + if (i_cell == cellX) distanceX = abs(i-xHitInCell); + if (j_cell == cellY) distanceY = abs(j-yHitInCell); + distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + } + else + { + int distanceX(0); + int distanceY(0); + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize + i - 1; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize + j - 1; + if (i_cell == cellX) distanceX = abs(i-xHitInCell); + if (j_cell == cellY) distanceY = abs(j-yHitInCell); + distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + } + } + } + pushEditToCommand(mNew, document, landTable, ltexTable, iteratedCellId); } } } @@ -307,13 +395,18 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe // Not implemented } +} + +void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, + CSMWorld::IdTable& landTable, CSMWorld::IdTable& ltexTable, std::string cellId) +{ QVariant changedLand; - changedLand.setValue(mNew); + changedLand.setValue(newLandGrid); CSMWorld::CommandMacro macro (document.getUndoStack(), "Edit texture records"); - QModelIndex index(landTable.getModelIndex (mCellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); - - macro.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); + QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); + + macro.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); macro.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); } diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 7e991a8f0..48b9aeb59 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -19,6 +19,11 @@ #include "../../model/world/data.hpp" #include "../../model/world/land.hpp" +#include "../../model/doc/document.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/landtexture.hpp" + namespace CSVWidget { class SceneToolMode; @@ -107,6 +112,8 @@ namespace CSVRender virtual void dragMoveEvent (QDragMoveEvent *event); void editTerrainTextureGrid (const WorldspaceHitResult& hit); + void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, + CSMWorld::IdTable& landTable, CSMWorld::IdTable& ltexTable, std::string cellId); private: TextureBrushWindow *textureBrushWindow; From cf7a0f715ea5f20ee5b3892fbf5ac0c888167566 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 21 Apr 2018 13:46:06 +0300 Subject: [PATCH 131/321] Command macro for complete drag-editing operations. --- .../opencs/view/render/terraintexturemode.cpp | 38 +++++++++++++------ .../opencs/view/render/terraintexturemode.hpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 6 +++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index baaae55be..f7f3b0631 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -196,8 +196,21 @@ void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitRe bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) { WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + + mCellId = getWorldspaceWidget().getCellId (hit.worldPos); + + QUndoStack& undoStack = document.getUndoStack(); + undoStack.beginMacro ("Edit texture records"); + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); editTerrainTextureGrid(hit); - return false; + + return true; } bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos) @@ -215,10 +228,16 @@ bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos) return false; } -void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) { +void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) +{ + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + editTerrainTextureGrid(hit); } void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) { + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + QUndoStack& undoStack = document.getUndoStack(); + undoStack.endMacro(); } void CSVRender::TerrainTextureMode::dragAborted() { @@ -266,8 +285,6 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe CSMDoc::Document& document = getWorldspaceWidget().getDocument(); CSMWorld::IdTable& landTable = dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); - CSMWorld::IdTable& ltexTable = dynamic_cast ( - *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); @@ -284,7 +301,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType mNew(mPointer); mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt; - pushEditToCommand(mNew, document, landTable, ltexTable, mCellId); + pushEditToCommand(mNew, document, landTable, mCellId); } if (mBrushShape == 1) @@ -329,7 +346,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } } - pushEditToCommand(mNew, document, landTable, ltexTable, iteratedCellId); + pushEditToCommand(mNew, document, landTable, iteratedCellId); } } } @@ -386,7 +403,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } } - pushEditToCommand(mNew, document, landTable, ltexTable, iteratedCellId); + pushEditToCommand(mNew, document, landTable, iteratedCellId); } } } @@ -398,16 +415,15 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, - CSMWorld::IdTable& landTable, CSMWorld::IdTable& ltexTable, std::string cellId) + CSMWorld::IdTable& landTable, std::string cellId) { QVariant changedLand; changedLand.setValue(newLandGrid); - CSMWorld::CommandMacro macro (document.getUndoStack(), "Edit texture records"); QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); - macro.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); - macro.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); + QUndoStack& undoStack = document.getUndoStack(); + undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); } void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 48b9aeb59..d8d27d045 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -113,7 +113,7 @@ namespace CSVRender void editTerrainTextureGrid (const WorldspaceHitResult& hit); void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, - CSMWorld::IdTable& landTable, CSMWorld::IdTable& ltexTable, std::string cellId); + CSMWorld::IdTable& landTable, std::string cellId); private: TextureBrushWindow *textureBrushWindow; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f3b781080..c8ba16666 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -651,6 +651,12 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mDragX = event->posF().x(); mDragY = height() - event->posF().y(); #endif + + if (mDragMode == InteractionType_PrimaryEdit) + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + editMode.drag (event->pos(), mDragX, mDragY, mDragFactor); // note: terraintexturemode only uses pos + } } } else From 5f3c8b2b9937c2400f4a06a879fb13546fdead80 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 21 Apr 2018 13:54:06 +0300 Subject: [PATCH 132/321] c_str -> fromStdString, remove TextureBrushButton class --- .../opencs/view/render/terraintexturemode.cpp | 11 +++-------- .../opencs/view/render/terraintexturemode.hpp | 19 +++++-------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index f7f3b0631..40afd9b35 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -62,11 +62,6 @@ CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p setLayout(layoutSliderSize); } -CSVRender::TextureBrushButton::TextureBrushButton (const QIcon & icon, const QString & text, QWidget * parent) - : QPushButton(icon, text, parent) -{ -} - CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent) : QFrame(parent, Qt::Popup), mWorldspaceWidget (worldspaceWidget), @@ -74,7 +69,7 @@ CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWi mBrushShape(0) { mBrushTextureLabel = "Brush: " + mBrushTexture; - selectedBrush = new QLabel(QString::fromUtf8(mBrushTextureLabel.c_str()), this); + selectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel), this); QVBoxLayout *layoutMain = new QVBoxLayout; layoutMain->setSpacing(0); @@ -122,7 +117,7 @@ CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWi connect(parent, SIGNAL(passBrushTexture(std::string)), this, SLOT(setBrushTexture(std::string))); } -void CSVRender::TextureBrushWindow::configureButtonInitialSettings(TextureBrushButton *button) +void CSVRender::TextureBrushWindow::configureButtonInitialSettings(QPushButton *button) { button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setContentsMargins (QMargins (0, 0, 0, 0)); @@ -136,7 +131,7 @@ void CSVRender::TextureBrushWindow::setBrushTexture(std::string brushTexture) { mBrushTexture = brushTexture; mBrushTextureLabel = "Brush:" + mBrushTexture; - selectedBrush->setText(QString::fromUtf8(mBrushTextureLabel.c_str())); + selectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); } void CSVRender::TextureBrushWindow::setBrushSize(int brushSize) diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index d8d27d045..4f20ccfc1 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -44,27 +44,18 @@ namespace CSVRender QHBoxLayout *layoutSliderSize; }; - class TextureBrushButton : public QPushButton - { - Q_OBJECT - - public: - TextureBrushButton (const QIcon& icon, const QString& tooltip = "", - QWidget *parent = 0); - }; - class TextureBrushWindow : public QFrame { Q_OBJECT public: TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); - void configureButtonInitialSettings(TextureBrushButton *button); + void configureButtonInitialSettings(QPushButton *button); - TextureBrushButton *buttonPoint = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); - TextureBrushButton *buttonSquare = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); - TextureBrushButton *buttonCircle = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); - TextureBrushButton *buttonCustom = new TextureBrushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); + QPushButton *buttonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); + QPushButton *buttonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); + QPushButton *buttonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); + QPushButton *buttonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); private: QLabel *selectedBrush; From 20d1d8ac8912ec65a9f12b93d090fa06acb1a90c Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 23 Apr 2018 11:21:59 +0300 Subject: [PATCH 133/321] Fixed brush calculations, implement undostack macro when clicked. --- .../opencs/view/render/terraintexturemode.cpp | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 40afd9b35..00bbfa110 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -174,7 +174,19 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here { + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + + mCellId = getWorldspaceWidget().getCellId (hit.worldPos); + + QUndoStack& undoStack = document.getUndoStack(); + undoStack.beginMacro ("Edit texture records"); + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); editTerrainTextureGrid(hit); + undoStack.endMacro(); } void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) @@ -331,10 +343,10 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { int distanceX(0); int distanceY(0); - if (i_cell < cellX) distanceX = xHitInCell + landTextureSize - i; - if (j_cell < cellY) distanceY = yHitInCell + landTextureSize - j; - if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize + i - 1; - if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize + j - 1; + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt; @@ -374,10 +386,10 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { int distanceX(0); int distanceY(0); - if (i_cell < cellX) distanceX = xHitInCell + landTextureSize - i; - if (j_cell < cellY) distanceY = yHitInCell + landTextureSize - j; - if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize + i - 1; - if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize + j - 1; + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize* abs(i_cell-cellX) + i; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); @@ -387,10 +399,10 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { int distanceX(0); int distanceY(0); - if (i_cell < cellX) distanceX = xHitInCell + landTextureSize - i; - if (j_cell < cellY) distanceY = yHitInCell + landTextureSize - j; - if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize + i - 1; - if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize + j - 1; + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); From 71398895669beeb3262238b46a647a946669c1aa Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 28 Apr 2018 16:05:15 +0300 Subject: [PATCH 134/321] Brush button window opens at modebutton, slider 1-50, doxygen comments --- .../opencs/view/render/terraintexturemode.cpp | 21 +++++++++++++++---- .../opencs/view/render/terraintexturemode.hpp | 19 +++++++++++++++++ apps/opencs/view/widget/scenetoolmode.cpp | 10 +++++++++ apps/opencs/view/widget/scenetoolmode.hpp | 3 +++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 00bbfa110..91672bbef 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -46,10 +46,11 @@ CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p brushSizeSlider = new QSlider(Qt::Horizontal); brushSizeSlider->setTickPosition(QSlider::TicksBothSides); brushSizeSlider->setTickInterval(10); + brushSizeSlider->setRange(1, 50); brushSizeSlider->setSingleStep(1); brushSizeSpinBox = new QSpinBox; - brushSizeSpinBox->setRange(1, 100); + brushSizeSpinBox->setRange(1, 50); brushSizeSpinBox->setSingleStep(1); layoutSliderSize = new QHBoxLayout; @@ -158,6 +159,7 @@ CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceW { connect(parent, SIGNAL(passEvent(QDragEnterEvent*)), this, SLOT(handleDragEnterEvent(QDragEnterEvent*))); connect(parent, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); + connect(parent, SIGNAL(passEvent(QMouseEvent*)), this, SLOT(handleMouseEvent(QMouseEvent*))); connect(textureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); connect(textureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); } @@ -191,9 +193,6 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) { - QPoint position = QCursor::pos(); - textureBrushWindow->move (position); - textureBrushWindow->show(); } void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitResult& hit) @@ -274,6 +273,20 @@ void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { } } +void CSVRender::TerrainTextureMode::handleMouseEvent (QMouseEvent *event) +{ + if (event->button()==Qt::MidButton) + { + QPoint position = QCursor::pos(); + textureBrushWindow->move (position); + textureBrushWindow->show(); + } + if (event->button()==Qt::LeftButton) PushButton::mouseReleaseEvent (event); +} + +void CSVRender::TerrainTextureMode::handlePrimarySelectOnModeButton () { +} + void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit) { mCellId = getWorldspaceWidget().getCellId (hit.worldPos); diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 4f20ccfc1..60d6fd87b 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -31,6 +31,8 @@ namespace CSVWidget namespace CSVRender { + + /// \brief Layout-box for some brush button settings class BrushSizeControls : public QGroupBox { Q_OBJECT @@ -44,6 +46,7 @@ namespace CSVRender QHBoxLayout *layoutSliderSize; }; + /// \brief Brush settings window class TextureBrushWindow : public QFrame { Q_OBJECT @@ -82,27 +85,41 @@ namespace CSVRender public: + /// \brief Editmode for terrain texture grid TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr); + /// \brief Create single command for one-click texture editing void primaryEditPressed (const WorldspaceHitResult& hit); + /// \brief Open brush settings window void primarySelectPressed(const WorldspaceHitResult&); + void secondarySelectPressed(const WorldspaceHitResult&); void activate(CSVWidget::SceneToolbar*); void deactivate(CSVWidget::SceneToolbar*); + /// \brief Start texture editing command macro virtual bool primaryEditStartDrag (const QPoint& pos); + virtual bool secondaryEditStartDrag (const QPoint& pos); virtual bool primarySelectStartDrag (const QPoint& pos); virtual bool secondarySelectStartDrag (const QPoint& pos); + + /// \brief Handle texture edit behavior during dragging virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor); + + /// \brief End texture editing command macro virtual void dragCompleted(const QPoint& pos); + virtual void dragAborted(); virtual void dragWheel (int diff, double speedFactor); virtual void dragMoveEvent (QDragMoveEvent *event); + /// \brief Handle brush mechanics, maths regarding worldspace hit etc. void editTerrainTextureGrid (const WorldspaceHitResult& hit); + + /// \brief Push texture edits to command macro void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, CSMWorld::IdTable& landTable, std::string cellId); @@ -123,6 +140,8 @@ namespace CSVRender public slots: void handleDragEnterEvent (QDragEnterEvent *event); void handleDropEvent(QDropEvent *event); + void handleMouseEvent (QMouseEvent *event); + void handlePrimarySelectOnModeButton(); void setBrushSize(int brushSize); void setBrushShape(int brushShape); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 80104515b..94435016f 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -134,6 +134,16 @@ void CSVWidget::SceneToolMode::setButton (const std::string& id) } } + +void CSVWidget::SceneToolMode::mouseReleaseEvent (QMouseEvent *event) +{ + if (event->button()==Qt::MidButton && getCurrentId() == "terrain-texture") emit passEvent(event); + if (getType()==Type_TopAction && event->button()==Qt::RightButton) + showPanel (parentWidget()->mapToGlobal (pos())); + else + PushButton::mouseReleaseEvent (event); +} + bool CSVWidget::SceneToolMode::event(QEvent* event) { if (event->type() == QEvent::ToolTip) diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 84fcf59a7..7d0c8f70e 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -44,6 +44,8 @@ namespace CSVWidget void setButton (std::map::iterator iter); + void mouseReleaseEvent (QMouseEvent *event); + protected: bool event(QEvent* event); @@ -74,6 +76,7 @@ namespace CSVWidget signals: void modeChanged (const std::string& id); + void passEvent (QMouseEvent *event); void passEvent (QDragEnterEvent *event); void passEvent (QDropEvent *event); From e8a9bff85c0bd6a3cb6310bdb31b3674497f8ebb Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 29 Apr 2018 12:26:18 +0300 Subject: [PATCH 135/321] Drop textures to landtextures from assets (try-method) --- .../opencs/view/render/terraintexturemode.cpp | 52 +++++++++++++++++++ .../opencs/view/render/terraintexturemode.hpp | 3 ++ 2 files changed, 55 insertions(+) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 91672bbef..5e1b6afb8 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -271,6 +271,16 @@ void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { emit passBrushTexture(mBrushTexture); } } + if (mime->holdsType (CSMWorld::UniversalId::Type_Texture)) + { + const std::vector ids = mime->getData(); + + for (const CSMWorld::UniversalId& uid : ids) + { + std::string textureFileName = uid.toString(); + createTexture(textureFileName); + } + } } void CSVRender::TerrainTextureMode::handleMouseEvent (QMouseEvent *event) @@ -446,6 +456,48 @@ void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColu undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); } +void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) +{ + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + + QUndoStack& undoStack = document.getUndoStack(); + + std::string newId; + + int counter=0; + bool freeIndexFound = false; + do { + const size_t maxCounter = std::numeric_limits::max() - 1; + try + { + newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter); + if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter; + } catch (const std::exception& e) + { + newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter); + freeIndexFound = true; + } + } while (freeIndexFound == false); + + std::size_t idlocation = textureFileName.find("Texture: "); + textureFileName = textureFileName.substr (idlocation + 9); + + QVariant textureNameVariant; + + QVariant textureFileNameVariant; + textureFileNameVariant.setValue(QString::fromStdString(textureFileName)); + + undoStack.beginMacro ("Add land texture record"); + + undoStack.push (new CSMWorld::CreateCommand (ltexTable, newId)); + QModelIndex index(ltexTable.getModelIndex (newId, ltexTable.findColumnIndex (CSMWorld::Columns::ColumnId_Texture))); + undoStack.push (new CSMWorld::ModifyCommand(ltexTable, index, textureFileNameVariant)); + undoStack.endMacro(); +} + void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { } diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 60d6fd87b..f6fde3544 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -123,6 +123,9 @@ namespace CSVRender void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, CSMWorld::IdTable& landTable, std::string cellId); + /// \brief Create new land texture record from texture asset + void createTexture(std::string textureFileName); + private: TextureBrushWindow *textureBrushWindow; std::string mCellId; From 24977fcc0f9d7358f07be1d6de6ec3ffd8903ceb Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 29 Apr 2018 13:33:00 +0300 Subject: [PATCH 136/321] improve hit calculation accuracy for texture editing --- apps/opencs/view/render/terraintexturemode.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 5e1b6afb8..97856c20c 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -307,8 +307,20 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe int cellY = cellCoordinates_pair.first.getY(); // The coordinates of hit in mCellId - int xHitInCell ((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize); - int yHitInCell ((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize); + int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.5)); + int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.5)); + if (xHitInCell < 0) + { + xHitInCell = xHitInCell + landTextureSize; + cellX = cellX - 1; + } + if (yHitInCell > 15) + { + yHitInCell = yHitInCell - landTextureSize; + cellY = cellY + 1; + } + + mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY); std::string iteratedCellId; From baa707b5e3e8cf020c7717a1b681f7abaccb1f64 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 29 Apr 2018 15:17:06 +0300 Subject: [PATCH 137/321] User setting for selective cell editing or new land creation --- apps/opencs/model/prefs/state.cpp | 12 + .../opencs/view/render/terraintexturemode.cpp | 216 +++++++++++++----- .../opencs/view/render/terraintexturemode.hpp | 3 + 3 files changed, 171 insertions(+), 60 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 8a9dad7f3..6cbc33766 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -222,6 +222,14 @@ void CSMPrefs::State::declare() EnumValues insertOutsideVisibleCell; insertOutsideVisibleCell.add (showAndInsert).add (dontInsert).add (insertAnyway); + EnumValue createAndLandEdit ("Create cell and land, then edit"); + EnumValue showAndLandEdit ("Show cell and edit"); + EnumValue dontLandEdit ("Discard"); + EnumValues landeditOutsideCell; + landeditOutsideCell.add (createAndLandEdit).add (dontLandEdit); + EnumValues landeditOutsideVisibleCell; + landeditOutsideVisibleCell.add (showAndLandEdit).add (dontLandEdit); + declareCategory ("Scene Drops"); declareInt ("distance", "Drop Distance", 50). setTooltip ("If an instance drop can not be placed against another object at the " @@ -230,6 +238,10 @@ void CSMPrefs::State::declare() addValues (insertOutsideCell); declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert). addValues (insertOutsideVisibleCell); + declareEnum ("outside-landedit", "Handling land edit outside of cells", createAndLandEdit). + addValues (landeditOutsideCell); + declareEnum ("outside-visible-landedit", "Handling land edit outside of visible cells", showAndLandEdit). + addValues (landeditOutsideVisibleCell); declareCategory ("Key Bindings"); diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 97856c20c..3468d4cd9 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -22,11 +22,13 @@ #include "../widget/scenetoolbar.hpp" #include "../../model/doc/document.hpp" +#include "../../model/prefs/state.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/commandmacro.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/world/land.hpp" #include "../../model/world/landtexture.hpp" #include "../../model/world/resourcetable.hpp" @@ -186,8 +188,11 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult QUndoStack& undoStack = document.getUndoStack(); undoStack.beginMacro ("Edit texture records"); - undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); - editTerrainTextureGrid(hit); + if(allowLandTextureEditing(mCellId)==true) + { + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); + editTerrainTextureGrid(hit); + } undoStack.endMacro(); } @@ -213,8 +218,11 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) QUndoStack& undoStack = document.getUndoStack(); undoStack.beginMacro ("Edit texture records"); - undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); - editTerrainTextureGrid(hit); + if(allowLandTextureEditing(mCellId)==true) + { + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); + editTerrainTextureGrid(hit); + } return true; } @@ -299,7 +307,12 @@ void CSVRender::TerrainTextureMode::handlePrimarySelectOnModeButton () { void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit) { + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + mCellId = getWorldspaceWidget().getCellId (hit.worldPos); + if(allowLandTextureEditing(mCellId)==true) {} std::pair cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (mCellId); @@ -321,13 +334,10 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY); + if(allowLandTextureEditing(mCellId)==true) {} std::string iteratedCellId; - CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - CSMWorld::IdTable& landTable = dynamic_cast ( - *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); - int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); std::size_t hashlocation = mBrushTexture.find("#"); @@ -342,8 +352,12 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt; - pushEditToCommand(mNew, document, landTable, mCellId); + + if(allowLandTextureEditing(mCellId)==true) + { + mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt; + pushEditToCommand(mNew, document, landTable, mCellId); + } } if (mBrushShape == 1) @@ -363,32 +377,35 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - for(int i = 0; i < landTextureSize; i++) + if(allowLandTextureEditing(iteratedCellId)==true) { - for(int j = 0; j < landTextureSize; j++) + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + for(int i = 0; i < landTextureSize; i++) { - - if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + for(int j = 0; j < landTextureSize; j++) { - mNew[j*landTextureSize+i] = brushInt; - } - else - { - int distanceX(0); - int distanceY(0); - if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; - if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; - if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i; - if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; - if (i_cell == cellX) distanceX = abs(i-xHitInCell); - if (j_cell == cellY) distanceY = abs(j-yHitInCell); - if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt; + + if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + { + mNew[j*landTextureSize+i] = brushInt; + } + else + { + int distanceX(0); + int distanceY(0); + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; + if (i_cell == cellX) distanceX = abs(i-xHitInCell); + if (j_cell == cellY) distanceY = abs(j-yHitInCell); + if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt; + } } } + pushEditToCommand(mNew, document, landTable, iteratedCellId); } - pushEditToCommand(mNew, document, landTable, iteratedCellId); } } } @@ -410,45 +427,49 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); - for(int i = 0; i < landTextureSize; i++) + if(allowLandTextureEditing(iteratedCellId)==true) { - for(int j = 0; j < landTextureSize; j++) + CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + for(int i = 0; i < landTextureSize; i++) { - - if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + for(int j = 0; j < landTextureSize; j++) { - int distanceX(0); - int distanceY(0); - if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; - if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; - if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize* abs(i_cell-cellX) + i; - if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; - if (i_cell == cellX) distanceX = abs(i-xHitInCell); - if (j_cell == cellY) distanceY = abs(j-yHitInCell); - distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (distance < rf) mNew[j*landTextureSize+i] = brushInt; - } - else - { - int distanceX(0); - int distanceY(0); - if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; - if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; - if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i; - if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; - if (i_cell == cellX) distanceX = abs(i-xHitInCell); - if (j_cell == cellY) distanceY = abs(j-yHitInCell); - distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + + if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + { + int distanceX(0); + int distanceY(0); + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize* abs(i_cell-cellX) + i; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; + if (i_cell == cellX) distanceX = abs(i-xHitInCell); + if (j_cell == cellY) distanceY = abs(j-yHitInCell); + distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + } + else + { + int distanceX(0); + int distanceY(0); + if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i; + if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j; + if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i; + if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; + if (i_cell == cellX) distanceX = abs(i-xHitInCell); + if (j_cell == cellY) distanceY = abs(j-yHitInCell); + distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + } } } + pushEditToCommand(mNew, document, landTable, iteratedCellId); } - pushEditToCommand(mNew, document, landTable, iteratedCellId); } } } + if (mBrushShape == 3) { // Not implemented @@ -510,6 +531,81 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) undoStack.endMacro(); } +bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) +{ + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + CSMWorld::IdTree& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + bool noCell = document.getData().getCells().searchId (cellId)==-1; + bool noLand = document.getData().getLand().searchId (cellId)==-1; + + if (noCell) + { + std::string mode = CSMPrefs::get()["Scene Drops"]["outside-landedit"].toString(); + + // target cell does not exist + if (mode=="Discard") + return false; + + if (mode=="Create cell and land, then edit") + { + std::unique_ptr createCommand ( + new CSMWorld::CreateCommand (cellTable, cellId)); + int parentIndex = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); + int index = cellTable.findNestedColumnIndex (parentIndex, CSMWorld::Columns::ColumnId_Interior); + createCommand->addNestedValue (parentIndex, index, false); + document.getUndoStack().push (createCommand.release()); + + if (CSVRender::PagedWorldspaceWidget *paged = + dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + selection.add (CSMWorld::CellCoordinates::fromId (cellId).first); + paged->setCellSelection (selection); + } + } + } + else if (CSVRender::PagedWorldspaceWidget *paged = + dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + if (!selection.has (CSMWorld::CellCoordinates::fromId (cellId).first)) + { + // target cell exists, but is not shown + std::string mode = + CSMPrefs::get()["Scene Drops"]["outside-visible-landedit"].toString(); + + if (mode=="Discard") + return false; + + if (mode=="Show cell and edit") + { + selection.add (CSMWorld::CellCoordinates::fromId (cellId).first); + paged->setCellSelection (selection); + } + } + } + + if (noLand) + { + std::string mode = CSMPrefs::get()["Scene Drops"]["outside-landedit"].toString(); + + // target cell does not exist + if (mode=="Discard") + return false; + + if (mode=="Create cell and land, then edit") + { + document.getUndoStack().push (new CSMWorld::CreateCommand (landTable, cellId)); + } + } + + return true; +} + void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { } diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index f6fde3544..dcf16040e 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -126,6 +126,9 @@ namespace CSVRender /// \brief Create new land texture record from texture asset void createTexture(std::string textureFileName); + /// \brief Create new cell and land if needed + bool allowLandTextureEditing(std::string textureFileName); + private: TextureBrushWindow *textureBrushWindow; std::string mCellId; From 56567454455bd284da4d22d669688582690f7c8f Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 6 May 2018 18:02:18 +0300 Subject: [PATCH 138/321] Select dragged texture-assets, add brush settings widget-type, fixes. --- apps/opencs/CMakeLists.txt | 2 +- .../opencs/view/render/terraintexturemode.cpp | 162 +++------------- .../opencs/view/render/terraintexturemode.hpp | 54 +----- apps/opencs/view/render/worldspacewidget.cpp | 4 - apps/opencs/view/widget/scenetoolmode.cpp | 10 - apps/opencs/view/widget/scenetoolmode.hpp | 5 - .../view/widget/scenetooltexturebrush.cpp | 173 ++++++++++++++++++ .../view/widget/scenetooltexturebrush.hpp | 109 +++++++++++ 8 files changed, 310 insertions(+), 209 deletions(-) create mode 100644 apps/opencs/view/widget/scenetooltexturebrush.cpp create mode 100644 apps/opencs/view/widget/scenetooltexturebrush.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f8dd1fe2d..d1ebcde42 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -81,7 +81,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit + scenetooltoggle2 scenetooltexturebrush completerpopup coloreditor colorpickerpopup droplineedit ) opencs_units (view/render diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 3468d4cd9..1c1c318d7 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -20,6 +20,7 @@ #include "../widget/modebutton.hpp" #include "../widget/scenetoolbar.hpp" +#include "../widget/scenetooltexturebrush.hpp" #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" @@ -41,138 +42,41 @@ #include "object.hpp" // Something small needed regarding pointers from here () #include "worldspacewidget.hpp" - -CSVRender::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) - : QGroupBox(title, parent) -{ - brushSizeSlider = new QSlider(Qt::Horizontal); - brushSizeSlider->setTickPosition(QSlider::TicksBothSides); - brushSizeSlider->setTickInterval(10); - brushSizeSlider->setRange(1, 50); - brushSizeSlider->setSingleStep(1); - - brushSizeSpinBox = new QSpinBox; - brushSizeSpinBox->setRange(1, 50); - brushSizeSpinBox->setSingleStep(1); - - layoutSliderSize = new QHBoxLayout; - layoutSliderSize->addWidget(brushSizeSlider); - layoutSliderSize->addWidget(brushSizeSpinBox); - - connect(brushSizeSlider, SIGNAL(valueChanged(int)), brushSizeSpinBox, SLOT(setValue(int))); - connect(brushSizeSpinBox, SIGNAL(valueChanged(int)), brushSizeSlider, SLOT(setValue(int))); - - setLayout(layoutSliderSize); -} - -CSVRender::TextureBrushWindow::TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent) - : QFrame(parent, Qt::Popup), - mWorldspaceWidget (worldspaceWidget), - mBrushSize(0), - mBrushShape(0) -{ - mBrushTextureLabel = "Brush: " + mBrushTexture; - selectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel), this); - - QVBoxLayout *layoutMain = new QVBoxLayout; - layoutMain->setSpacing(0); - - QHBoxLayout *layoutHorizontal = new QHBoxLayout; - layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0)); - layoutHorizontal->setSpacing(0); - - configureButtonInitialSettings(buttonPoint); - configureButtonInitialSettings(buttonSquare); - configureButtonInitialSettings(buttonCircle); - configureButtonInitialSettings(buttonCustom); - - QButtonGroup* brushButtonGroup = new QButtonGroup(this); - brushButtonGroup->addButton(buttonPoint); - brushButtonGroup->addButton(buttonSquare); - brushButtonGroup->addButton(buttonCircle); - brushButtonGroup->addButton(buttonCustom); - - brushButtonGroup->setExclusive(true); - - layoutHorizontal->addWidget(buttonPoint); - layoutHorizontal->addWidget(buttonSquare); - layoutHorizontal->addWidget(buttonCircle); - layoutHorizontal->addWidget(buttonCustom); - - horizontalGroupBox = new QGroupBox(tr("")); - horizontalGroupBox->setLayout(layoutHorizontal); - - BrushSizeControls* sizeSliders = new BrushSizeControls(tr(""), this); - - layoutMain->addWidget(horizontalGroupBox); - layoutMain->addWidget(sizeSliders); - layoutMain->addWidget(selectedBrush); - - setLayout(layoutMain); - - connect(buttonPoint, SIGNAL(clicked()), this, SLOT(setBrushShape())); - connect(buttonSquare, SIGNAL(clicked()), this, SLOT(setBrushShape())); - connect(buttonCircle, SIGNAL(clicked()), this, SLOT(setBrushShape())); - connect(buttonCustom, SIGNAL(clicked()), this, SLOT(setBrushShape())); - - connect(sizeSliders->brushSizeSlider, SIGNAL(valueChanged(int)), parent, SLOT(setBrushSize(int))); - - connect(parent, SIGNAL(passBrushTexture(std::string)), this, SLOT(setBrushTexture(std::string))); -} - -void CSVRender::TextureBrushWindow::configureButtonInitialSettings(QPushButton *button) -{ - button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); - button->setContentsMargins (QMargins (0, 0, 0, 0)); - button->setIconSize (QSize (48-6, 48-6)); - button->setFixedSize (48, 48); - button->setAcceptDrops(true); - button->setCheckable(true); -} - -void CSVRender::TextureBrushWindow::setBrushTexture(std::string brushTexture) -{ - mBrushTexture = brushTexture; - mBrushTextureLabel = "Brush:" + mBrushTexture; - selectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); -} - -void CSVRender::TextureBrushWindow::setBrushSize(int brushSize) -{ - mBrushSize = brushSize; - emit passBrushSize(mBrushSize); -} - -void CSVRender::TextureBrushWindow::setBrushShape() -{ - if(buttonPoint->isChecked()) mBrushShape = 0; - if(buttonSquare->isChecked()) mBrushShape = 1; - if(buttonCircle->isChecked()) mBrushShape = 2; - if(buttonCustom->isChecked()) mBrushShape = 3; - emit passBrushShape(mBrushShape); -} - CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent), - textureBrushWindow(new TextureBrushWindow(worldspaceWidget, this)), mBrushTexture("#0"), mBrushSize(0), - mBrushShape(0) + mBrushShape(0), + mTextureBrushScenetool(0) { - connect(parent, SIGNAL(passEvent(QDragEnterEvent*)), this, SLOT(handleDragEnterEvent(QDragEnterEvent*))); - connect(parent, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); - connect(parent, SIGNAL(passEvent(QMouseEvent*)), this, SLOT(handleMouseEvent(QMouseEvent*))); - connect(textureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); - connect(textureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); } void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) { + if(!mTextureBrushScenetool) + { + mTextureBrushScenetool = new CSVWidget::SceneToolTextureBrush (toolbar, "scenetooltexturebrush"); + connect(mTextureBrushScenetool, SIGNAL (clicked()), mTextureBrushScenetool, SLOT (activate())); + connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); + connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); + connect(mTextureBrushScenetool->mTextureBrushWindow->mSizeSliders->mBrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrushSize(int))); + + connect(mTextureBrushScenetool, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); + connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool->mTextureBrushWindow, SLOT(setBrushTexture(std::string))); + } + EditMode::activate(toolbar); + toolbar->addTool (mTextureBrushScenetool); } void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) { + if(mTextureBrushScenetool) + { + toolbar->removeTool (mTextureBrushScenetool); + delete mTextureBrushScenetool; + mTextureBrushScenetool = 0; + } EditMode::deactivate(toolbar); } @@ -259,10 +163,6 @@ void CSVRender::TerrainTextureMode::dragAborted() { void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) {} -void CSVRender::TerrainTextureMode::handleDragEnterEvent (QDragEnterEvent *event) { - event->accept(); -} - void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -287,24 +187,11 @@ void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { { std::string textureFileName = uid.toString(); createTexture(textureFileName); + emit passBrushTexture(mBrushTexture); } } } -void CSVRender::TerrainTextureMode::handleMouseEvent (QMouseEvent *event) -{ - if (event->button()==Qt::MidButton) - { - QPoint position = QCursor::pos(); - textureBrushWindow->move (position); - textureBrushWindow->show(); - } - if (event->button()==Qt::LeftButton) PushButton::mouseReleaseEvent (event); -} - -void CSVRender::TerrainTextureMode::handlePrimarySelectOnModeButton () { -} - void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit) { CSMDoc::Document& document = getWorldspaceWidget().getDocument(); @@ -529,6 +416,7 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) QModelIndex index(ltexTable.getModelIndex (newId, ltexTable.findColumnIndex (CSMWorld::Columns::ColumnId_Texture))); undoStack.push (new CSMWorld::ModifyCommand(ltexTable, index, textureFileNameVariant)); undoStack.endMacro(); + mBrushTexture = newId; } bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) @@ -602,7 +490,7 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) document.getUndoStack().push (new CSMWorld::CreateCommand (landTable, cellId)); } } - + return true; } diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index dcf16040e..212cff639 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -26,59 +26,12 @@ namespace CSVWidget { - class SceneToolMode; + class SceneToolTextureBrush; } namespace CSVRender { - /// \brief Layout-box for some brush button settings - class BrushSizeControls : public QGroupBox - { - Q_OBJECT - - public: - BrushSizeControls(const QString &title, QWidget *parent); - QSlider *brushSizeSlider; - - private: - QSpinBox *brushSizeSpinBox; - QHBoxLayout *layoutSliderSize; - }; - - /// \brief Brush settings window - class TextureBrushWindow : public QFrame - { - Q_OBJECT - - public: - TextureBrushWindow(WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); - void configureButtonInitialSettings(QPushButton *button); - - QPushButton *buttonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); - QPushButton *buttonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); - QPushButton *buttonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); - QPushButton *buttonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); - - private: - QLabel *selectedBrush; - QGroupBox *horizontalGroupBox; - WorldspaceWidget *mWorldspaceWidget; - int mBrushSize; - int mBrushShape; - std::string mBrushTexture; - std::string mBrushTextureLabel; - - public slots: - void setBrushTexture(std::string brushTexture); - void setBrushShape(); - void setBrushSize(int brushSize); - - signals: - void passBrushSize (int brushSize); - void passBrushShape(int brushShape); - }; - class TerrainTextureMode : public EditMode { Q_OBJECT @@ -130,11 +83,11 @@ namespace CSVRender bool allowLandTextureEditing(std::string textureFileName); private: - TextureBrushWindow *textureBrushWindow; std::string mCellId; std::string mBrushTexture; int mBrushSize; int mBrushShape; + CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool; const int cellSize {ESM::Land::REAL_SIZE}; const int landSize {ESM::Land::LAND_SIZE}; @@ -144,10 +97,7 @@ namespace CSVRender void passBrushTexture(std::string brushTexture); public slots: - void handleDragEnterEvent (QDragEnterEvent *event); void handleDropEvent(QDropEvent *event); - void handleMouseEvent (QMouseEvent *event); - void handlePrimarySelectOnModeButton(); void setBrushSize(int brushSize); void setBrushShape(int brushShape); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index c8ba16666..9fb6aa02a 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -576,10 +576,6 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { - dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); - if (mEditMode->getCurrentId() == "terrain-texture") mEditMode->setAcceptDrops(true); - else mEditMode->setAcceptDrops(false); - mDragging = false; mDragMode = InteractionType_None; } diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 94435016f..426bceb29 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -137,7 +137,6 @@ void CSVWidget::SceneToolMode::setButton (const std::string& id) void CSVWidget::SceneToolMode::mouseReleaseEvent (QMouseEvent *event) { - if (event->button()==Qt::MidButton && getCurrentId() == "terrain-texture") emit passEvent(event); if (getType()==Type_TopAction && event->button()==Qt::RightButton) showPanel (parentWidget()->mapToGlobal (pos())); else @@ -154,15 +153,6 @@ bool CSVWidget::SceneToolMode::event(QEvent* event) return SceneTool::event(event); } -void CSVWidget::SceneToolMode::dragEnterEvent (QDragEnterEvent *event) -{ - emit passEvent(event); -} -void CSVWidget::SceneToolMode::dropEvent (QDropEvent *event) -{ - emit passEvent(event); -} - void CSVWidget::SceneToolMode::selected() { std::map::iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 7d0c8f70e..377357df6 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -49,8 +49,6 @@ namespace CSVWidget protected: bool event(QEvent* event); - void dragEnterEvent (QDragEnterEvent *event); - void dropEvent (QDropEvent *event); public: @@ -76,9 +74,6 @@ namespace CSVWidget signals: void modeChanged (const std::string& id); - void passEvent (QMouseEvent *event); - void passEvent (QDragEnterEvent *event); - void passEvent (QDropEvent *event); private slots: diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp new file mode 100644 index 000000000..abf65182c --- /dev/null +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -0,0 +1,173 @@ +#include "scenetooltexturebrush.hpp" + +#include + +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scenetool.hpp" + +CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) + : QGroupBox(title, parent) +{ + mBrushSizeSlider = new QSlider(Qt::Horizontal); + mBrushSizeSlider->setTickPosition(QSlider::TicksBothSides); + mBrushSizeSlider->setTickInterval(10); + mBrushSizeSlider->setRange(1, 50); + mBrushSizeSlider->setSingleStep(1); + + mBrushSizeSpinBox = new QSpinBox; + mBrushSizeSpinBox->setRange(1, 50); + mBrushSizeSpinBox->setSingleStep(1); + + mLayoutSliderSize = new QHBoxLayout; + mLayoutSliderSize->addWidget(mBrushSizeSlider); + mLayoutSliderSize->addWidget(mBrushSizeSpinBox); + + connect(mBrushSizeSlider, SIGNAL(valueChanged(int)), mBrushSizeSpinBox, SLOT(setValue(int))); + connect(mBrushSizeSpinBox, SIGNAL(valueChanged(int)), mBrushSizeSlider, SLOT(setValue(int))); + + setLayout(mLayoutSliderSize); +} + +CSVWidget::TextureBrushWindow::TextureBrushWindow(QWidget *parent) + : QFrame(parent, Qt::Popup), + mBrushShape(0), + mBrushSize(0) + +{ + mBrushTextureLabel = "Brush: " + mBrushTexture; + mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel), this); + + QVBoxLayout *layoutMain = new QVBoxLayout; + layoutMain->setSpacing(0); + + QHBoxLayout *layoutHorizontal = new QHBoxLayout; + layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0)); + layoutHorizontal->setSpacing(0); + + configureButtonInitialSettings(mButtonPoint); + configureButtonInitialSettings(mButtonSquare); + configureButtonInitialSettings(mButtonCircle); + configureButtonInitialSettings(mButtonCustom); + + QButtonGroup* brushButtonGroup = new QButtonGroup(this); + brushButtonGroup->addButton(mButtonPoint); + brushButtonGroup->addButton(mButtonSquare); + brushButtonGroup->addButton(mButtonCircle); + brushButtonGroup->addButton(mButtonCustom); + + brushButtonGroup->setExclusive(true); + + layoutHorizontal->addWidget(mButtonPoint); + layoutHorizontal->addWidget(mButtonSquare); + layoutHorizontal->addWidget(mButtonCircle); + layoutHorizontal->addWidget(mButtonCustom); + + mHorizontalGroupBox = new QGroupBox(tr("")); + mHorizontalGroupBox->setLayout(layoutHorizontal); + + layoutMain->addWidget(mHorizontalGroupBox); + layoutMain->addWidget(mSizeSliders); + layoutMain->addWidget(mSelectedBrush); + + setLayout(layoutMain); + + connect(mButtonPoint, SIGNAL(clicked()), this, SLOT(setBrushShape())); + connect(mButtonSquare, SIGNAL(clicked()), this, SLOT(setBrushShape())); + connect(mButtonCircle, SIGNAL(clicked()), this, SLOT(setBrushShape())); + connect(mButtonCustom, SIGNAL(clicked()), this, SLOT(setBrushShape())); +} + +void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton *button) +{ + button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + button->setContentsMargins (QMargins (0, 0, 0, 0)); + button->setIconSize (QSize (48-6, 48-6)); + button->setFixedSize (48, 48); + button->setCheckable(true); +} + +void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) +{ + mBrushTexture = brushTexture; + mBrushTextureLabel = "Brush:" + mBrushTexture; + mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); +} + +void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize) +{ + mBrushSize = brushSize; + emit passBrushSize(mBrushSize); +} + +void CSVWidget::TextureBrushWindow::setBrushShape() +{ + if(mButtonPoint->isChecked()) mBrushShape = 0; + if(mButtonSquare->isChecked()) mBrushShape = 1; + if(mButtonCircle->isChecked()) mBrushShape = 2; + if(mButtonCustom->isChecked()) mBrushShape = 3; + emit passBrushShape(mBrushShape); +} + +void CSVWidget::SceneToolTextureBrush::adjustToolTips() +{ +} + +CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip) +: SceneTool (parent), + mToolTip (toolTip), + mTextureBrushWindow(new TextureBrushWindow(this)) +{ + setAcceptDrops(true); + if(mTextureBrushWindow->mBrushShape == 0) setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); + if(mTextureBrushWindow->mBrushShape == 1) setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); + if(mTextureBrushWindow->mBrushShape == 2) setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); + if(mTextureBrushWindow->mBrushShape == 3) setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); + connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int))); +} + +void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) +{ + if(brushShape == 0) setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); + if(brushShape == 1) setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); + if(brushShape == 2) setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); + if(brushShape == 3) setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); +} + +void CSVWidget::SceneToolTextureBrush::showPanel (const QPoint& position) +{ + +} + +void CSVWidget::SceneToolTextureBrush::activate () +{ + QPoint position = QCursor::pos(); + mTextureBrushWindow->move (position); + mTextureBrushWindow->show(); +} + +void CSVWidget::SceneToolTextureBrush::dragEnterEvent (QDragEnterEvent *event) +{ + emit passEvent(event); + event->accept(); +} +void CSVWidget::SceneToolTextureBrush::dropEvent (QDropEvent *event) +{ + emit passEvent(event); + event->accept(); +} diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp new file mode 100644 index 000000000..d9cc1e566 --- /dev/null +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -0,0 +1,109 @@ +#ifndef CSV_WIDGET_SCENETOOLTEXTUREBRUSH_H +#define CSV_WIDGET_SCENETOOLTEXTUREBRUSH_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scenetool.hpp" + +/*namespace CSVRender +{ + class TerrainTextureMode; +}*/ + +namespace CSVWidget +{ + /// \brief Layout-box for some brush button settings + class BrushSizeControls : public QGroupBox + { + Q_OBJECT + + public: + BrushSizeControls(const QString &title, QWidget *parent); + QSlider *mBrushSizeSlider; + + private: + QSpinBox *mBrushSizeSpinBox; + QHBoxLayout *mLayoutSliderSize; + }; + + /// \brief Brush settings window + class TextureBrushWindow : public QFrame + { + Q_OBJECT + + public: + TextureBrushWindow(QWidget *parent = 0); + void configureButtonInitialSettings(QPushButton *button); + + QPushButton *mButtonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); + QPushButton *mButtonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); + QPushButton *mButtonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); + QPushButton *mButtonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); + BrushSizeControls* mSizeSliders = new BrushSizeControls(tr(""), this); + int mBrushShape; + + private: + QLabel *mSelectedBrush; + QGroupBox *mHorizontalGroupBox; + int mBrushSize; + std::string mBrushTexture; + std::string mBrushTextureLabel; + + public slots: + void setBrushTexture(std::string brushTexture); + void setBrushShape(); + void setBrushSize(int brushSize); + + signals: + void passBrushSize (int brushSize); + void passBrushShape(int brushShape); + }; + + class SceneToolTextureBrush : public SceneTool + { + Q_OBJECT + + QString mToolTip; + + //CSVRender::TerrainTextureMode *mTerrainTextureMode; + //QIcon *mTextureBrushIcon; + + private: + + void adjustToolTips(); + + public: + + SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip); + + virtual void showPanel (const QPoint& position); + + TextureBrushWindow *mTextureBrushWindow; + //virtual void activate(); + + void dropEvent (QDropEvent *event); + void dragEnterEvent (QDragEnterEvent *event); + + public slots: + void setButtonIcon(int brushShape); + virtual void activate(); + //void clicked (); + + signals: + void passEvent(QDropEvent *event); + void passEvent(QDragEnterEvent *event); + }; +} + +#endif From d33c98c68d6b56ac4377d64b90140c1954b2f0b3 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 6 May 2018 18:13:15 +0300 Subject: [PATCH 139/321] Revert unintended changes --- apps/opencs/view/render/worldspacewidget.cpp | 1 + apps/opencs/view/widget/scenetoolmode.cpp | 9 --------- apps/opencs/view/widget/scenetoolmode.hpp | 2 -- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 9fb6aa02a..c2a6617c1 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -576,6 +576,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { + dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); mDragging = false; mDragMode = InteractionType_None; } diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 426bceb29..7b2ff64db 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -134,15 +134,6 @@ void CSVWidget::SceneToolMode::setButton (const std::string& id) } } - -void CSVWidget::SceneToolMode::mouseReleaseEvent (QMouseEvent *event) -{ - if (getType()==Type_TopAction && event->button()==Qt::RightButton) - showPanel (parentWidget()->mapToGlobal (pos())); - else - PushButton::mouseReleaseEvent (event); -} - bool CSVWidget::SceneToolMode::event(QEvent* event) { if (event->type() == QEvent::ToolTip) diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 377357df6..90f1dc419 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -44,8 +44,6 @@ namespace CSVWidget void setButton (std::map::iterator iter); - void mouseReleaseEvent (QMouseEvent *event); - protected: bool event(QEvent* event); From 62066f01bd417a8a513daa5a81f73ddb2bfe9e88 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 6 May 2018 18:51:58 +0300 Subject: [PATCH 140/321] clean-up --- apps/opencs/view/render/terraintexturemode.cpp | 6 ------ apps/opencs/view/render/terraintexturemode.hpp | 8 -------- apps/opencs/view/widget/scenetooltexturebrush.cpp | 4 ---- apps/opencs/view/widget/scenetooltexturebrush.hpp | 5 ----- 4 files changed, 23 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 1c1c318d7..33822291b 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -5,14 +5,8 @@ #include #include -#include -#include -#include #include #include -#include -#include -#include #include #include diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 212cff639..084f4c637 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -6,15 +6,7 @@ #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include #include "../../model/world/data.hpp" #include "../../model/world/land.hpp" diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index abf65182c..ddc921729 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -1,13 +1,10 @@ #include "scenetooltexturebrush.hpp" -#include - #include #include #include #include - #include #include #include @@ -151,7 +148,6 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) void CSVWidget::SceneToolTextureBrush::showPanel (const QPoint& position) { - } void CSVWidget::SceneToolTextureBrush::activate () diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index d9cc1e566..66d40ca53 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -76,9 +76,6 @@ namespace CSVWidget QString mToolTip; - //CSVRender::TerrainTextureMode *mTerrainTextureMode; - //QIcon *mTextureBrushIcon; - private: void adjustToolTips(); @@ -90,7 +87,6 @@ namespace CSVWidget virtual void showPanel (const QPoint& position); TextureBrushWindow *mTextureBrushWindow; - //virtual void activate(); void dropEvent (QDropEvent *event); void dragEnterEvent (QDragEnterEvent *event); @@ -98,7 +94,6 @@ namespace CSVWidget public slots: void setButtonIcon(int brushShape); virtual void activate(); - //void clicked (); signals: void passEvent(QDropEvent *event); From d2cf764a46e1358dda4bd8bcde036afc905d57cb Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 10 May 2018 15:01:53 +0300 Subject: [PATCH 141/321] Tooltips, fixes --- .../view/widget/scenetooltexturebrush.cpp | 58 +++++++++++++------ .../view/widget/scenetooltexturebrush.hpp | 10 +++- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index ddc921729..07682cbca 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -44,24 +44,30 @@ CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p CSVWidget::TextureBrushWindow::TextureBrushWindow(QWidget *parent) : QFrame(parent, Qt::Popup), mBrushShape(0), - mBrushSize(0) - + mBrushSize(0), + mBrushTexture("L0#0") { - mBrushTextureLabel = "Brush: " + mBrushTexture; + mBrushTextureLabel = "Selected texture (id): " + mBrushTexture; mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel), this); QVBoxLayout *layoutMain = new QVBoxLayout; layoutMain->setSpacing(0); + layoutMain->setContentsMargins(4,0,4,4); QHBoxLayout *layoutHorizontal = new QHBoxLayout; - layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0)); layoutHorizontal->setSpacing(0); + layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0)); configureButtonInitialSettings(mButtonPoint); configureButtonInitialSettings(mButtonSquare); configureButtonInitialSettings(mButtonCircle); configureButtonInitialSettings(mButtonCustom); + mButtonPoint->setToolTip (toolTipPoint); + mButtonSquare->setToolTip (toolTipSquare); + mButtonCircle->setToolTip (toolTipCircle); + mButtonCustom->setToolTip (toolTipCustom); + QButtonGroup* brushButtonGroup = new QButtonGroup(this); brushButtonGroup->addButton(mButtonPoint); brushButtonGroup->addButton(mButtonSquare); @@ -70,10 +76,10 @@ CSVWidget::TextureBrushWindow::TextureBrushWindow(QWidget *parent) brushButtonGroup->setExclusive(true); - layoutHorizontal->addWidget(mButtonPoint); - layoutHorizontal->addWidget(mButtonSquare); - layoutHorizontal->addWidget(mButtonCircle); - layoutHorizontal->addWidget(mButtonCustom); + layoutHorizontal->addWidget(mButtonPoint, 0, Qt::AlignTop); + layoutHorizontal->addWidget(mButtonSquare, 0, Qt::AlignTop); + layoutHorizontal->addWidget(mButtonCircle, 0, Qt::AlignTop); + layoutHorizontal->addWidget(mButtonCustom, 0, Qt::AlignTop); mHorizontalGroupBox = new QGroupBox(tr("")); mHorizontalGroupBox->setLayout(layoutHorizontal); @@ -102,8 +108,9 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton * void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) { mBrushTexture = brushTexture; - mBrushTextureLabel = "Brush:" + mBrushTexture; + mBrushTextureLabel = "Selected texture (id): " + mBrushTexture; mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); + emit passBrushShape(mBrushShape); // update icon } void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize) @@ -131,19 +138,36 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, c mTextureBrushWindow(new TextureBrushWindow(this)) { setAcceptDrops(true); - if(mTextureBrushWindow->mBrushShape == 0) setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); - if(mTextureBrushWindow->mBrushShape == 1) setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); - if(mTextureBrushWindow->mBrushShape == 2) setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); - if(mTextureBrushWindow->mBrushShape == 3) setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int))); + setButtonIcon(mTextureBrushWindow->mBrushShape); } void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) { - if(brushShape == 0) setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); - if(brushShape == 1) setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); - if(brushShape == 2) setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); - if(brushShape == 3) setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); + QString tooltip = "Brush settings

Currently selected: "; + if(brushShape == 0) + { + setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); + tooltip += dynamic_cast (mTextureBrushWindow->toolTipPoint); + } + if(brushShape == 1) + { + setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); + tooltip += dynamic_cast (mTextureBrushWindow->toolTipSquare); + } + if(brushShape == 2) + { + setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); + tooltip += dynamic_cast (mTextureBrushWindow->toolTipCircle); + } + if(brushShape == 3) + { + setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); + tooltip += dynamic_cast (mTextureBrushWindow->toolTipCustom); + } + tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture); + tooltip += "
(drop texture here to change)"; + setToolTip (tooltip); } void CSVWidget::SceneToolTextureBrush::showPanel (const QPoint& position) diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 66d40ca53..1bf15ead9 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -50,14 +50,18 @@ namespace CSVWidget QPushButton *mButtonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); QPushButton *mButtonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); QPushButton *mButtonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); - BrushSizeControls* mSizeSliders = new BrushSizeControls(tr(""), this); + QString toolTipPoint = "Paint single point"; + QString toolTipSquare = "Paint with square brush"; + QString toolTipCircle = "Paint with circle brush"; + QString toolTipCustom = "Paint custom selection (not implemented yet)"; + BrushSizeControls* mSizeSliders = new BrushSizeControls("Brush size", this); int mBrushShape; + int mBrushSize; + std::string mBrushTexture; private: QLabel *mSelectedBrush; QGroupBox *mHorizontalGroupBox; - int mBrushSize; - std::string mBrushTexture; std::string mBrushTextureLabel; public slots: From 1c79d5311c198f49ce3efea7f536daa85b424dfa Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 10 May 2018 21:58:36 +0300 Subject: [PATCH 142/321] Brush history menu --- .../opencs/view/render/terraintexturemode.cpp | 7 ++ .../opencs/view/render/terraintexturemode.hpp | 2 +- .../view/widget/scenetooltexturebrush.cpp | 72 ++++++++++++++++++- .../view/widget/scenetooltexturebrush.hpp | 12 ++-- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 33822291b..ea68cfa93 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -54,9 +54,11 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); connect(mTextureBrushScenetool->mTextureBrushWindow->mSizeSliders->mBrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrushSize(int))); + connect(mTextureBrushScenetool, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string))); connect(mTextureBrushScenetool, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool->mTextureBrushWindow, SLOT(setBrushTexture(std::string))); + connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool, SLOT(updateBrushHistory(std::string))); } EditMode::activate(toolbar); @@ -500,3 +502,8 @@ void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) { mBrushShape = brushShape; } + +void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture) +{ + mBrushTexture = brushTexture; +} diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 084f4c637..e1538e243 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -92,7 +92,7 @@ namespace CSVRender void handleDropEvent(QDropEvent *event); void setBrushSize(int brushSize); void setBrushShape(int brushShape); - + void setBrushTexture(std::string brushShape); }; } diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index 07682cbca..990963415 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -15,6 +15,10 @@ #include #include #include +#include +#include +#include +#include #include "scenetool.hpp" @@ -133,13 +137,40 @@ void CSVWidget::SceneToolTextureBrush::adjustToolTips() } CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip) -: SceneTool (parent), +: SceneTool (parent, Type_TopAction), mToolTip (toolTip), + mBrushHistory{"L0#0"}, mTextureBrushWindow(new TextureBrushWindow(this)) { setAcceptDrops(true); connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int))); setButtonIcon(mTextureBrushWindow->mBrushShape); + + mPanel = new QFrame (this, Qt::Popup); + + QHBoxLayout *layout = new QHBoxLayout (mPanel); + + layout->setContentsMargins (QMargins (0, 0, 0, 0)); + + mTable = new QTableWidget (0, 2, this); + + mTable->setShowGrid (true); + mTable->verticalHeader()->hide(); + mTable->horizontalHeader()->hide(); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + mTable->horizontalHeader()->setSectionResizeMode (0, QHeaderView::Stretch); + mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents); +#else + mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch); + mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); +#endif + mTable->setSelectionMode (QAbstractItemView::NoSelection); + + layout->addWidget (mTable); + + connect (mTable, SIGNAL (clicked (const QModelIndex&)), + this, SLOT (clicked (const QModelIndex&))); + } void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) @@ -172,6 +203,45 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) void CSVWidget::SceneToolTextureBrush::showPanel (const QPoint& position) { + updatePanel(); + mPanel->move (position); + mPanel->show(); +} + +void CSVWidget::SceneToolTextureBrush::updatePanel() +{ + mTable->setRowCount (mBrushHistory.size()); + + mTable->setItem (0, 1, new QTableWidgetItem ( + QApplication::style()->standardIcon (QStyle::SP_TitleBarCloseButton), "")); + + for (int i = mBrushHistory.size()-1; i >= 0; --i) + { + mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i]))); + } +} + +void CSVWidget::SceneToolTextureBrush::updateBrushHistory (const std::string& brushTexture) +{ + mBrushHistory.insert(mBrushHistory.begin(), brushTexture); + if(mBrushHistory.size() > 5) mBrushHistory.pop_back(); +} + +void CSVWidget::SceneToolTextureBrush::clicked (const QModelIndex& index) +{ + if (index.column()==0) + { + std::string brushTexture = mBrushHistory[index.row()]; + std::swap(mBrushHistory[index.row()], mBrushHistory[0]); + mTextureBrushWindow->setBrushTexture(brushTexture); + emit passTextureId(brushTexture); + updatePanel(); + mPanel->hide(); + } + else if (index.column()==1) + { + mPanel->hide(); + } } void CSVWidget::SceneToolTextureBrush::activate () diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 1bf15ead9..982ccc3aa 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -16,10 +16,7 @@ #include "scenetool.hpp" -/*namespace CSVRender -{ - class TerrainTextureMode; -}*/ +class QTableWidget; namespace CSVWidget { @@ -79,6 +76,9 @@ namespace CSVWidget Q_OBJECT QString mToolTip; + QFrame *mPanel; + QTableWidget *mTable; + std::vector mBrushHistory; private: @@ -89,6 +89,7 @@ namespace CSVWidget SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip); virtual void showPanel (const QPoint& position); + void updatePanel (); TextureBrushWindow *mTextureBrushWindow; @@ -97,11 +98,14 @@ namespace CSVWidget public slots: void setButtonIcon(int brushShape); + void updateBrushHistory (const std::string& mBrushTexture); + void clicked (const QModelIndex& index); virtual void activate(); signals: void passEvent(QDropEvent *event); void passEvent(QDragEnterEvent *event); + void passTextureId(std::string brushTexture); }; } From 49ae5bc75c59b2c645267ea535f5753e13299188 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 10 May 2018 22:57:48 +0300 Subject: [PATCH 143/321] List initialization -> initialization in constructor --- apps/opencs/view/widget/scenetooltexturebrush.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index 990963415..2a41ce091 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -139,9 +139,11 @@ void CSVWidget::SceneToolTextureBrush::adjustToolTips() CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip) : SceneTool (parent, Type_TopAction), mToolTip (toolTip), - mBrushHistory{"L0#0"}, mTextureBrushWindow(new TextureBrushWindow(this)) { + mBrushHistory.resize(1); + mBrushHistory[0] = "L0#0"; + setAcceptDrops(true); connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int))); setButtonIcon(mTextureBrushWindow->mBrushShape); From 6630a02c3f268b07d07b57c98b1b42c20c355e22 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 May 2018 09:56:44 +0200 Subject: [PATCH 144/321] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 3b8088c7e..9c6a5edbe 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -157,6 +157,7 @@ Programmers terrorfisch thegriglat Thomas Luppi (Digmaster) + tri4ng1e unelsson Will Herrmann (Thunderforge) Tom Mason (wheybags) From 9126e844bfeb12b4f68e56e88476d536a0ae4156 Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Fri, 11 May 2018 17:24:36 +0300 Subject: [PATCH 145/321] Use data paths from config (bug #4412) --- apps/mwiniimporter/importer.cpp | 37 +++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 74c21da29..3601f0e9b 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -873,8 +873,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co std::time_t defaultTime = 0; ToUTF8::Utf8Encoder encoder(mEncoding); - // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini - const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); + std::vector dataPaths; + if (cfg.count("data")) + { + for (std::string filePathString : cfg["data"]) + { + if (filePathString.front() == '"') + { + filePathString.erase(filePathString.begin()); + filePathString.erase(filePathString.end() - 1); + } + dataPaths.emplace_back(filePathString); + } + } + dataPaths.push_back(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); for (int i=0; it != ini.end(); i++) @@ -893,9 +905,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { - boost::filesystem::path filepath(gameFilesDir); - filepath /= *entry; - contentFiles.push_back({lastWriteTime(filepath, defaultTime), filepath}); + bool found = false; + for (auto & dataPath : dataPaths) + { + boost::filesystem::path path = dataPath / *entry; + std::time_t time = lastWriteTime(path, defaultTime); + if (time != defaultTime) + { + contentFiles.push_back({time, path}); + found = true; + break; + } + } + if (!found) + std::cout << "Warning: " << *entry << " not found, ignoring" << std::endl; } } } @@ -981,9 +1004,5 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << timeStrBuffer << std::endl; } - else - { - std::cout << "content file: " << filename << " not found" << std::endl; - } return writeTime; } From bdfa4308570ba10626af38c3d13c308716d90c0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 13 May 2018 09:24:24 +0200 Subject: [PATCH 146/321] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 9c6a5edbe..17f11730d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -44,6 +44,7 @@ Programmers crussell187 DanielVukelich darkf + David Cernat (davidcernat) devnexen Dieho Dmitry Shkurskiy (endorph) From 1c9fba9a8cc1353708e3ebb26f67c8fa9d332a05 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 12 May 2018 19:02:39 +0300 Subject: [PATCH 147/321] Fix jumping encumbrance calculation --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f3f763897..8e8b5c3ad 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -988,7 +988,7 @@ namespace MWClass const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects(); const float encumbranceTerm = gmst.fJumpEncumbranceBase->getFloat() + gmst.fJumpEncumbranceMultiplier->getFloat() * - (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + (1.0f - Npc::getNormalizedEncumbrance(ptr)); float a = static_cast(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified()); float b = 0.0f; From ba077e72910c59a04e1945108769060c9e3ad2f9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 12 May 2018 19:06:18 +0300 Subject: [PATCH 148/321] Fix movement fatigue loss encumbrance calculation (fixes #4413) --- apps/openmw/mwmechanics/character.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2ef5e07d7..68dc17915 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1751,8 +1751,7 @@ void CharacterController::update(float duration) if (cls.getEncumbrance(mPtr) <= cls.getCapacity(mPtr)) { - const float encumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr); - + const float encumbrance = cls.getNormalizedEncumbrance(mPtr); if (sneak) fatigueLoss = fFatigueSneakBase + encumbrance * fFatigueSneakMult; else From 409d466e42cfa87eb47a2d3526438112e3fe2f5a Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 12 May 2018 20:50:18 +0300 Subject: [PATCH 149/321] Make 0/0 encumbrance 0% encumbrance --- apps/openmw/mwworld/class.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e59dde7b1..5425c2bd3 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -462,10 +462,15 @@ namespace MWWorld float Class::getNormalizedEncumbrance(const Ptr &ptr) const { float capacity = getCapacity(ptr); + float encumbrance = getEncumbrance(ptr); + + if (encumbrance == 0) + return 0.f; + if (capacity == 0) return 1.f; - return getEncumbrance(ptr) / capacity; + return encumbrance / capacity; } std::string Class::getSound(const MWWorld::ConstPtr&) const From e32f38b939dbb8470a598d05a24f8bc310008a38 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 21 Mar 2018 00:19:44 +0300 Subject: [PATCH 150/321] Allow jumping when you're stuck on a slope (fixes #4221) --- apps/openmw/mwphysics/physicssystem.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f3c34bc4e..77e836789 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -308,6 +308,7 @@ namespace MWPhysics float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; + osg::Vec3f inertia = physicActor->getInertialForce(); osg::Vec3f velocity; @@ -320,10 +321,11 @@ namespace MWPhysics { velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; - if (velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope()) + if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope()) + || (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope())) inertia = velocity; - else if(!physicActor->getOnGround() || physicActor->getOnSlope()) - velocity = velocity + physicActor->getInertialForce(); + else if (!physicActor->getOnGround() || physicActor->getOnSlope()) + velocity = velocity + inertia; } // dead actors underwater will float to the surface, if the CharacterController tells us to do so From f8655d2425a8d8a86b8c916b00f5327b1c816228 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 May 2018 20:38:53 +0400 Subject: [PATCH 151/321] Use actor's physics position as a ray origin in tracer --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1cff6b522..412e5e5b3 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -249,7 +249,7 @@ namespace MWPhysics // Check if we actually found a valid spawn point (use an infinitely thin ray this time). // Required for some broken door destinations in Morrowind.esm, where the spawn point // intersects with other geometry if the actor's base is taken into account - btVector3 from = toBullet(position); + btVector3 from = toBullet(position + offset); btVector3 to = from - btVector3(0,0,maxHeight); btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); From 6a3ff5ed81dadd8057f59c8fd9e502a537421d6a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 May 2018 10:10:42 +0400 Subject: [PATCH 152/321] Fix compiler warning in getNestedData --- apps/opencs/model/world/refidadapterimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index ba67b4e14..46d1e5748 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1368,13 +1368,15 @@ QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn const ESM::Creature& creature = record.get(); - if (subRowIndex < 0 || subRowIndex > 2 || subColIndex < 0 || subColIndex > 2) + if (subRowIndex < 0 || subRowIndex > 2) throw std::runtime_error ("index out of range"); if (subColIndex == 0) return subRowIndex + 1; - else if (subColIndex < 3) // 1 or 2 + else if (subColIndex == 1 || subColIndex == 2) return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)]; + else + throw std::runtime_error ("index out of range"); } void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column, From 164e3d12feb079f1d043aea51a7075a013c0834f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 May 2018 11:18:22 +0400 Subject: [PATCH 153/321] Display weapon reach on tooltips in feet. --- apps/openmw/mwclass/weapon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 9fb4a9767..e59567aac 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -325,7 +325,10 @@ namespace MWClass // add reach and attack speed for melee weapon if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game")) { - text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mReach, "#{sRange}"); + // 64 game units = 1 yard = 3 ft, display value in feet + const float combatDistance = store.get().find("fCombatDistance")->getFloat() * ref->mBase->mData.mReach; + text += MWGui::ToolTips::getWeightString(combatDistance*3/64, "#{sRange}"); + text += " #{sFeet}"; text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mSpeed, "#{sAttributeSpeed}"); } From 758ccac75aace490d5d2d3877c2e03823117fc20 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 16 May 2018 11:34:58 +0300 Subject: [PATCH 154/321] Show texture id + filename --- .../opencs/view/render/terraintexturemode.cpp | 2 +- .../view/widget/scenetooltexturebrush.cpp | 62 +++++++++++++------ .../view/widget/scenetooltexturebrush.hpp | 8 ++- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index ea68cfa93..2b5e9ca59 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -49,7 +49,7 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) { if(!mTextureBrushScenetool) { - mTextureBrushScenetool = new CSVWidget::SceneToolTextureBrush (toolbar, "scenetooltexturebrush"); + mTextureBrushScenetool = new CSVWidget::SceneToolTextureBrush (toolbar, "scenetooltexturebrush", getWorldspaceWidget().getDocument()); connect(mTextureBrushScenetool, SIGNAL (clicked()), mTextureBrushScenetool, SLOT (activate())); connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index 2a41ce091..003ab12fd 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -21,6 +21,11 @@ #include #include "scenetool.hpp" +#include "../../model/doc/document.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/landtexture.hpp" + CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) : QGroupBox(title, parent) @@ -45,14 +50,21 @@ CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p setLayout(mLayoutSliderSize); } -CSVWidget::TextureBrushWindow::TextureBrushWindow(QWidget *parent) +CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent) : QFrame(parent, Qt::Popup), mBrushShape(0), mBrushSize(0), - mBrushTexture("L0#0") + mBrushTexture("L0#0"), + mDocument(document) { - mBrushTextureLabel = "Selected texture (id): " + mBrushTexture; - mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel), this); + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + + int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + + QModelIndex index = ltexTable.getModelIndex (mBrushTexture, landTextureFilename); + mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; + mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + ltexTable.data(index).value()); QVBoxLayout *layoutMain = new QVBoxLayout; layoutMain->setSpacing(0); @@ -111,10 +123,16 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton * void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) { + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + mBrushTexture = brushTexture; - mBrushTextureLabel = "Selected texture (id): " + mBrushTexture; - mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); + mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; + QModelIndex index = ltexTable.getModelIndex (mBrushTexture, landTextureFilename); + mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + ltexTable.data(index).value()); emit passBrushShape(mBrushShape); // update icon + } void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize) @@ -136,10 +154,11 @@ void CSVWidget::SceneToolTextureBrush::adjustToolTips() { } -CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip) +CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip, CSMDoc::Document& document) : SceneTool (parent, Type_TopAction), mToolTip (toolTip), - mTextureBrushWindow(new TextureBrushWindow(this)) + mDocument (document), + mTextureBrushWindow(new TextureBrushWindow(document, this)) { mBrushHistory.resize(1); mBrushHistory[0] = "L0#0"; @@ -161,10 +180,10 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, c mTable->horizontalHeader()->hide(); #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) mTable->horizontalHeader()->setSectionResizeMode (0, QHeaderView::Stretch); - mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents); + mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::Stretch); #else mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch); - mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); + mTable->horizontalHeader()->setResizeMode (1, QHeaderView::Stretch); #endif mTable->setSelectionMode (QAbstractItemView::NoSelection); @@ -198,7 +217,14 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); tooltip += dynamic_cast (mTextureBrushWindow->toolTipCustom); } - tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture); + tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " "; + + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + QModelIndex index = ltexTable.getModelIndex (mTextureBrushWindow->mBrushTexture, landTextureFilename); + tooltip += ltexTable.data(index).value(); + tooltip += "
(drop texture here to change)"; setToolTip (tooltip); } @@ -214,11 +240,13 @@ void CSVWidget::SceneToolTextureBrush::updatePanel() { mTable->setRowCount (mBrushHistory.size()); - mTable->setItem (0, 1, new QTableWidgetItem ( - QApplication::style()->standardIcon (QStyle::SP_TitleBarCloseButton), "")); - for (int i = mBrushHistory.size()-1; i >= 0; --i) { + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + QModelIndex index = ltexTable.getModelIndex (mBrushHistory[i], landTextureFilename); + mTable->setItem (i, 1, new QTableWidgetItem (ltexTable.data(index).value())); mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i]))); } } @@ -231,7 +259,7 @@ void CSVWidget::SceneToolTextureBrush::updateBrushHistory (const std::string& br void CSVWidget::SceneToolTextureBrush::clicked (const QModelIndex& index) { - if (index.column()==0) + if (index.column()==0 || index.column()==1) { std::string brushTexture = mBrushHistory[index.row()]; std::swap(mBrushHistory[index.row()], mBrushHistory[0]); @@ -240,10 +268,6 @@ void CSVWidget::SceneToolTextureBrush::clicked (const QModelIndex& index) updatePanel(); mPanel->hide(); } - else if (index.column()==1) - { - mPanel->hide(); - } } void CSVWidget::SceneToolTextureBrush::activate () diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 982ccc3aa..1c0e0a334 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -16,6 +16,8 @@ #include "scenetool.hpp" +#include "../../model/doc/document.hpp" + class QTableWidget; namespace CSVWidget @@ -40,7 +42,7 @@ namespace CSVWidget Q_OBJECT public: - TextureBrushWindow(QWidget *parent = 0); + TextureBrushWindow(CSMDoc::Document& document, QWidget *parent = 0); void configureButtonInitialSettings(QPushButton *button); QPushButton *mButtonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); @@ -57,6 +59,7 @@ namespace CSVWidget std::string mBrushTexture; private: + CSMDoc::Document& mDocument; QLabel *mSelectedBrush; QGroupBox *mHorizontalGroupBox; std::string mBrushTextureLabel; @@ -76,6 +79,7 @@ namespace CSVWidget Q_OBJECT QString mToolTip; + CSMDoc::Document& mDocument; QFrame *mPanel; QTableWidget *mTable; std::vector mBrushHistory; @@ -86,7 +90,7 @@ namespace CSVWidget public: - SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip); + SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip, CSMDoc::Document& document); virtual void showPanel (const QPoint& position); void updatePanel (); From 17e01ca336ae232114666866b92f949c5278ad71 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 16 May 2018 11:41:37 +0300 Subject: [PATCH 155/321] Setting "Scene Drops" rename "3D Scene Editing" --- apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/view/render/instancemode.cpp | 4 ++-- apps/opencs/view/render/terraintexturemode.cpp | 6 +++--- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 6cbc33766..99cbd98db 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -230,7 +230,7 @@ void CSMPrefs::State::declare() EnumValues landeditOutsideVisibleCell; landeditOutsideVisibleCell.add (showAndLandEdit).add (dontLandEdit); - declareCategory ("Scene Drops"); + declareCategory ("3D Scene Editing"); declareInt ("distance", "Drop Distance", 50). setTooltip ("If an instance drop can not be placed against another object at the " "insert point, it will be placed by this distance from the insert point instead"); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index ee3e18d71..4b14e29bf 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -551,7 +551,7 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) if (noCell) { - std::string mode = CSMPrefs::get()["Scene Drops"]["outside-drop"].toString(); + std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-drop"].toString(); // target cell does not exist if (mode=="Discard") @@ -585,7 +585,7 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) { // target cell exists, but is not shown std::string mode = - CSMPrefs::get()["Scene Drops"]["outside-visible-drop"].toString(); + CSMPrefs::get()["3D Scene Editing"]["outside-visible-drop"].toString(); if (mode=="Discard") return; diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 2b5e9ca59..c7ffe6b38 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -428,7 +428,7 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) if (noCell) { - std::string mode = CSMPrefs::get()["Scene Drops"]["outside-landedit"].toString(); + std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-landedit"].toString(); // target cell does not exist if (mode=="Discard") @@ -460,7 +460,7 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) { // target cell exists, but is not shown std::string mode = - CSMPrefs::get()["Scene Drops"]["outside-visible-landedit"].toString(); + CSMPrefs::get()["3D Scene Editing"]["outside-visible-landedit"].toString(); if (mode=="Discard") return false; @@ -475,7 +475,7 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) if (noLand) { - std::string mode = CSMPrefs::get()["Scene Drops"]["outside-landedit"].toString(); + std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-landedit"].toString(); // target cell does not exist if (mode=="Discard") diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index c2a6617c1..084fb87e6 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -445,7 +445,7 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo // Default placement direction.normalize(); - direction *= CSMPrefs::get()["Scene Drops"]["distance"].toInt(); + direction *= CSMPrefs::get()["3D Scene Editing"]["distance"].toInt(); WorldspaceHitResult hit = { false, 0, 0, 0, 0, start + direction }; return hit; From df459199dd2bfedbc6580d009b3e85c13e85509e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 May 2018 12:59:05 +0400 Subject: [PATCH 156/321] Avoid left shift of negative value --- apps/openmw/mwrender/globalmap.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 24f6de6ce..af2bb101a 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -125,7 +125,7 @@ namespace MWRender { for (int cellX=0; cellX(float(cellX)/float(mCellSize) * 9); + int vertexX = static_cast(float(cellX) / float(mCellSize) * 9); int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); int texelX = (x-mMinX) * mCellSize + cellX; @@ -135,9 +135,9 @@ namespace MWRender float y2 = 0; if (land && (land->mDataTypes & ESM::Land::DATA_WNAM)) - y2 = (land->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; + y2 = land->mWnam[vertexY * 9 + vertexX] / 128.f; else - y2 = (SCHAR_MIN << 4) / 2048.f; + y2 = SCHAR_MIN / 128.f; if (y2 < 0) { r = static_cast(14 * y2 + 38); From e5db5e2651c9843843524aba28c5a8450b2d1b54 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 May 2018 16:13:22 +0400 Subject: [PATCH 157/321] Fix 'maybe-uninitialized' warning in openal_output --- apps/openmw/mwsound/openal_output.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 829c001e5..a8a541704 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -951,10 +951,11 @@ std::pair OpenAL_Output::loadSound(const std::string &fname getALError(); std::vector data; - ALenum format; + ALenum format = AL_NONE; int srate; - try { + try + { DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. if(decoder->mResourceMgr->exists(fname)) @@ -974,7 +975,8 @@ std::pair OpenAL_Output::loadSound(const std::string &fname format = getALFormat(chans, type); if(format) decoder->readAll(data); } - catch(std::exception &e) { + catch(std::exception &e) + { std::cerr<< "Failed to load audio from "< Date: Wed, 16 May 2018 16:34:58 +0400 Subject: [PATCH 158/321] Initialize srate variable in openal_output --- apps/openmw/mwsound/openal_output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a8a541704..31d46ce31 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -952,7 +952,7 @@ std::pair OpenAL_Output::loadSound(const std::string &fname std::vector data; ALenum format = AL_NONE; - int srate; + int srate = 0; try { From 4e485dbd4466f1ec075e4ad82dd7fb469e3f7d14 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 17 May 2018 12:57:58 +0300 Subject: [PATCH 159/321] Rename Original Creature column to Parent Creature (fixes #2897) --- apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7c0fbff4b..109708ab0 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -105,7 +105,7 @@ namespace CSMWorld { ColumnId_Respawn, "Respawn" }, { ColumnId_CreatureType, "Creature Type" }, { ColumnId_SoulPoints, "Soul Points" }, - { ColumnId_OriginalCreature, "Original Creature" }, + { ColumnId_ParentCreature, "Parent Creature" }, { ColumnId_Biped, "Biped" }, { ColumnId_HasWeapon, "Has Weapon" }, { ColumnId_Swims, "Swims" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 15018795c..f9ba5725a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -99,7 +99,7 @@ namespace CSMWorld ColumnId_Respawn = 84, ColumnId_CreatureType = 85, ColumnId_SoulPoints = 86, - ColumnId_OriginalCreature = 87, + ColumnId_ParentCreature = 87, ColumnId_Biped = 88, ColumnId_HasWeapon = 89, // unused diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 44a6ce07d..60a513cb6 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -331,7 +331,7 @@ CSMWorld::RefIdCollection::RefIdCollection() creatureColumns.mType = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); creatureColumns.mScale = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_ParentCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); static const struct From 3b86f73ae71eb6129c3f7209e01f6ad2c2f725fb Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Thu, 17 May 2018 21:04:40 +0300 Subject: [PATCH 160/321] Replace MwIniImporter::numberToString with std::to_string --- apps/mwiniimporter/importer.cpp | 10 ++-------- apps/mwiniimporter/importer.hpp | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 3601f0e9b..3433fe5c7 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -654,12 +654,6 @@ void MwIniImporter::setVerbose(bool verbose) { mVerbose = verbose; } -std::string MwIniImporter::numberToString(int n) { - std::stringstream str; - str << n; - return str.str(); -} - MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; @@ -801,7 +795,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { archive = baseArchive; - archive.append(this->numberToString(i)); + archive.append(std::to_string(i)); it = ini.find(archive); if(it == ini.end()) { @@ -892,7 +886,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co for (int i=0; it != ini.end(); i++) { gameFile = baseGameFile; - gameFile.append(this->numberToString(i)); + gameFile.append(std::to_string(i)); it = ini.find(gameFile); if(it == ini.end()) diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index e1595ad96..d99866533 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -35,7 +35,6 @@ class MwIniImporter { static std::vector::iterator findString(std::vector& source, const std::string& string); static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); - static std::string numberToString(int n); /// \return file's "last modified time", used in original MW to determine plug-in load order static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); From 7e03dd0f1247f152e10bf6e09ec7478b2972da00 Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Thu, 17 May 2018 21:07:20 +0300 Subject: [PATCH 161/321] Read data paths from `data-local` section too --- apps/mwiniimporter/importer.cpp | 27 ++++++++++++++++----------- apps/mwiniimporter/importer.hpp | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 3433fe5c7..6f5c2e2cd 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -859,6 +859,17 @@ std::vector::iterator MwIniImporter::findString(std::vector& output, std::vector input) { + for (auto& path : input) { + if (path.front() == '"') + { + path.erase(path.begin()); + path.erase(path.end() - 1); + } + output.emplace_back(path); + } +} + void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { std::vector> contentFiles; @@ -869,17 +880,11 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co std::vector dataPaths; if (cfg.count("data")) - { - for (std::string filePathString : cfg["data"]) - { - if (filePathString.front() == '"') - { - filePathString.erase(filePathString.begin()); - filePathString.erase(filePathString.end() - 1); - } - dataPaths.emplace_back(filePathString); - } - } + addPaths(dataPaths, cfg["data"]); + + if (cfg.count("data-local")) + addPaths(dataPaths, cfg["data-local"]); + dataPaths.push_back(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index d99866533..7b710a4a4 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -35,6 +35,7 @@ class MwIniImporter { static std::vector::iterator findString(std::vector& source, const std::string& string); static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); + static void addPaths(std::vector& output, std::vector input); /// \return file's "last modified time", used in original MW to determine plug-in load order static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); From f2613a74b1fb329cd66f1ffdbb47a6e102d378ec Mon Sep 17 00:00:00 2001 From: tri4ng1e Date: Thu, 17 May 2018 21:20:04 +0300 Subject: [PATCH 162/321] Write settings before invoking openmw-iniimporter --- apps/wizard/mainwizard.cpp | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 0f8fb0c49..57d080cf8 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -231,29 +231,13 @@ void Wizard::MainWizard::setupInstallations() void Wizard::MainWizard::runSettingsImporter() { + writeSettings(); + QString path(field(QLatin1String("installation.path")).toString()); - // Create the file if it doesn't already exist, else the importer will fail QString userPath(toQString(mCfgMgr.getUserConfigPath())); QFile file(userPath + QLatin1String("openmw.cfg")); - if (!file.exists()) { - if (!file.open(QIODevice::ReadWrite)) { - // File cannot be created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("

Could not open or create %1 for writing

\ -

Please make sure you have the right permissions \ - and try again.

").arg(file.fileName())); - msgBox.exec(); - return qApp->quit(); - } - - file.close(); - } - // Construct the arguments to run the importer QStringList arguments; From c2cddc91e42768b67f93be0a51f5d9c1491248fd Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 18 May 2018 11:32:42 +0300 Subject: [PATCH 163/321] Brush maximum size to a custom setting --- apps/opencs/model/prefs/state.cpp | 2 ++ apps/opencs/view/widget/scenetooltexturebrush.cpp | 8 ++++++-- apps/opencs/view/widget/scenetooltexturebrush.hpp | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 99cbd98db..6f64da72e 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -242,6 +242,8 @@ void CSMPrefs::State::declare() addValues (landeditOutsideCell); declareEnum ("outside-visible-landedit", "Handling land edit outside of visible cells", showAndLandEdit). addValues (landeditOutsideVisibleCell); + declareInt ("texturebrush-maximumsize", "Maximum texture brush size", 50). + setMin (1); declareCategory ("Key Bindings"); diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index 003ab12fd..76727a7a9 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -21,7 +21,9 @@ #include #include "scenetool.hpp" + #include "../../model/doc/document.hpp" +#include "../../model/prefs/state.hpp" #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/landtexture.hpp" @@ -33,11 +35,11 @@ CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p mBrushSizeSlider = new QSlider(Qt::Horizontal); mBrushSizeSlider->setTickPosition(QSlider::TicksBothSides); mBrushSizeSlider->setTickInterval(10); - mBrushSizeSlider->setRange(1, 50); + mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt()); mBrushSizeSlider->setSingleStep(1); mBrushSizeSpinBox = new QSpinBox; - mBrushSizeSpinBox->setRange(1, 50); + mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt()); mBrushSizeSpinBox->setSingleStep(1); mLayoutSliderSize = new QHBoxLayout; @@ -273,6 +275,8 @@ void CSVWidget::SceneToolTextureBrush::clicked (const QModelIndex& index) void CSVWidget::SceneToolTextureBrush::activate () { QPoint position = QCursor::pos(); + mTextureBrushWindow->mSizeSliders->mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt()); + mTextureBrushWindow->mSizeSliders->mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt()); mTextureBrushWindow->move (position); mTextureBrushWindow->show(); } diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 1c0e0a334..33a6dc2de 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -30,9 +30,9 @@ namespace CSVWidget public: BrushSizeControls(const QString &title, QWidget *parent); QSlider *mBrushSizeSlider; + QSpinBox *mBrushSizeSpinBox; private: - QSpinBox *mBrushSizeSpinBox; QHBoxLayout *mLayoutSliderSize; }; From 867a5938caffc9e0ad8a7f6a2ef7fda195a8e82a Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 20 May 2018 10:24:20 +0300 Subject: [PATCH 164/321] Don't reset sneaking camera offset while in GUI (fixes #4420) --- apps/openmw/mwworld/worldimp.cpp | 6 +++--- apps/openmw/mwworld/worldimp.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 13bfc32b3..6cf1ead87 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1621,7 +1621,7 @@ namespace MWWorld if (!paused) doPhysics (duration); - updatePlayer(paused); + updatePlayer(); mPhysics->debugDraw(); @@ -1637,7 +1637,7 @@ namespace MWWorld } } - void World::updatePlayer(bool paused) + void World::updatePlayer() { MWWorld::Ptr player = getPlayerPtr(); @@ -1670,7 +1670,7 @@ namespace MWWorld bool swimming = isSwimming(player); static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); - if(!paused && sneaking && !(swimming || inair)) + if (sneaking && !(swimming || inair)) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else mRendering->getCamera()->setSneakOffset(0.f); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 40a22af5d..0d168c912 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -129,7 +129,7 @@ namespace MWWorld Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos); void updateSoundListener(); - void updatePlayer(bool paused); + void updatePlayer(); void preloadSpells(); From f8304a52c489711a6ea97dc15966d0e51749dff6 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 17:04:52 +0200 Subject: [PATCH 165/321] Enable verbose logging for CI --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d8f2bfc35..42aabab37 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ install: - set PATH=C:\Program Files\Git\mingw64\bin;%PATH% before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% -v %msvc% + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% -v %msvc% -V build_script: - cmd: if %PLATFORM%==Win32 set build=MSVC%msvc%_32 From ea6c73333b6cbd6745b0eeed6c543ffede34f4fb Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 17:14:32 +0200 Subject: [PATCH 166/321] Bumping Qt to 5.10 for Appveyor --- CI/before_script.msvc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index a0cf06919..9b564a180 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -568,7 +568,7 @@ echo if [ -z $APPVEYOR ]; then printf "Qt 5.7.0... " else - printf "Qt 5.7 AppVeyor... " + printf "Qt 5.10 AppVeyor... " fi { if [ $BITS -eq 64 ]; then @@ -618,7 +618,7 @@ fi echo Done. else - QT_SDK="C:/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}" + QT_SDK="C:/Qt/5.10/msvc${MSVC_YEAR}${SUFFIX}" add_cmake_opts -DDESIRED_QT_VERSION=5 \ -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \ From 12b201348a6cf1b2f6e668654fd54396181c6b15 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 17:17:04 +0200 Subject: [PATCH 167/321] Switch to the supported VS versions on Appveyor --- appveyor.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 42aabab37..bce288a57 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,12 +8,12 @@ branches: environment: matrix: - - msvc: 2013 - msvc: 2015 + - msvc: 2017 platform: - - Win32 -# - x64 +# - Win32 + - x64 configuration: - Debug @@ -27,16 +27,10 @@ os: Visual Studio 2015 clone_depth: 1 cache: - - C:\projects\openmw\deps\Bullet-2.83.7-msvc2013-win32.7z - - C:\projects\openmw\deps\Bullet-2.83.7-msvc2013-win64.7z - C:\projects\openmw\deps\Bullet-2.83.7-msvc2015-win32.7z - C:\projects\openmw\deps\Bullet-2.83.7-msvc2015-win64.7z - - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2013-win32.7z - - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2013-win32.7z - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2015-win64.7z - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2015-win64.7z - - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2013-win32.7z - - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2013-win32.7z - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2015-win64.7z - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2015-win64.7z - C:\projects\openmw\deps\ffmpeg-3.0.1-dev-win32.7z From e1e7a4b11adeeb51e4d565b5050f87268535bdd1 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 18:04:59 +0200 Subject: [PATCH 168/321] Change Appveyor to use Visual Studio 2017 --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index bce288a57..ca6a59585 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ branches: environment: matrix: - - msvc: 2015 +# - msvc: 2015 - msvc: 2017 platform: @@ -20,7 +20,7 @@ configuration: # - Release # For the Qt, Boost, CMake, etc installs -os: Visual Studio 2015 +os: Visual Studio 2017 # We want the git revision for versioning, # so shallow clones don't work. From 4b1247597ea82c9c77cfe40ff2e88db885e84fe4 Mon Sep 17 00:00:00 2001 From: declan-millar Date: Sun, 20 May 2018 17:06:26 +0100 Subject: [PATCH 169/321] Use soulgem value rebalance formula from morrowind code patch --- apps/openmw/mwclass/misc.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 5a933d535..4b1a8844d 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -84,8 +84,19 @@ namespace MWClass if (ptr.getCellRef().getSoul() != "") { const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().search(ref->mRef.getSoul()); - if (creature) - value *= creature->mData.mSoul; + if (creature) { + // value *= creature->mData.mSoul; + + // use soulgem value rebalance formula from morrowind code patch + int soul = creature->mData.mSoul; + float soul_value = 0.0001 * pow(soul, 3) + 2 * soul; + + // for Azura's star add the unfilled value + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "Misc_SoulGem_Azura")) + value += soul_value; + else + value = soul_value; + } } return value; From bcfa2a13a6b3fa02f1691bf6fcf3dc6ed07bbc26 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 18:09:31 +0200 Subject: [PATCH 170/321] Use the VS2017 packaging of Qt5 for Appveyor --- CI/before_script.msvc.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 9b564a180..3b4b23027 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -385,7 +385,7 @@ else if [ $MSVC_VER -eq 12 ]; then printf "Boost 1.58.0 AppVeyor... " else - printf "Boost 1.60.0 AppVeyor... " + printf "Boost 1.67.0 AppVeyor... " fi fi { @@ -411,7 +411,7 @@ fi if [ $MSVC_VER -eq 12 ]; then BOOST_SDK="c:/Libraries/boost_1_58_0" else - BOOST_SDK="c:/Libraries/boost_1_60_0" + BOOST_SDK="c:/Libraries/boost_1_67_0" fi add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ -DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.0" @@ -618,7 +618,7 @@ fi echo Done. else - QT_SDK="C:/Qt/5.10/msvc${MSVC_YEAR}${SUFFIX}" + QT_SDK="C:/Qt/5.10/msvc${MSVC_DISPLAY_YEAR}${SUFFIX}" add_cmake_opts -DDESIRED_QT_VERSION=5 \ -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \ From 3bd8dc3ef6e4a178e715133c06ae562fc43ea9d4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 18:22:02 +0200 Subject: [PATCH 171/321] Use the right boost version for Appveyor --- CI/before_script.msvc.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3b4b23027..a4a436b48 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -216,6 +216,7 @@ case $VS_VERSION in 15|15.0|2017 ) GENERATOR="Visual Studio 15 2017" TOOLSET="vc140" + MSVC_REAL_VER="15" MSVC_VER="14" MSVC_YEAR="2015" MSVC_DISPLAY_YEAR="2017" @@ -224,6 +225,7 @@ case $VS_VERSION in 14|14.0|2015 ) GENERATOR="Visual Studio 14 2015" TOOLSET="vc140" + MSVC_REAL_VER="14" MSVC_VER="14" MSVC_YEAR="2015" MSVC_DISPLAY_YEAR="2015" @@ -232,6 +234,7 @@ case $VS_VERSION in 12|12.0|2013 ) GENERATOR="Visual Studio 12 2013" TOOLSET="vc120" + MSVC_REAL_VER="12" MSVC_VER="12" MSVC_YEAR="2013" MSVC_DISPLAY_YEAR="2013" @@ -408,13 +411,19 @@ fi echo Done. else # Appveyor unstable has all the boost we need already - if [ $MSVC_VER -eq 12 ]; then + if [ $MSVC_REAL_VER -eq 12 ]; then BOOST_SDK="c:/Libraries/boost_1_58_0" else BOOST_SDK="c:/Libraries/boost_1_67_0" fi + if [ $MSVC_REAL_VER -eq 15 ]; then + LIB_SUFFIX="1" + else + LIB_SUFFIX="0" + fi + add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ - -DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.0" + -DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.${LIB_SUFFIX}" add_cmake_opts -DBoost_COMPILER="-${TOOLSET}" echo Done. From 4f758bdd4800fd6323f51c683a65bab2cdd6f91f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 18:24:06 +0200 Subject: [PATCH 172/321] Use different environments for 2015 and 2017 --- appveyor.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ca6a59585..eae4bd5b1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,8 +8,10 @@ branches: environment: matrix: -# - msvc: 2015 + - msvc: 2015 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - msvc: 2017 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 platform: # - Win32 @@ -20,7 +22,7 @@ configuration: # - Release # For the Qt, Boost, CMake, etc installs -os: Visual Studio 2017 +#os: Visual Studio 2017 # We want the git revision for versioning, # so shallow clones don't work. From d05de8e4114d28a7e10d8d4d0d7e679d4b643348 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 20 May 2018 18:51:28 +0200 Subject: [PATCH 173/321] Give boost the correct toolset for 2017 --- CI/before_script.msvc.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index a4a436b48..9c12c45db 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -216,6 +216,7 @@ case $VS_VERSION in 15|15.0|2017 ) GENERATOR="Visual Studio 15 2017" TOOLSET="vc140" + TOOLSET_REAL="vc141" MSVC_REAL_VER="15" MSVC_VER="14" MSVC_YEAR="2015" @@ -225,6 +226,7 @@ case $VS_VERSION in 14|14.0|2015 ) GENERATOR="Visual Studio 14 2015" TOOLSET="vc140" + TOOLSET_REAL="vc140" MSVC_REAL_VER="14" MSVC_VER="14" MSVC_YEAR="2015" @@ -234,6 +236,7 @@ case $VS_VERSION in 12|12.0|2013 ) GENERATOR="Visual Studio 12 2013" TOOLSET="vc120" + TOOLSET_REAL="vc120" MSVC_REAL_VER="12" MSVC_VER="12" MSVC_YEAR="2013" @@ -424,7 +427,7 @@ fi add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \ -DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.${LIB_SUFFIX}" - add_cmake_opts -DBoost_COMPILER="-${TOOLSET}" + add_cmake_opts -DBoost_COMPILER="-${TOOLSET_REAL}" echo Done. fi From 21e8d08e69bbf9968ffea15104569153084eb79a Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 20 May 2018 21:20:40 +0300 Subject: [PATCH 174/321] Handle invalid texture id's --- .../opencs/view/render/terraintexturemode.cpp | 52 +++++++++--- .../view/widget/scenetooltexturebrush.cpp | 81 +++++++++++++------ 2 files changed, 96 insertions(+), 37 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index c7ffe6b38..dac744ae6 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -38,7 +38,7 @@ CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent), - mBrushTexture("#0"), + mBrushTexture("L0#0"), mBrushSize(0), mBrushShape(0), mTextureBrushScenetool(0) @@ -87,13 +87,19 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult mCellId = getWorldspaceWidget().getCellId (hit.worldPos); QUndoStack& undoStack = document.getUndoStack(); - undoStack.beginMacro ("Edit texture records"); - if(allowLandTextureEditing(mCellId)==true) + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); - editTerrainTextureGrid(hit); + undoStack.beginMacro ("Edit texture records"); + if(allowLandTextureEditing(mCellId)==true) + { + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); + editTerrainTextureGrid(hit); + } + undoStack.endMacro(); } - undoStack.endMacro(); } void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) @@ -117,11 +123,18 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) mCellId = getWorldspaceWidget().getCellId (hit.worldPos); QUndoStack& undoStack = document.getUndoStack(); - undoStack.beginMacro ("Edit texture records"); - if(allowLandTextureEditing(mCellId)==true) + + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); - editTerrainTextureGrid(hit); + undoStack.beginMacro ("Edit texture records"); + if(allowLandTextureEditing(mCellId)==true) + { + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); + editTerrainTextureGrid(hit); + } } return true; @@ -145,13 +158,28 @@ bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos) void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) { WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); - editTerrainTextureGrid(hit); + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + editTerrainTextureGrid(hit); + } } void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) { CSMDoc::Document& document = getWorldspaceWidget().getDocument(); QUndoStack& undoStack = document.getUndoStack(); - undoStack.endMacro(); + + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + undoStack.endMacro(); + } } void CSVRender::TerrainTextureMode::dragAborted() { diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index 76727a7a9..a58b98bdd 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -25,8 +25,10 @@ #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" #include "../../model/world/data.hpp" +#include "../../model/world/idcollection.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/landtexture.hpp" +#include "../../model/world/universalid.hpp" CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent) @@ -59,14 +61,21 @@ CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QW mBrushTexture("L0#0"), mDocument(document) { - CSMWorld::IdTable& ltexTable = dynamic_cast ( - *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; - int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); - QModelIndex index = ltexTable.getModelIndex (mBrushTexture, landTextureFilename); - mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; - mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + ltexTable.data(index).value()); + int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value()); + } else + { + mBrushTextureLabel = "No selected texture or invalid texture"; + mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel)); + } QVBoxLayout *layoutMain = new QVBoxLayout; layoutMain->setSpacing(0); @@ -125,16 +134,22 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton * void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) { - CSMWorld::IdTable& ltexTable = dynamic_cast ( - *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); - int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + int index = landtexturesCollection.searchId(mBrushTexture); mBrushTexture = brushTexture; - mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; - QModelIndex index = ltexTable.getModelIndex (mBrushTexture, landTextureFilename); - mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + ltexTable.data(index).value()); - emit passBrushShape(mBrushShape); // update icon + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value()); + } else + { + mBrushTextureLabel = "No selected texture or invalid texture"; + mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel)); + } + + emit passBrushShape(mBrushShape); // update icon } void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize) @@ -219,13 +234,22 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); tooltip += dynamic_cast (mTextureBrushWindow->toolTipCustom); } - tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " "; - CSMWorld::IdTable& ltexTable = dynamic_cast ( - *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); - int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); - QModelIndex index = ltexTable.getModelIndex (mTextureBrushWindow->mBrushTexture, landTextureFilename); - tooltip += ltexTable.data(index).value(); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + + int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + int index = landtexturesCollection.searchId(mTextureBrushWindow->mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + //QModelIndex qIndex = landtexturesCollection.getModelIndex (mBrushTexture, landTextureFilename); + tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " "; + + tooltip += landtexturesCollection.getData(index, landTextureFilename).value(); + } else + { + tooltip += "No selected texture or invalid texture"; + } tooltip += "
(drop texture here to change)"; setToolTip (tooltip); @@ -244,12 +268,19 @@ void CSVWidget::SceneToolTextureBrush::updatePanel() for (int i = mBrushHistory.size()-1; i >= 0; --i) { - CSMWorld::IdTable& ltexTable = dynamic_cast ( - *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); - int landTextureFilename = ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); - QModelIndex index = ltexTable.getModelIndex (mBrushHistory[i], landTextureFilename); - mTable->setItem (i, 1, new QTableWidgetItem (ltexTable.data(index).value())); - mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i]))); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + int index = landtexturesCollection.searchId(mBrushHistory[i]); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + mTable->setItem (i, 1, new QTableWidgetItem (landtexturesCollection.getData(index, landTextureFilename).value())); + mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i]))); + } else + { + mTable->setItem (i, 1, new QTableWidgetItem ("Invalid/deleted texture")); + mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i]))); + } } } From 8ae46519cf3df1ea4a136c49532218f6938351a7 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 20 May 2018 21:58:40 +0300 Subject: [PATCH 175/321] Fix missed worldspacehits, add linebreak to tooltip --- apps/opencs/view/render/terraintexturemode.cpp | 6 +++--- apps/opencs/view/widget/scenetooltexturebrush.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index dac744ae6..d312c28d9 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -90,7 +90,7 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); int index = landtexturesCollection.searchId(mBrushTexture); - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true) { undoStack.beginMacro ("Edit texture records"); if(allowLandTextureEditing(mCellId)==true) @@ -130,7 +130,7 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { undoStack.beginMacro ("Edit texture records"); - if(allowLandTextureEditing(mCellId)==true) + if(allowLandTextureEditing(mCellId)==true && hit.hit == true) { undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); editTerrainTextureGrid(hit); @@ -163,7 +163,7 @@ void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diff CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); int index = landtexturesCollection.searchId(mBrushTexture); - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true) { editTerrainTextureGrid(hit); } diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index a58b98bdd..d8d4600e5 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -248,7 +248,7 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) tooltip += landtexturesCollection.getData(index, landTextureFilename).value(); } else { - tooltip += "No selected texture or invalid texture"; + tooltip += "

No selected texture or invalid texture"; } tooltip += "
(drop texture here to change)"; From 78e79d577535098c0be8747257ab7a7aabf28b5c Mon Sep 17 00:00:00 2001 From: declan-millar Date: Mon, 21 May 2018 13:33:42 +0100 Subject: [PATCH 176/321] Add advanced option to Rebalance soulgem values to the launcher --- apps/launcher/advancedpage.cpp | 2 ++ apps/openmw/mwclass/misc.cpp | 6 +++--- files/settings-default.cfg | 3 +++ files/ui/advancedpage.ui | 10 ++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 9b6e5fa8c..dcf376362 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -23,6 +23,7 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game"); loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); + loadSettingBool(rebalanceSoulgemValuesCheckBox, "rebalance soulgem values", "Game"); // Expected values are (0, 1, 2, 3) int showOwnedIndex = mEngineSettings.getInt("show owned", "Game"); @@ -61,6 +62,7 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game"); saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); + saveSettingBool(rebalanceSoulgemValuesCheckBox, "rebalance soulgem values", "Game"); int showOwnedCurrentIndex = showOwnedComboBox->currentIndex(); if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game")) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 4b1a8844d..d2f5d35ba 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -89,13 +89,13 @@ namespace MWClass // use soulgem value rebalance formula from morrowind code patch int soul = creature->mData.mSoul; - float soul_value = 0.0001 * pow(soul, 3) + 2 * soul; + float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; // for Azura's star add the unfilled value if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "Misc_SoulGem_Azura")) - value += soul_value; + value += soulValue; else - value = soul_value; + value = soulValue; } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 87443ff1a..a2524ff17 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -216,6 +216,9 @@ followers attack on sight = false # Can loot non-fighting actors during death animation can loot during death animation = true +# Makes the value of filled soulgems dependent only on soul magnitude (with formula from the Morrowind Code Patch) +rebalance soulgem values = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 6832b86df..28d0f0543 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -109,6 +109,16 @@ + + + + <html><head/><body><p>If this setting is true, the value of filled soulgems is dependent only on soul magnitude.</p><p>The default value is false.</p></body></html> + + + Rebalance soulgem values + + + From 9346a552fa1808372899602b1f3eb7125bcde6b3 Mon Sep 17 00:00:00 2001 From: declan-millar Date: Mon, 21 May 2018 13:59:20 +0100 Subject: [PATCH 177/321] Use Rebalance soulgem values option to set soulgem value --- apps/openmw/mwclass/misc.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index d2f5d35ba..8e39b44e9 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -1,6 +1,7 @@ #include "misc.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -84,18 +85,22 @@ namespace MWClass if (ptr.getCellRef().getSoul() != "") { const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().search(ref->mRef.getSoul()); - if (creature) { - // value *= creature->mData.mSoul; - - // use soulgem value rebalance formula from morrowind code patch - int soul = creature->mData.mSoul; - float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; - - // for Azura's star add the unfilled value - if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "Misc_SoulGem_Azura")) - value += soulValue; + if (creature) + { + if (Settings::Manager::getBool("rebalance soulgem values", "Game")) + { + // use soulgem value rebalance formula from morrowind code patch + int soul = creature->mData.mSoul; + float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; + + // for Azura's star add the unfilled value + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "Misc_SoulGem_Azura")) + value += soulValue; + else + value = soulValue; + } else - value = soulValue; + value *= creature->mData.mSoul; } } From 028b528c0bc253ac2446173bfd52406935f2526a Mon Sep 17 00:00:00 2001 From: declan-millar Date: Mon, 21 May 2018 18:16:04 +0100 Subject: [PATCH 178/321] Get soul magnitude before checking the rebalance setting --- apps/openmw/mwclass/misc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8e39b44e9..c7e0796d5 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -87,10 +87,10 @@ namespace MWClass const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().search(ref->mRef.getSoul()); if (creature) { + int soul = creature->mData.mSoul; if (Settings::Manager::getBool("rebalance soulgem values", "Game")) { // use soulgem value rebalance formula from morrowind code patch - int soul = creature->mData.mSoul; float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; // for Azura's star add the unfilled value @@ -100,7 +100,7 @@ namespace MWClass value = soulValue; } else - value *= creature->mData.mSoul; + value *= soul; } } From 9ed4f330488342834e0301d3d50e223dcf889045 Mon Sep 17 00:00:00 2001 From: declan-millar Date: Mon, 21 May 2018 19:10:24 +0100 Subject: [PATCH 179/321] Replace spelling: soulgem -> soul gem --- apps/launcher/advancedpage.cpp | 4 ++-- apps/openmw/mwclass/misc.cpp | 2 +- files/settings-default.cfg | 4 ++-- files/ui/advancedpage.ui | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index dcf376362..9ae83419d 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -23,7 +23,7 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game"); loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); - loadSettingBool(rebalanceSoulgemValuesCheckBox, "rebalance soulgem values", "Game"); + loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game"); // Expected values are (0, 1, 2, 3) int showOwnedIndex = mEngineSettings.getInt("show owned", "Game"); @@ -62,7 +62,7 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game"); saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); - saveSettingBool(rebalanceSoulgemValuesCheckBox, "rebalance soulgem values", "Game"); + saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game"); int showOwnedCurrentIndex = showOwnedComboBox->currentIndex(); if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game")) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index c7e0796d5..091bb3120 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -88,7 +88,7 @@ namespace MWClass if (creature) { int soul = creature->mData.mSoul; - if (Settings::Manager::getBool("rebalance soulgem values", "Game")) + if (Settings::Manager::getBool("rebalance soul gem values", "Game")) { // use soulgem value rebalance formula from morrowind code patch float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a2524ff17..b10b91eb1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -216,8 +216,8 @@ followers attack on sight = false # Can loot non-fighting actors during death animation can loot during death animation = true -# Makes the value of filled soulgems dependent only on soul magnitude (with formula from the Morrowind Code Patch) -rebalance soulgem values = false +# Makes the value of filled soul gems dependent only on soul magnitude (with formula from the Morrowind Code Patch) +rebalance soul gem values = false [General] diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 28d0f0543..f436b4db3 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -110,12 +110,12 @@ - + - <html><head/><body><p>If this setting is true, the value of filled soulgems is dependent only on soul magnitude.</p><p>The default value is false.</p></body></html> + <html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is false.</p></body></html> - Rebalance soulgem values + Rebalance soul gem values From 844aef85f33a31c8ad6c0f51d037cd53c18a8c0b Mon Sep 17 00:00:00 2001 From: declan-millar Date: Mon, 21 May 2018 22:12:19 +0100 Subject: [PATCH 180/321] Replace spelling: soulgem -> soul gem in code comment --- apps/openmw/mwclass/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 091bb3120..4188cf222 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -90,7 +90,7 @@ namespace MWClass int soul = creature->mData.mSoul; if (Settings::Manager::getBool("rebalance soul gem values", "Game")) { - // use soulgem value rebalance formula from morrowind code patch + // use the 'Soul gem value rebalance' formula from morrowind code patch float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; // for Azura's star add the unfilled value From b8df4b7c5a3b0e4e9702fdf3eebe438cedc8ab7d Mon Sep 17 00:00:00 2001 From: declan-millar Date: Mon, 21 May 2018 22:14:23 +0100 Subject: [PATCH 181/321] Tidy in-code comment --- apps/openmw/mwclass/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 4188cf222..62b15bc86 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -90,7 +90,7 @@ namespace MWClass int soul = creature->mData.mSoul; if (Settings::Manager::getBool("rebalance soul gem values", "Game")) { - // use the 'Soul gem value rebalance' formula from morrowind code patch + // use the 'soul gem value rebalance' formula from the Morrowind Code Patch float soulValue = 0.0001 * pow(soul, 3) + 2 * soul; // for Azura's star add the unfilled value From 888c2d9a33c27b764e55793ecc5cee7a4364d446 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 22 May 2018 12:40:01 +0400 Subject: [PATCH 182/321] Render default land texture for Wilderness cells with distant terrain --- components/terrain/quadtreeworld.cpp | 37 +++++++++------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f31064805..bc26e084e 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -189,35 +189,22 @@ public: node->setViewDataMap(mViewDataMap); parent->addChild(node); - if (center.x() - size > mMaxX - || center.x() + size < mMinX - || center.y() - size > mMaxY - || center.y() + size < mMinY ) - // Out of bounds of the actual terrain - this will happen because - // we rounded the size up to the next power of two - { - // Still create and return an empty node so as to not break the assumption that each QuadTreeNode has either 4 or 0 children. - return node; - } - - if (node->getSize() <= mMinSize) - { - // We arrived at a leaf - float minZ,maxZ; - if (mStorage->getMinMaxHeights(size, center, minZ, maxZ)) - { - float cellWorldSize = mStorage->getCellWorldSize(); - osg::BoundingBox boundingBox(osg::Vec3f((center.x()-size)*cellWorldSize, (center.y()-size)*cellWorldSize, minZ), - osg::Vec3f((center.x()+size)*cellWorldSize, (center.y()+size)*cellWorldSize, maxZ)); - node->setBoundingBox(boundingBox); - } - return node; - } - else + if (node->getSize() > mMinSize) { addChildren(node); return node; } + + // We arrived at a leaf + float minZ, maxZ; + mStorage->getMinMaxHeights(size, center, minZ, maxZ); + + float cellWorldSize = mStorage->getCellWorldSize(); + osg::BoundingBox boundingBox(osg::Vec3f((center.x()-size)*cellWorldSize, (center.y()-size)*cellWorldSize, minZ), + osg::Vec3f((center.x()+size)*cellWorldSize, (center.y()+size)*cellWorldSize, maxZ)); + node->setBoundingBox(boundingBox); + + return node; } osg::ref_ptr getRootNode() From 825c3317644eefb073553a96fa5c268046c616e5 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 22 May 2018 14:55:09 +0300 Subject: [PATCH 183/321] Remove texture filtering, better ltex importing, reindexing duplicates --- .../world/landtexturetableproxymodel.cpp | 5 -- .../opencs/view/render/terraintexturemode.cpp | 5 ++ .../view/widget/scenetooltexturebrush.cpp | 46 +++++++++++++++++-- .../view/widget/scenetooltexturebrush.hpp | 1 + 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/landtexturetableproxymodel.cpp b/apps/opencs/model/world/landtexturetableproxymodel.cpp index cf33fab9e..e064bbe8a 100644 --- a/apps/opencs/model/world/landtexturetableproxymodel.cpp +++ b/apps/opencs/model/world/landtexturetableproxymodel.cpp @@ -11,11 +11,6 @@ namespace CSMWorld bool LandTextureTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { - int columnIndex = mSourceModel->findColumnIndex(Columns::ColumnId_Modification); - QModelIndex index = mSourceModel->index(sourceRow, columnIndex); - if (mSourceModel->data(index).toInt() != RecordBase::State_ModifiedOnly) - return false; - return IdTableProxyModel::filterAcceptsRow(sourceRow, sourceParent); } } diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index d312c28d9..376258c5e 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -55,6 +55,7 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); connect(mTextureBrushScenetool->mTextureBrushWindow->mSizeSliders->mBrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrushSize(int))); connect(mTextureBrushScenetool, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string))); + connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string))); connect(mTextureBrushScenetool, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*))); connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool->mTextureBrushWindow, SLOT(setBrushTexture(std::string))); @@ -391,12 +392,16 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, CSMWorld::IdTable& landTable, std::string cellId) { + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + QVariant changedLand; changedLand.setValue(newLandGrid); QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); QUndoStack& undoStack = document.getUndoStack(); + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); } diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index d8d4600e5..d6df4e9f9 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -24,6 +24,7 @@ #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" +#include "../../model/world/commands.hpp" #include "../../model/world/data.hpp" #include "../../model/world/idcollection.hpp" #include "../../model/world/idtable.hpp" @@ -134,19 +135,57 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton * void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) { + mBrushTexture = brushTexture; + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); + int columnModification = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Modification); int index = landtexturesCollection.searchId(mBrushTexture); - mBrushTexture = brushTexture; + + // Check if texture exists in current plugin + if(landtexturesCollection.getData(index, columnModification).value() == 0) + { + CSMWorld::IdTable& ltexTable = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); + + QUndoStack& undoStack = mDocument.getUndoStack(); + + QVariant textureFileNameVariant; + textureFileNameVariant.setValue(landtexturesCollection.getData(index, landTextureFilename).value()); + + std::size_t hashlocation = mBrushTexture.find("#"); + std::string mBrushTexturePlugin = "L0#" + mBrushTexture.substr (hashlocation+1); + int indexPlugin = landtexturesCollection.searchId(mBrushTexturePlugin); + + // Reindex texture if needed + if (indexPlugin != -1 && !landtexturesCollection.getRecord(indexPlugin).isDeleted()) + { + int counter=0; + bool freeIndexFound = false; + do { + const size_t maxCounter = std::numeric_limits::max() - 1; + mBrushTexturePlugin = CSMWorld::LandTexture::createUniqueRecordId(0, counter); + if (landtexturesCollection.searchId(mBrushTexturePlugin) != -1 && landtexturesCollection.getRecord(mBrushTexturePlugin).isDeleted() == 0) counter = (counter + 1) % maxCounter; + else freeIndexFound = true; + } while (freeIndexFound == false); + } + + undoStack.beginMacro ("Add land texture record"); + undoStack.push (new CSMWorld::CloneCommand (ltexTable, mBrushTexture, mBrushTexturePlugin, CSMWorld::UniversalId::Type_LandTexture)); + undoStack.endMacro(); + mBrushTexture = mBrushTexturePlugin; + emit passTextureId(mBrushTexture); + } if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value()); + mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; + mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value()); } else { mBrushTextureLabel = "No selected texture or invalid texture"; - mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel)); + mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); } emit passBrushShape(mBrushShape); // update icon @@ -242,7 +281,6 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - //QModelIndex qIndex = landtexturesCollection.getModelIndex (mBrushTexture, landTextureFilename); tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " "; tooltip += landtexturesCollection.getData(index, landTextureFilename).value(); diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 33a6dc2de..d40132d42 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -72,6 +72,7 @@ namespace CSVWidget signals: void passBrushSize (int brushSize); void passBrushShape(int brushShape); + void passTextureId(std::string brushTexture); }; class SceneToolTextureBrush : public SceneTool From 2963524a013e679f2c48d0929ac8065a3840aedc Mon Sep 17 00:00:00 2001 From: declan-millar Date: Tue, 22 May 2018 12:59:27 +0100 Subject: [PATCH 184/321] set rebalance soul gem values to true by default --- files/settings-default.cfg | 2 +- files/ui/advancedpage.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index b10b91eb1..4483e3d9d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -217,7 +217,7 @@ followers attack on sight = false can loot during death animation = true # Makes the value of filled soul gems dependent only on soul magnitude (with formula from the Morrowind Code Patch) -rebalance soul gem values = false +rebalance soul gem values = true [General] diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index f436b4db3..4e0234e2e 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -112,7 +112,7 @@ - <html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is false.</p></body></html> + <html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is true.</p></body></html> Rebalance soul gem values From d58cce9c727dd6ddccea3bcee44338457615338f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 22 May 2018 20:50:31 -0500 Subject: [PATCH 185/321] Adding WIP code to dynamically change the autocomplete fields --- apps/launcher/advancedpage.cpp | 5 +++++ apps/launcher/advancedpage.hpp | 3 +++ apps/launcher/datafilespage.cpp | 7 +++++++ apps/launcher/datafilespage.hpp | 3 +++ apps/launcher/maindialog.cpp | 1 + components/contentselector/view/contentselector.cpp | 13 +++++++++++++ components/contentselector/view/contentselector.hpp | 2 ++ 7 files changed, 34 insertions(+) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index bd077c12f..383799e2a 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -162,4 +162,9 @@ void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::str bool cValue = checkbox->checkState(); if (cValue != mEngineSettings.getBool(setting, group)) mEngineSettings.setBool(setting, group, cValue); +} + +void Launcher::AdvancedPage::slotSelectedDataFilesChanged(QStringList selectedFiles) +{ + loadCellsForAutocomplete(selectedFiles); } \ No newline at end of file diff --git a/apps/launcher/advancedpage.hpp b/apps/launcher/advancedpage.hpp index 654214f29..c40ae2da1 100644 --- a/apps/launcher/advancedpage.hpp +++ b/apps/launcher/advancedpage.hpp @@ -29,6 +29,9 @@ namespace Launcher */ void loadCellsForAutocomplete(QStringList filePaths); + public slots: + void slotSelectedDataFilesChanged(QStringList selectedFiles); + private slots: void on_skipMenuCheckBox_stateChanged(int state); void on_runScriptAfterStartupBrowseButton_clicked(); diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 484c8c56b..8d4d2422f 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -37,6 +37,8 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config: connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); + connect(mSelector, SIGNAL(signalSelectedFilesChanged(QStringList)), + this, SLOT(slotSelectedFilesChanged(QStringList))); buildView(); loadSettings(); @@ -319,3 +321,8 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text) return (msgBox.clickedButton() == deleteButton); } + +void Launcher::DataFilesPage::slotSelectedFilesChanged(QStringList selectedFilesChanged) +{ + emit signalSelectedFilesChanged(selectedFilesChanged); +} \ No newline at end of file diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 9955737d5..fb9f9e04f 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -7,6 +7,7 @@ #include #include +#include class QSortFilterProxyModel; class QAbstractItemModel; @@ -49,6 +50,7 @@ namespace Launcher signals: void signalProfileChanged (int index); + void signalSelectedFilesChanged(QStringList selectedFiles); public slots: void slotProfileChanged (int index); @@ -58,6 +60,7 @@ namespace Launcher void slotProfileChangedByUser(const QString &previous, const QString ¤t); void slotProfileRenamed(const QString &previous, const QString ¤t); void slotProfileDeleted(const QString &item); + void slotSelectedFilesChanged (QStringList selectedFiles); void updateOkButton(const QString &text); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 9967cbddc..f3afb2732 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -142,6 +142,7 @@ void Launcher::MainDialog::createPages() connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int))); connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int))); + connect(mDataFilesPage, SIGNAL(signalSelectedFilesChanged(QStringList)), mAdvancedPage, SLOT(slotSelectedDataFilesChanged(QStringList))); } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index f4da7e6ad..4798d160c 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -216,6 +216,8 @@ void ContentSelectorView::ContentSelector::slotShowContextMenu(const QPoint& pos { QPoint globalPos = ui.addonView->viewport()->mapToGlobal(pos); mContextMenu->exec(globalPos); + // TODO This is a temporary workaround to demonstrate that the selected files signal can be sent + emitSelectedFilesChanged(); } void ContentSelectorView::ContentSelector::setCheckStateForMultiSelectedItems(bool checked) @@ -240,3 +242,14 @@ void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems() { setCheckStateForMultiSelectedItems(true); } + +void ContentSelectorView::ContentSelector::emitSelectedFilesChanged() +{ + //retrieve the files selected for the profile + ContentSelectorModel::ContentFileList items = selectedFiles(); + QStringList filePaths; + foreach(const ContentSelectorModel::EsmFile *item, items) { + filePaths.append(item->filePath()); + } + emit signalSelectedFilesChanged(filePaths); +} \ No newline at end of file diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 9f775d597..5015306ab 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -56,11 +56,13 @@ namespace ContentSelectorView void buildContextMenu(); void setGameFileSelected(int index, bool selected); void setCheckStateForMultiSelectedItems(bool checked); + void emitSelectedFilesChanged(); signals: void signalCurrentGamefileIndexChanged (int); void signalAddonDataChanged (const QModelIndex& topleft, const QModelIndex& bottomright); + void signalSelectedFilesChanged(QStringList selectedFiles); private slots: From 9ac752ea70d32901c25144a057272a6f4383bb56 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 24 May 2018 10:48:46 +0400 Subject: [PATCH 186/321] Implement filtering in the spells window --- apps/openmw/mwgui/keyboardnavigation.cpp | 3 +++ apps/openmw/mwgui/spellmodel.cpp | 20 +++++++++++++++++--- apps/openmw/mwgui/spellmodel.hpp | 3 +++ apps/openmw/mwgui/spellwindow.cpp | 19 +++++++++++++++++-- apps/openmw/mwgui/spellwindow.hpp | 2 ++ files/mygui/openmw_spell_window.layout | 6 +++++- 6 files changed, 47 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 1374ef93d..cde8a17cc 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -14,6 +14,9 @@ namespace MWGui bool shouldAcceptKeyFocus(MyGUI::Widget* w) { + if (w && w->getUserString("IgnoreTabKey") == "y") + return false; + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); } diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index f83b72096..ba661093f 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -32,10 +32,14 @@ namespace namespace MWGui { + SpellModel::SpellModel(const MWWorld::Ptr &actor, const std::string& filter) + : mActor(actor), mFilter(filter) + { + } + SpellModel::SpellModel(const MWWorld::Ptr &actor) : mActor(actor) { - } void SpellModel::update() @@ -54,8 +58,13 @@ namespace MWGui if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell) continue; + std::string name = spell->mName; + + if (name.find(mFilter) == std::string::npos) + continue; + Spell newSpell; - newSpell.mName = spell->mName; + newSpell.mName = name; if (spell->mData.mType == ESM::Spell::ST_Spell) { newSpell.mType = Spell::Type_Spell; @@ -89,10 +98,15 @@ namespace MWGui if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce) continue; + std::string name = item.getClass().getName(item); + + if (name.find(mFilter) == std::string::npos) + continue; + Spell newSpell; newSpell.mItem = item; newSpell.mId = item.getCellRef().getRefId(); - newSpell.mName = item.getClass().getName(item); + newSpell.mName = name; newSpell.mType = Spell::Type_EnchantedItem; newSpell.mSelected = invStore.getSelectedEnchantItem() == it; diff --git a/apps/openmw/mwgui/spellmodel.hpp b/apps/openmw/mwgui/spellmodel.hpp index 21fbc9a6e..6b10f7127 100644 --- a/apps/openmw/mwgui/spellmodel.hpp +++ b/apps/openmw/mwgui/spellmodel.hpp @@ -35,6 +35,7 @@ namespace MWGui class SpellModel { public: + SpellModel(const MWWorld::Ptr& actor, const std::string& filter); SpellModel(const MWWorld::Ptr& actor); typedef int ModelIndex; @@ -50,6 +51,8 @@ namespace MWGui MWWorld::Ptr mActor; std::vector mSpells; + + std::string mFilter; }; } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 601204aa1..10b4598ee 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -38,8 +39,12 @@ namespace MWGui getWidget(mSpellView, "SpellView"); getWidget(mEffectBox, "EffectsBox"); + getWidget(mFilterEdit, "FilterEdit"); + + mFilterEdit->setUserString("IgnoreTabKey", "y"); mSpellView->eventSpellClicked += MyGUI::newDelegate(this, &SpellWindow::onModelIndexSelected); + mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &SpellWindow::onFilterChanged); setCoord(498, 300, 302, 300); } @@ -64,6 +69,11 @@ namespace MWGui void SpellWindow::onOpen() { + // Reset the filter focus when opening the window + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (focus == mFilterEdit) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); + updateSpells(); } @@ -82,7 +92,7 @@ namespace MWGui { mSpellIcons->updateWidgets(mEffectBox, false); - mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), mFilterEdit->getCaption())); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) @@ -167,6 +177,11 @@ namespace MWGui } } + void SpellWindow::onFilterChanged(MyGUI::EditBox *sender) + { + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), sender->getCaption())); + } + void SpellWindow::onSpellSelected(const std::string& spellId) { MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -202,7 +217,7 @@ namespace MWGui if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery()) return; - mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), mFilterEdit->getCaption())); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index f8fead9ea..ce10770f5 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -32,6 +32,7 @@ namespace MWGui void onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped); void onSpellSelected(const std::string& spellId); void onModelIndexSelected(SpellModel::ModelIndex index); + void onFilterChanged(MyGUI::EditBox *sender); void onDeleteSpellAccept(); void askDeleteSpell(const std::string& spellId); @@ -41,6 +42,7 @@ namespace MWGui SpellView* mSpellView; SpellIcons* mSpellIcons; + MyGUI::EditBox* mFilterEdit; private: float mUpdateTimer; diff --git a/files/mygui/openmw_spell_window.layout b/files/mygui/openmw_spell_window.layout index 21bf74267..8a98c47b2 100644 --- a/files/mygui/openmw_spell_window.layout +++ b/files/mygui/openmw_spell_window.layout @@ -10,7 +10,11 @@ - + + + + + From b5374029e5af3d4b9756ddb41b0c5e9cb65930c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 24 May 2018 12:39:00 +0400 Subject: [PATCH 187/321] Implement case-insensitive search in spell window --- apps/openmw/mwgui/spellmodel.cpp | 12 +++--- apps/openmw/mwgui/spellwindow.cpp | 2 +- components/misc/stringops.hpp | 66 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index ba661093f..d1db582d2 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -52,19 +52,21 @@ namespace MWGui const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); + std::string filter = Misc::StringUtils::lowerCaseUtf8(mFilter); + for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { const ESM::Spell* spell = it->first; if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell) continue; - std::string name = spell->mName; + std::string name = Misc::StringUtils::lowerCaseUtf8(spell->mName); - if (name.find(mFilter) == std::string::npos) + if (name.find(filter) == std::string::npos) continue; Spell newSpell; - newSpell.mName = name; + newSpell.mName = spell->mName; if (spell->mData.mType == ESM::Spell::ST_Spell) { newSpell.mType = Spell::Type_Spell; @@ -98,9 +100,9 @@ namespace MWGui if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce) continue; - std::string name = item.getClass().getName(item); + std::string name = Misc::StringUtils::lowerCaseUtf8(item.getClass().getName(item)); - if (name.find(mFilter) == std::string::npos) + if (name.find(filter) == std::string::npos) continue; Spell newSpell; diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 10b4598ee..3fe171e4e 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -217,7 +217,7 @@ namespace MWGui if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery()) return; - mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), mFilterEdit->getCaption())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), "")); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9f4931d72..0fde1c96c 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -6,6 +6,8 @@ #include #include +#include "utf8stream.hpp" + namespace Misc { class StringUtils @@ -56,6 +58,70 @@ public: }; } + static Utf8Stream::UnicodeChar toLowerUtf8(Utf8Stream::UnicodeChar ch) + { + // Russian alphabet + if (ch >= 0x0410 && ch < 0x0430) + return ch += 0x20; + + // Cyrillic IO character + if (ch == 0x0401) + return ch += 0x50; + + // Latin alphabet + if (ch >= 0x41 && ch < 0x60) + return ch += 0x20; + + // Deutch characters + if (ch == 0xc4 || ch == 0xd6 || ch == 0xdc) + return ch += 0x20; + if (ch == 0x1e9e) + return 0xdf; + + // TODO: probably we will need to support characters from other languages + + return ch; + } + + static std::string lowerCaseUtf8(const std::string str) + { + if (str.empty()) + return str; + + // Decode string as utf8 characters, convert to lower case and pack them to string + std::string out; + Utf8Stream stream (str.c_str()); + while (!stream.eof ()) + { + Utf8Stream::UnicodeChar character = toLowerUtf8(stream.peek()); + + if (character <= 0x7f) + out.append(1, static_cast(character)); + else if (character <= 0x7ff) + { + out.append(1, static_cast(0xc0 | ((character >> 6) & 0x1f))); + out.append(1, static_cast(0x80 | (character & 0x3f))); + } + else if (character <= 0xffff) + { + out.append(1, static_cast(0xe0 | ((character >> 12) & 0x0f))); + out.append(1, static_cast(0x80 | ((character >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (character & 0x3f))); + } + else + { + out.append(1, static_cast(0xf0 | ((character >> 18) & 0x07))); + out.append(1, static_cast(0x80 | ((character >> 12) & 0x3f))); + out.append(1, static_cast(0x80 | ((character >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (character & 0x3f))); + } + + stream.consume(); + } + + return out; + } + static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } From afae398b5c7f557c272c3b61f2129ccf9f8aedf0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 24 May 2018 12:53:06 +0400 Subject: [PATCH 188/321] Use utf8 lowercase function for journal index to avoid code duplication --- apps/openmw/mwgui/journalbooks.cpp | 4 ++-- apps/openmw/mwgui/journalviewmodel.cpp | 24 +++--------------------- apps/openmw/mwgui/journalviewmodel.hpp | 4 +++- components/misc/utf8stream.hpp | 1 + 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index e8aa23158..1075239fa 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -244,7 +244,7 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, (uint32_t) ch); + textColours.journalTopicPressed, (Utf8Stream::UnicodeChar) ch); if (i == 13) typesetter->sectionBreak (); @@ -274,7 +274,7 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () sprintf(buffer, "( %c%c )", ch[0], ch[1]); Utf8Stream stream ((char*) ch); - uint32_t first = stream.peek(); + Utf8Stream::UnicodeChar first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 6ff68c9c5..63b48eab1 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -7,7 +7,6 @@ #include #include -#include #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -307,39 +306,22 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (Utf8Stream::UnicodeChar character, std::function < void (const std::string&) > visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { Utf8Stream stream (i->first.c_str()); - uint32_t first = toUpper(stream.peek()); + Utf8Stream::UnicodeChar first = Misc::StringUtils::toLowerUtf8(stream.peek()); - if (first != character) + if (first != Misc::StringUtils::toLowerUtf8(character)) continue; visitor (i->second.getName()); } } - static uint32_t toUpper(uint32_t ch) - { - // Russian alphabet - if (ch >= 0x0430 && ch < 0x0450) - ch -= 0x20; - - // Cyrillic IO character - if (ch == 0x0451) - ch -= 0x50; - - // Latin alphabet - if (ch >= 0x61 && ch < 0x80) - ch -= 0x20; - - return ch; - } - struct TopicEntryImpl : BaseEntry { MWDialogue::Topic const & mTopic; diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 01dcb49de..fa4090225 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -6,6 +6,8 @@ #include #include +#include + namespace MWGui { /// View-Model for the journal GUI @@ -76,7 +78,7 @@ namespace MWGui virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; /// walks over the topics whose names start with the character - virtual void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const = 0; + virtual void visitTopicNamesStartingWith (Utf8Stream::UnicodeChar character, std::function < void (const std::string&) > visitor) const = 0; /// walks over the topic entries for the topic specified by its identifier virtual void visitTopicEntries (TopicId topicId, std::function visitor) const = 0; diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp index 368374a64..e499d15e6 100644 --- a/components/misc/utf8stream.hpp +++ b/components/misc/utf8stream.hpp @@ -1,6 +1,7 @@ #ifndef MISC_UTF8ITER_HPP #define MISC_UTF8ITER_HPP +#include #include class Utf8Stream From 1abff5365bb31378047bab5692608fc787125947 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 24 May 2018 12:57:29 +0400 Subject: [PATCH 189/321] Capitalize enchanted items names again in spells window --- apps/openmw/mwgui/spellmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index d1db582d2..a73d343f9 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -108,7 +108,7 @@ namespace MWGui Spell newSpell; newSpell.mItem = item; newSpell.mId = item.getCellRef().getRefId(); - newSpell.mName = name; + newSpell.mName = item.getClass().getName(item); newSpell.mType = Spell::Type_EnchantedItem; newSpell.mSelected = invStore.getSelectedEnchantItem() == it; From 8c9567635224cc1d9997e050a8b33e5e43de416b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 24 May 2018 22:49:53 +0400 Subject: [PATCH 190/321] Preserve AppVeyor builds --- appveyor.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index eae4bd5b1..ede57d890 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -55,6 +55,10 @@ build_script: - cmd: if %PLATFORM%==x64 set build=MSVC%msvc%_64 - cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +after_build: + - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Debug\ -xr"!*.pdb" + - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Debug\*.pdb + test: off #notifications: @@ -63,3 +67,9 @@ test: off # - # on_build_failure: true # on_build_status_changed: true + +artifacts: + - path: OpenMW_MSVC%msvc%_x64.zip + name: OpenMW_MSVC%msvc%_x64 + - path: OpenMW_MSVC%msvc%_x64_pdb.zip + name: OpenMW_MSVC%msvc%_x64_pdb From 77c5e85e8db8748a89fe286bc212c37986c3b73f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 24 May 2018 22:51:25 +0400 Subject: [PATCH 191/321] Enable release builds --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ede57d890..21fb7e1d6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,8 +18,8 @@ platform: - x64 configuration: - - Debug -# - Release +# - Debug + - Release # For the Qt, Boost, CMake, etc installs #os: Visual Studio 2017 @@ -56,8 +56,8 @@ build_script: - cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Debug\ -xr"!*.pdb" - - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Debug\*.pdb + - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Release\ -xr"!*.pdb" + - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Release\*.pdb test: off From ba3a02ad055a2713f53aafe1d5a6c3bb69a957bc Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 24 May 2018 23:00:59 +0200 Subject: [PATCH 192/321] [macOS, CI] Do not upload a nightly if there's already one of the same commit --- CI/deploy.osx.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CI/deploy.osx.sh b/CI/deploy.osx.sh index 53bfa18b5..5fa2b70a3 100755 --- a/CI/deploy.osx.sh +++ b/CI/deploy.osx.sh @@ -6,4 +6,6 @@ DATE=`date +'%d%m%Y'` SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}` TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg" -curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}" +if ! curl --ssl -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}" --silent | grep $SHORT_COMMIT > /dev/null; then + curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}" +fi From 48e15dabc3c70a5bfcc35c1277d188818759c42b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 25 May 2018 12:16:13 +0400 Subject: [PATCH 193/321] Try to generate PDB for release builds --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd809b58c..bfef2d328 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,6 +360,8 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter") endif() elseif (MSVC) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /Zi /bigobj") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO") # Enable link-time code generation globally for all linking if (OPENMW_LTO_BUILD) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") From e76df5f4d39afe5a2f0bfa7db2da400d4061900e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 May 2018 11:53:08 +0200 Subject: [PATCH 194/321] minor tooltip fixes --- .../view/widget/scenetooltexturebrush.cpp | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index d6df4e9f9..dab6a2850 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -252,28 +252,38 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, c void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) { - QString tooltip = "Brush settings

Currently selected: "; - if(brushShape == 0) - { - setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); - tooltip += dynamic_cast (mTextureBrushWindow->toolTipPoint); - } - if(brushShape == 1) - { - setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); - tooltip += dynamic_cast (mTextureBrushWindow->toolTipSquare); - } - if(brushShape == 2) - { - setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); - tooltip += dynamic_cast (mTextureBrushWindow->toolTipCircle); - } - if(brushShape == 3) + QString tooltip = "Change brush settings

Currently selected: "; + + switch (brushShape) { - setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); - tooltip += dynamic_cast (mTextureBrushWindow->toolTipCustom); + case 0: + + setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); + tooltip += mTextureBrushWindow->toolTipPoint; + break; + + case 1: + + setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); + tooltip += mTextureBrushWindow->toolTipSquare; + break; + + case 2: + + setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); + tooltip += mTextureBrushWindow->toolTipCircle; + break; + + case 3: + + setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); + tooltip += mTextureBrushWindow->toolTipCustom; + break; } + tooltip += "

(right click to access of previously used brush settings)"; + + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); From bbc337a0af8618e6c0b6f3f5c2816b113d07c44c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 May 2018 12:16:02 +0200 Subject: [PATCH 195/321] code cleanup --- .../view/widget/scenetooltexturebrush.cpp | 7 +++ .../view/widget/scenetooltexturebrush.hpp | 46 +++++++++++++------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index dab6a2850..2208f88a6 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -78,6 +78,13 @@ CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QW mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel)); } + mButtonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); + mButtonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); + mButtonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); + mButtonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); + + mSizeSliders = new BrushSizeControls("Brush size", this); + QVBoxLayout *layoutMain = new QVBoxLayout; layoutMain->setSpacing(0); layoutMain->setContentsMargins(4,0,4,4); diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index d40132d42..4669f432e 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -20,8 +20,15 @@ class QTableWidget; +namespace CSVRender +{ + class TerrainTextureMode; +} + namespace CSVWidget { + class SceneToolTextureBrush; + /// \brief Layout-box for some brush button settings class BrushSizeControls : public QGroupBox { @@ -29,13 +36,18 @@ namespace CSVWidget public: BrushSizeControls(const QString &title, QWidget *parent); - QSlider *mBrushSizeSlider; - QSpinBox *mBrushSizeSpinBox; private: QHBoxLayout *mLayoutSliderSize; + QSlider *mBrushSizeSlider; + QSpinBox *mBrushSizeSpinBox; + + friend class SceneToolTextureBrush; + friend class CSVRender::TerrainTextureMode; }; + class SceneToolTextureBrush; + /// \brief Brush settings window class TextureBrushWindow : public QFrame { @@ -45,24 +57,27 @@ namespace CSVWidget TextureBrushWindow(CSMDoc::Document& document, QWidget *parent = 0); void configureButtonInitialSettings(QPushButton *button); - QPushButton *mButtonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this); - QPushButton *mButtonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this); - QPushButton *mButtonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this); - QPushButton *mButtonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this); - QString toolTipPoint = "Paint single point"; - QString toolTipSquare = "Paint with square brush"; - QString toolTipCircle = "Paint with circle brush"; - QString toolTipCustom = "Paint custom selection (not implemented yet)"; - BrushSizeControls* mSizeSliders = new BrushSizeControls("Brush size", this); + const QString toolTipPoint = "Paint single point"; + const QString toolTipSquare = "Paint with square brush"; + const QString toolTipCircle = "Paint with circle brush"; + const QString toolTipCustom = "Paint custom selection (not implemented yet)"; + + private: int mBrushShape; int mBrushSize; std::string mBrushTexture; - - private: CSMDoc::Document& mDocument; QLabel *mSelectedBrush; QGroupBox *mHorizontalGroupBox; std::string mBrushTextureLabel; + QPushButton *mButtonPoint; + QPushButton *mButtonSquare; + QPushButton *mButtonCircle; + QPushButton *mButtonCustom; + BrushSizeControls* mSizeSliders; + + friend class SceneToolTextureBrush; + friend class CSVRender::TerrainTextureMode; public slots: void setBrushTexture(std::string brushTexture); @@ -84,6 +99,7 @@ namespace CSVWidget QFrame *mPanel; QTableWidget *mTable; std::vector mBrushHistory; + TextureBrushWindow *mTextureBrushWindow; private: @@ -96,11 +112,11 @@ namespace CSVWidget virtual void showPanel (const QPoint& position); void updatePanel (); - TextureBrushWindow *mTextureBrushWindow; - void dropEvent (QDropEvent *event); void dragEnterEvent (QDragEnterEvent *event); + friend class CSVRender::TerrainTextureMode; + public slots: void setButtonIcon(int brushShape); void updateBrushHistory (const std::string& mBrushTexture); From 99ffaafe3068d9727acaf76d054f9329f4eac879 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 26 May 2018 11:35:48 +0000 Subject: [PATCH 196/321] Revert "Merge pull request #1701 from akortunov/standfix" This reverts commit da47fc79f540c65ccc2d7276f560d3d3a1e105a3, reversing changes made to 7324bd368f103a5dc3c029dfd1c7024e90200cdf. --- apps/openmw/mwbase/world.hpp | 1 - apps/openmw/mwmechanics/aiwander.cpp | 3 ++- apps/openmw/mwmechanics/character.cpp | 3 +-- apps/openmw/mwphysics/actor.cpp | 7 +----- apps/openmw/mwphysics/actor.hpp | 8 ------- apps/openmw/mwphysics/physicssystem.cpp | 31 +------------------------ apps/openmw/mwphysics/physicssystem.hpp | 3 --- apps/openmw/mwscript/miscextensions.cpp | 2 -- apps/openmw/mwstate/statemanagerimp.cpp | 5 +--- apps/openmw/mwworld/worldimp.cpp | 7 ++---- apps/openmw/mwworld/worldimp.hpp | 1 - 11 files changed, 8 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 086e81678..68d4ac85d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -391,7 +391,6 @@ namespace MWBase virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const = 0; virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; - virtual bool isIdle(const MWWorld::Ptr &ptr) const = 0; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 511a47a49..8199170dc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -866,7 +866,8 @@ namespace MWMechanics } // place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be underground. - dest.mZ += 80; + // Adding 20 in adjustPosition() is not enough. + dest.mZ += 60; ToWorldCoordinates(dest, actor.getCell()->getCell()); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 1ba5cc0d5..29a6d5e3b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2036,8 +2036,7 @@ void CharacterController::update(float duration) moved.z() = 1.0; // Update movement - // We should not apply movement for standing actors - if(mMovementAnimationControlled && mPtr.getClass().isActor() && (movement.length2() > 0.f || !world->isIdle(mPtr))) + if(mMovementAnimationControlled && mPtr.getClass().isActor()) world->queueMovement(mPtr, moved); mSkipAnim = false; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 6de0d1984..79c6dcabf 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -18,7 +18,7 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) - , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false), mIdle(true) + , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mInternalCollisionMode(true) , mExternalCollisionMode(true) , mCollisionWorld(world) @@ -195,11 +195,6 @@ void Actor::setOnSlope(bool slope) mOnSlope = slope; } -void Actor::setIdle(bool idle) -{ - mIdle = idle; -} - bool Actor::isWalkingOnWater() const { return mWalkingOnWater; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index bdafc1235..8ec94200f 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -139,13 +139,6 @@ namespace MWPhysics return mInternalCollisionMode && mOnSlope; } - void setIdle(bool idle); - - bool getIdle() const - { - return mIdle; - } - btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); @@ -186,7 +179,6 @@ namespace MWPhysics osg::Vec3f mForce; bool mOnGround; bool mOnSlope; - bool mIdle; bool mInternalCollisionMode; bool mExternalCollisionMode; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 412e5e5b3..f3c34bc4e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -249,7 +249,7 @@ namespace MWPhysics // Check if we actually found a valid spawn point (use an infinitely thin ray this time). // Required for some broken door destinations in Morrowind.esm, where the spawn point // intersects with other geometry if the actor's base is taken into account - btVector3 from = toBullet(position + offset); + btVector3 from = toBullet(position); btVector3 to = from - btVector3(0,0,maxHeight); btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); @@ -683,7 +683,6 @@ namespace MWPhysics , mWaterEnabled(false) , mParentNode(parentNode) , mPhysicsDt(1.f / 60.f) - , mIdleUpdateTimer(0) { mResourceSystem->addResourceManager(mShapeManager.get()); @@ -740,18 +739,6 @@ namespace MWPhysics delete mBroadphase; } - void PhysicsSystem::updateIdle() - { - for (ActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it) - { - osg::Vec3f pos(it->second->getCollisionObjectPosition()); - - RayResult result = castRay(pos, pos - osg::Vec3f(0, 0, it->second->getHalfExtents().z() + 2), it->second->getPtr(), std::vector(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); - - it->second->setIdle(result.mHit); - } - } - void PhysicsSystem::setUnrefQueue(SceneUtil::UnrefQueue *unrefQueue) { mUnrefQueue = unrefQueue; @@ -1058,11 +1045,6 @@ namespace MWPhysics return physactor && physactor->getOnGround(); } - bool PhysicsSystem::isIdle(const MWWorld::Ptr &actor) - { - Actor* physactor = getActor(actor); - return physactor && physactor->getIdle(); - } bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel) { const Actor* physicActor = getActor(actor); @@ -1355,10 +1337,6 @@ namespace MWPhysics cmode = !cmode; found->second->enableCollisionMode(cmode); found->second->enableCollisionBody(cmode); - - if (cmode) - queueObjectMovement(MWMechanics::getPlayer(), osg::Vec3f(0, 0, -0.1f)); - return cmode; } @@ -1478,13 +1456,6 @@ namespace MWPhysics for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) (*it)->animateCollisionShapes(mCollisionWorld); - mIdleUpdateTimer -= dt; - if (mIdleUpdateTimer <= 0.f) - { - mIdleUpdateTimer = 0.5f; - updateIdle(); - } - #ifndef BT_NO_PROFILE CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index fe2433ce0..3ef9990f5 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -124,7 +124,6 @@ namespace MWPhysics bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; bool isOnGround (const MWWorld::Ptr& actor); - bool isIdle (const MWWorld::Ptr& actor); bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel); @@ -174,7 +173,6 @@ namespace MWPhysics private: void updateWater(); - void updateIdle(); osg::ref_ptr mUnrefQueue; @@ -223,7 +221,6 @@ namespace MWPhysics osg::ref_ptr mParentNode; float mPhysicsDt; - float mIdleUpdateTimer; PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index fd27fe54b..243ba7b7e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -701,8 +701,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->queueMovement(ptr, osg::Vec3f(0, 0, -0.1f)); } }; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 911e0ebdc..c1bb589e8 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -506,7 +506,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - const MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::ConstPtr ptr = MWMechanics::getPlayer(); if (ptr.isInCell()) { @@ -538,9 +538,6 @@ void MWState::StateManager::loadGame (const Character *character, const std::str // Since we passed "changeEvent=false" to changeCell, we shouldn't have triggered the cell change flag. // But make sure the flag is cleared anyway in case it was set from an earlier game. MWBase::Environment::get().getWorld()->markCellAsUnchanged(); - - // Workaround to fix camera position upon game load - MWBase::Environment::get().getWorld()->queueMovement(ptr, osg::Vec3f(0, 0, 0)); } catch (const std::exception& e) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1179e1a9b..bbca8a46e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1314,6 +1314,8 @@ namespace MWWorld if (pos.z() < terrainHeight) pos.z() = terrainHeight; + pos.z() += 20; // place slightly above. will snap down to ground with code below + if (force || !isFlying(ptr)) { osg::Vec3f traced = mPhysics->traceDown(ptr, pos, 500); @@ -2160,11 +2162,6 @@ namespace MWWorld return mPhysics->isOnGround(ptr); } - bool World::isIdle(const MWWorld::Ptr &ptr) const - { - return mPhysics->isIdle(ptr); - } - void World::togglePOV() { mRendering->togglePOV(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 25fc473dc..023d91bca 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -489,7 +489,6 @@ namespace MWWorld bool isWading(const MWWorld::ConstPtr &object) const override; bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; bool isOnGround(const MWWorld::Ptr &ptr) const override; - bool isIdle(const MWWorld::Ptr &ptr) const override; osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; From cfdf99f601a36a6c5fb816311f41dc08ba264f89 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 26 May 2018 11:39:30 +0000 Subject: [PATCH 197/321] Revert "Merged pull request #1573" This reverts commit 7324bd368f103a5dc3c029dfd1c7024e90200cdf, reversing changes made to 810e4416f68cd564a9d189e88c15b1cae29e663e. --- apps/openmw/mwbase/world.hpp | 7 +- apps/openmw/mwmechanics/character.cpp | 9 --- apps/openmw/mwmechanics/spellcasting.cpp | 83 +++-------------------- apps/openmw/mwrender/animation.cpp | 14 ++-- apps/openmw/mwrender/animation.hpp | 3 +- apps/openmw/mwrender/effectmanager.cpp | 9 +-- apps/openmw/mwrender/effectmanager.hpp | 1 - apps/openmw/mwrender/objects.cpp | 8 --- apps/openmw/mwrender/objects.hpp | 2 - apps/openmw/mwrender/renderingmanager.cpp | 13 +--- apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwscript/miscextensions.cpp | 2 - apps/openmw/mwworld/worldimp.cpp | 9 +-- apps/openmw/mwworld/worldimp.hpp | 4 +- 14 files changed, 23 insertions(+), 143 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 68d4ac85d..47502fd71 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -5,9 +5,6 @@ #include #include -#include -#include - #include #include "../mwworld/ptr.hpp" @@ -537,7 +534,7 @@ namespace MWBase /// Spawn a blood effect for \a ptr at \a worldPosition virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) = 0; + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, @@ -579,8 +576,6 @@ namespace MWBase /// Preload VFX associated with this effect list virtual void preloadEffects(const ESM::EffectList* effectList) = 0; - - virtual osg::ref_ptr getInstance (const std::string& modelName) = 0; }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 29a6d5e3b..68dc17915 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -833,7 +833,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); mAnimation->runAnimation(0.f); - mAnimation->updateEffects(0.f); unpersistAnimationState(); } @@ -1997,13 +1996,6 @@ void CharacterController::update(float duration) } osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); - - // treat player specifically since he is not in rendering mObjects - if (mPtr == getPlayer()) - { - mAnimation->updateEffects(mSkipAnim ? 0.f : duration); - } - if(duration > 0.0f) moved /= duration; else @@ -2199,7 +2191,6 @@ void CharacterController::forceStateUpdate() } mAnimation->runAnimation(0.f); - mAnimation->updateEffects(0.f); } CharacterController::KillResult CharacterController::kill() diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index cdadd3b15..1f78e296f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -6,12 +6,8 @@ #include -#include -#include - #include #include -#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -28,7 +24,6 @@ #include "../mwworld/inventorystore.hpp" #include "../mwrender/animation.hpp" -#include "../mwrender/vismask.hpp" #include "npcstats.hpp" #include "actorutil.hpp" @@ -997,13 +992,11 @@ namespace MWMechanics return true; } - void CastSpell::playSpellCastingEffects(const std::string &spellid) - { + void CastSpell::playSpellCastingEffects(const std::string &spellid){ + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Spell *spell = store.get().find(spellid); - std::vector addedEffects; - for (std::vector::const_iterator iter = spell->mEffects.mList.begin(); iter != spell->mEffects.mList.end(); ++iter) { @@ -1012,72 +1005,18 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); - const ESM::Static* castStatic; - - if (!effect->mCasting.empty()) - castStatic = store.get().find (effect->mCasting); - else - castStatic = store.get().find ("VFX_DefaultCast"); - - // check if the effect was already added - if (std::find(addedEffects.begin(), addedEffects.end(), "meshes\\" + castStatic->mModel) != addedEffects.end()) - continue; - - std::string texture = effect->mParticle; - - float scale = 1.0f; - osg::Vec3f pos (mCaster.getRefData().getPosition().asVec3()); - - if (animation && mCaster.getClass().isNpc()) + if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL) { - // For NOC we should take race height as scaling factor - const ESM::NPC *npc = mCaster.get()->mBase; - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Race *race = - esmStore.get().find(npc->mRace); + const ESM::Static* castStatic; - scale = npc->isMale() ? race->mData.mHeight.mMale : race->mData.mHeight.mFemale; - } - else - { - std::string casterModel = mCaster.getClass().getModel(mCaster); - osg::ref_ptr model = MWBase::Environment::get().getWorld()->getInstance(casterModel); - - osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(~(MWRender::Mask_ParticleSystem|MWRender::Mask_Effect)); - model->accept(computeBoundsVisitor); - osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); - - if (bounds.valid()) - { - float meshSizeX = std::abs(bounds.xMax() - bounds.xMin()); - float meshSizeY = std::abs(bounds.yMax() - bounds.yMin()); - float meshSizeZ = std::abs(bounds.zMax() - bounds.zMin()); - - // TODO: take a size of particle or NPC with height and weight = 1.0 as scale = 1.0 - float scaleX = meshSizeX/60.f; - float scaleY = meshSizeY/60.f; - float scaleZ = meshSizeZ/120.f; + if (!effect->mCasting.empty()) + castStatic = store.get().find (effect->mCasting); + else + castStatic = store.get().find ("VFX_DefaultCast"); - scale = std::max({ scaleX, scaleY, scaleZ }); + std::string texture = effect->mParticle; - //pos = bounds.center(); - //pos[2] = bounds.zMin(); - } - } - - // If the caster has no animation, add the effect directly to the effectManager - if (animation) - { - animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture, scale); - } - else - { - // We should set scale for effect manager manually - float meshScale = !mCaster.getClass().isActor() ? mCaster.getCellRef().getScale() : 1.0f; - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + castStatic->mModel, effect->mParticle, pos, scale * meshScale); + animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); } if (animation && !mCaster.getClass().isActor()) @@ -1087,8 +1026,6 @@ namespace MWMechanics "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" }; - addedEffects.push_back("meshes\\" + castStatic->mModel); - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mCastSound.empty()) sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1b508e593..1bd839ead 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include @@ -1117,6 +1115,8 @@ namespace MWRender ++stateiter; } + updateEffects(duration); + if (mHeadController) { const float epsilon = 0.001f; @@ -1366,7 +1366,7 @@ namespace MWRender useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); } - void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture, float scale) + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture) { if (!mObjectRoot.get()) return; @@ -1417,13 +1417,7 @@ namespace MWRender overrideFirstRootTexture(texture, mResourceSystem, node); - osg::Vec3f scale3f (scale, scale, scale); - - osg::ref_ptr trans = new osg::PositionAttitudeTransform; - trans->setScale(scale3f); - trans->addChild(node); - parentNode->removeChild(node); - parentNode->addChild(trans); + // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. mEffects.push_back(params); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 74224c6bd..cff98a4b7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -364,7 +364,7 @@ public: * @param texture override the texture specified in the model's materials - if empty, do not override * @note Will not add an effect twice. */ - void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "", float scale = 1.0f); + void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = ""); void removeEffect (int effectId); void getLoopingEffects (std::vector& out) const; @@ -446,6 +446,7 @@ public: void setLoopingEnabled(const std::string &groupname, bool enabled); + /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); /// Return a node with the specified name, or NULL if not existing. diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index c44c5428a..3e785a769 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -26,13 +26,6 @@ EffectManager::~EffectManager() } void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) -{ - osg::Vec3f scale3f (scale, scale, scale); - - addEffect(model, textureOverride, worldPosition, scale3f, isMagicVFX); -} - -void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, const osg::Vec3f &scale, bool isMagicVFX) { osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(model); @@ -47,7 +40,7 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu osg::ref_ptr trans = new osg::PositionAttitudeTransform; trans->setPosition(worldPosition); - trans->setScale(scale); + trans->setScale(osg::Vec3f(scale, scale, scale)); trans->addChild(node); SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime); diff --git a/apps/openmw/mwrender/effectmanager.hpp b/apps/openmw/mwrender/effectmanager.hpp index cc1c1b42e..5873c00dd 100644 --- a/apps/openmw/mwrender/effectmanager.hpp +++ b/apps/openmw/mwrender/effectmanager.hpp @@ -33,7 +33,6 @@ namespace MWRender /// Add an effect. When it's finished playing, it will be removed automatically. void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true); - void addEffect (const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, const osg::Vec3f &scale3f, bool isMagicVFX); void update(float dt); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 523f1774c..f0a3d2e38 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -138,14 +138,6 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr) return false; } -void Objects::updateEffects(float duration) -{ - for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) - { - iter->second->updateEffects(duration); - ++iter; - } -} void Objects::removeCell(const MWWorld::CellStore* store) { diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index e97395213..659853763 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -88,8 +88,6 @@ public: bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? - void updateEffects(float duration); - void removeCell(const MWWorld::CellStore* store); /// Updates containing cell for object rendering data diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e5933a72a..6f0ddba3a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -557,7 +557,6 @@ namespace MWRender mEffectManager->update(dt); mSky->update(dt); mWater->update(dt); - mObjects->updateEffects(dt); } mCamera->update(dt, paused); @@ -842,11 +841,9 @@ namespace MWRender mObjects->updatePtr(old, updated); } - void RenderingManager::spawnEffect(const std::string &model, const std::string& texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) { - osg::Vec3f scale3f (scale, scale, scale); - - mEffectManager->addEffect(model, texture, worldPosition, scale3f, isMagicVFX); + mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX); } void RenderingManager::notifyWorldSpaceChanged() @@ -1125,12 +1122,6 @@ namespace MWRender updateProjectionMatrix(); } } - - osg::ref_ptr RenderingManager::getInstance(const std::string& modelName) - { - return mResourceSystem->getSceneManager()->getInstance(modelName); - } - void RenderingManager::exportSceneGraph(const MWWorld::Ptr &ptr, const std::string &filename, const std::string &format) { osg::Node* node = mViewer->getSceneData(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 7a570f249..1c689d29f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -205,8 +205,6 @@ namespace MWRender LandManager* getLandManager() const; - osg::ref_ptr getInstance(const std::string& modelName); - private: void updateProjectionMatrix(); void updateTextureFiltering(); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 243ba7b7e..59f2cc9c6 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -14,7 +14,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/world.hpp" @@ -1052,7 +1051,6 @@ namespace MWScript MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false); MWMechanics::CastSpell cast(ptr, target); - cast.playSpellCastingEffects(spell); cast.mHitPosition = target.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bbca8a46e..6cf1ead87 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1535,11 +1535,6 @@ namespace MWWorld } } - osg::ref_ptr World::getInstance (const std::string& modelName) - { - return mRendering->getInstance(modelName); - } - const ESM::Potion *World::createRecord (const ESM::Potion& record) { return mStore.insert(record); @@ -3329,9 +3324,9 @@ namespace MWWorld mRendering->spawnEffect(model, texture, worldPosition, 1.0f, false); } - void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos, float scale, bool isMagicVFX) + void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos) { - mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX); + mRendering->spawnEffect(model, textureOverride, worldPos); } void World::explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const Ptr& caster, const Ptr& ignore, ESM::RangeType rangeType, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 023d91bca..0d168c912 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -640,7 +640,7 @@ namespace MWWorld /// Spawn a blood effect for \a ptr at \a worldPosition void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) override; + void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, @@ -680,8 +680,6 @@ namespace MWWorld /// Preload VFX associated with this effect list void preloadEffects(const ESM::EffectList* effectList) override; - - osg::ref_ptr getInstance (const std::string& modelName); }; } From 7e38bb8513fd4841e57810d65910adb674dc5c9d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 26 May 2018 22:17:27 +0300 Subject: [PATCH 198/321] Verifier: improve handling of class name and description --- apps/opencs/model/tools/classcheck.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 316fc0ce5..79cb704bf 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -28,9 +28,13 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId); - // test for empty name and description + // A class should have a name if (class_.mName.empty()) - messages.push_back (std::make_pair (id, class_.mId + " has an empty name")); + messages.push_back (std::make_pair (id, class_.mId + " doesn't have a name")); + + // A playable class should have a description + if (class_.mData.mIsPlayable != 0 && class_.mDescription.empty()) + messages.push_back (std::make_pair (id, class_.mId + " doesn't have a description and it's playable")); // test for invalid attributes for (int i=0; i<2; ++i) From c2fff61ccdc9c8397e7cae28f8c48bea5f6ab588 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 26 May 2018 20:35:28 -0500 Subject: [PATCH 199/321] Changing so that data changes happen only after the addon is checked --- apps/launcher/datafilespage.cpp | 15 +++++++++++---- apps/launcher/datafilespage.hpp | 4 ++-- .../contentselector/view/contentselector.cpp | 13 ------------- .../contentselector/view/contentselector.hpp | 2 -- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 8d4d2422f..25a09ab1b 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -37,11 +37,14 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config: connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); - connect(mSelector, SIGNAL(signalSelectedFilesChanged(QStringList)), - this, SLOT(slotSelectedFilesChanged(QStringList))); buildView(); loadSettings(); + + // Connect signal and slot after the settings have been loaded. We only care about the user changing + // the addons and don't want to get signals of the system doing it during startup. + connect(mSelector, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex)), + this, SLOT(slotAddonDataChanged())); } void Launcher::DataFilesPage::buildView() @@ -322,7 +325,11 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text) return (msgBox.clickedButton() == deleteButton); } -void Launcher::DataFilesPage::slotSelectedFilesChanged(QStringList selectedFilesChanged) +void Launcher::DataFilesPage::slotAddonDataChanged() { - emit signalSelectedFilesChanged(selectedFilesChanged); + QStringList selectedFiles = selectedFilePaths(); + if (previousSelectedFiles != selectedFiles) { + previousSelectedFiles = selectedFiles; + emit signalSelectedFilesChanged(selectedFiles); + } } \ No newline at end of file diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index fb9f9e04f..8893412be 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -60,7 +60,7 @@ namespace Launcher void slotProfileChangedByUser(const QString &previous, const QString ¤t); void slotProfileRenamed(const QString &previous, const QString ¤t); void slotProfileDeleted(const QString &item); - void slotSelectedFilesChanged (QStringList selectedFiles); + void slotAddonDataChanged (); void updateOkButton(const QString &text); @@ -81,7 +81,7 @@ namespace Launcher Config::LauncherSettings &mLauncherSettings; QString mPreviousProfile; - + QStringList previousSelectedFiles; QString mDataLocal; void setPluginsCheckstates(Qt::CheckState state); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 4798d160c..5e16064f4 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -216,8 +216,6 @@ void ContentSelectorView::ContentSelector::slotShowContextMenu(const QPoint& pos { QPoint globalPos = ui.addonView->viewport()->mapToGlobal(pos); mContextMenu->exec(globalPos); - // TODO This is a temporary workaround to demonstrate that the selected files signal can be sent - emitSelectedFilesChanged(); } void ContentSelectorView::ContentSelector::setCheckStateForMultiSelectedItems(bool checked) @@ -241,15 +239,4 @@ void ContentSelectorView::ContentSelector::slotUncheckMultiSelectedItems() void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems() { setCheckStateForMultiSelectedItems(true); -} - -void ContentSelectorView::ContentSelector::emitSelectedFilesChanged() -{ - //retrieve the files selected for the profile - ContentSelectorModel::ContentFileList items = selectedFiles(); - QStringList filePaths; - foreach(const ContentSelectorModel::EsmFile *item, items) { - filePaths.append(item->filePath()); - } - emit signalSelectedFilesChanged(filePaths); } \ No newline at end of file diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 5015306ab..323f926ed 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -15,7 +15,6 @@ namespace ContentSelectorView Q_OBJECT QMenu *mContextMenu; - QStringList mFilePaths; protected: @@ -56,7 +55,6 @@ namespace ContentSelectorView void buildContextMenu(); void setGameFileSelected(int index, bool selected); void setCheckStateForMultiSelectedItems(bool checked); - void emitSelectedFilesChanged(); signals: void signalCurrentGamefileIndexChanged (int); From 31ea7c8edde6745031df2d72da0050315a6ddee2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 27 May 2018 10:43:31 +0000 Subject: [PATCH 200/321] Revert "set rebalance soul gem values to true by default" This reverts commit 2963524a013e679f2c48d0929ac8065a3840aedc. --- files/settings-default.cfg | 2 +- files/ui/advancedpage.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4483e3d9d..b10b91eb1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -217,7 +217,7 @@ followers attack on sight = false can loot during death animation = true # Makes the value of filled soul gems dependent only on soul magnitude (with formula from the Morrowind Code Patch) -rebalance soul gem values = true +rebalance soul gem values = false [General] diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 4e0234e2e..f436b4db3 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -112,7 +112,7 @@ - <html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is true.</p></body></html> + <html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is false.</p></body></html> Rebalance soul gem values From 78234e9468c2467a90e6a0bcf9101cebee76bb32 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 27 May 2018 16:47:09 -0500 Subject: [PATCH 201/321] Moving autocomplete code to thread --- apps/launcher/advancedpage.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 383799e2a..bc0378314 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -166,5 +167,8 @@ void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::str void Launcher::AdvancedPage::slotSelectedDataFilesChanged(QStringList selectedFiles) { - loadCellsForAutocomplete(selectedFiles); + // Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a + // barely perceptible UI lag. Splitting into its own thread to alleviate that. + std::thread loadCellsThread(&AdvancedPage::loadCellsForAutocomplete, this, selectedFiles); + loadCellsThread.join(); } \ No newline at end of file From 26dfef797040e6e944495ab017c0c8c4e6770748 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 27 May 2018 17:15:36 -0500 Subject: [PATCH 202/321] Changing where we are loading cells to prevent Qt access issue --- apps/launcher/advancedpage.cpp | 17 ++++------------- apps/launcher/advancedpage.hpp | 2 +- apps/launcher/datafilespage.cpp | 15 ++++++++++++++- apps/launcher/datafilespage.hpp | 1 + apps/launcher/maindialog.cpp | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index bc0378314..3fe7c1f89 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -2,10 +2,8 @@ #include #include -#include #include #include -#include #include #include @@ -23,13 +21,9 @@ Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, loadSettings(); } -void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList filePaths) { - CellNameLoader cellNameLoader; - QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(filePaths)); - std::sort(cellNamesList.begin(), cellNamesList.end()); - +void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) { // Set up an auto-completer for the "Start default character at" field - auto *completer = new QCompleter(cellNamesList); + auto *completer = new QCompleter(cellNames); completer->setCompletionMode(QCompleter::PopupCompletion); completer->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); startDefaultCharacterAtField->setCompleter(completer); @@ -165,10 +159,7 @@ void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::str mEngineSettings.setBool(setting, group, cValue); } -void Launcher::AdvancedPage::slotSelectedDataFilesChanged(QStringList selectedFiles) +void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames) { - // Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a - // barely perceptible UI lag. Splitting into its own thread to alleviate that. - std::thread loadCellsThread(&AdvancedPage::loadCellsForAutocomplete, this, selectedFiles); - loadCellsThread.join(); + loadCellsForAutocomplete(cellNames); } \ No newline at end of file diff --git a/apps/launcher/advancedpage.hpp b/apps/launcher/advancedpage.hpp index c40ae2da1..82b9c3b65 100644 --- a/apps/launcher/advancedpage.hpp +++ b/apps/launcher/advancedpage.hpp @@ -30,7 +30,7 @@ namespace Launcher void loadCellsForAutocomplete(QStringList filePaths); public slots: - void slotSelectedDataFilesChanged(QStringList selectedFiles); + void slotLoadedCellsChanged(QStringList cellNames); private slots: void on_skipMenuCheckBox_stateChanged(int state); diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 25a09ab1b..1f46c7156 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -7,7 +7,9 @@ #include #include #include +#include +#include #include #include @@ -330,6 +332,17 @@ void Launcher::DataFilesPage::slotAddonDataChanged() QStringList selectedFiles = selectedFilePaths(); if (previousSelectedFiles != selectedFiles) { previousSelectedFiles = selectedFiles; - emit signalSelectedFilesChanged(selectedFiles); + // Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a + // barely perceptible UI lag. Splitting into its own thread to alleviate that. + std::thread loadCellsThread(&DataFilesPage::reloadCells, this, selectedFiles); + loadCellsThread.join(); } +} + +void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles) +{ + CellNameLoader cellNameLoader; + QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles)); + std::sort(cellNamesList.begin(), cellNamesList.end()); + emit signalSelectedFilesChanged(cellNamesList); } \ No newline at end of file diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 8893412be..d871eeee0 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -96,6 +96,7 @@ namespace Launcher void addProfile (const QString &profile, bool setAsCurrent); void checkForDefaultProfile(); void populateFileViews(const QString& contentModelName); + void reloadCells(QStringList selectedFiles); class PathIterator { diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f3afb2732..79f3e5c67 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -142,7 +142,7 @@ void Launcher::MainDialog::createPages() connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int))); connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int))); - connect(mDataFilesPage, SIGNAL(signalSelectedFilesChanged(QStringList)), mAdvancedPage, SLOT(slotSelectedDataFilesChanged(QStringList))); + connect(mDataFilesPage, SIGNAL(signalSelectedFilesChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList))); } From de2513653e10af6648434aaf12f92bafbf5fb4fc Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 26 May 2018 19:51:50 +0400 Subject: [PATCH 203/321] AppVeyor: build with Release configuration --- CI/before_script.msvc.sh | 15 +++++++++++++-- CMakeLists.txt | 5 +---- appveyor.yml | 17 +++++++++-------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 9c12c45db..16def0f8c 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -636,6 +636,17 @@ fi -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \ -DCMAKE_PREFIX_PATH="$QT_SDK" + if [ $CONFIGURATION == "Debug" ]; then + SUFFIX="d" + else + SUFFIX="" + fi + + DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + + add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll + add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll" + echo Done. fi } @@ -710,7 +721,7 @@ if [ ! -z $CI ]; then fi # NOTE: Disable this when/if we want to run test cases -if [ -z $CI ]; then +#if [ -z $CI ]; then echo "- Copying Runtime DLLs..." mkdir -p $BUILD_CONFIG for DLL in $RUNTIME_DLLS; do @@ -742,7 +753,7 @@ if [ -z $CI ]; then cp "$DLL" "${BUILD_CONFIG}/platforms" done echo -fi +#fi if [ -z $VERBOSE ]; then printf -- "- Configuring... " diff --git a/CMakeLists.txt b/CMakeLists.txt index bfef2d328..3cd1082f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,8 +360,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter") endif() elseif (MSVC) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /Zi /bigobj") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO") # Enable link-time code generation globally for all linking if (OPENMW_LTO_BUILD) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") @@ -707,8 +705,7 @@ if (WIN32) endif() if (BUILD_OPENMW) - # Very specific issue this, only needed on 32-bit VS2015 during unity builds. - if (MSVC_VERSION GREATER 1800 AND CMAKE_SIZEOF_VOID_P EQUAL 4 AND OPENMW_UNITY_BUILD) + if (OPENMW_UNITY_BUILD) set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD} /bigobj") else() set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") diff --git a/appveyor.yml b/appveyor.yml index 21fb7e1d6..97eaa0e26 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,8 @@ platform: configuration: # - Debug - - Release + - Release +# - RelWithDebInfo # For the Qt, Boost, CMake, etc installs #os: Visual Studio 2017 @@ -48,7 +49,7 @@ install: - set PATH=C:\Program Files\Git\mingw64\bin;%PATH% before_build: - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% -v %msvc% -V + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -c %configuration% -p %PLATFORM% -v %msvc% -V build_script: - cmd: if %PLATFORM%==Win32 set build=MSVC%msvc%_32 @@ -56,8 +57,8 @@ build_script: - cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Release\ -xr"!*.pdb" - - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Release\*.pdb + - cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\%configuration%\ -xr"!*.pdb" + #- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\%configuration%\*.pdb test: off @@ -69,7 +70,7 @@ test: off # on_build_status_changed: true artifacts: - - path: OpenMW_MSVC%msvc%_x64.zip - name: OpenMW_MSVC%msvc%_x64 - - path: OpenMW_MSVC%msvc%_x64_pdb.zip - name: OpenMW_MSVC%msvc%_x64_pdb + - path: OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%.zip + name: OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit% + #- path: OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%_pdb.zip + # name: OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%_pdb From 24863f620b1ea705d76972c87b4f60668d659935 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 30 May 2018 14:43:07 +0400 Subject: [PATCH 204/321] RotateWorld: rotate around world axis (bug #4426) --- apps/openmw/mwbase/world.hpp | 2 ++ .../mwscript/transformationextensions.cpp | 25 +++++++++---------- apps/openmw/mwworld/worldimp.cpp | 9 +++++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 47502fd71..fb1450aa6 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -564,6 +564,8 @@ namespace MWBase virtual bool isPlayerInJail() const = 0; + virtual void rotateWorldObject (const MWWorld::Ptr& ptr, osg::Quat rotate) = 0; + /// Return terrain height at \a worldPos position. virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const = 0; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 5e617fb1a..611199f72 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -579,26 +579,25 @@ namespace MWScript Interpreter::Type_Float rotation = osg::DegreesToRadians(runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - const float *objRot = ptr.getRefData().getPosition().rot; + if (!ptr.getRefData().getBaseNode()) + return; - float ax = objRot[0]; - float ay = objRot[1]; - float az = objRot[2]; + // We can rotate actors only around Z axis + if (ptr.getClass().isActor() && (axis == "x" || axis == "y")) + return; + osg::Quat rot; if (axis == "x") - { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); - } + rot = osg::Quat(rotation, -osg::X_AXIS); else if (axis == "y") - { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); - } + rot = osg::Quat(rotation, -osg::Y_AXIS); else if (axis == "z") - { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); - } + rot = osg::Quat(rotation, -osg::Z_AXIS); else throw std::runtime_error ("invalid rotation axis: " + axis); + + osg::Quat attitude = ptr.getRefData().getBaseNode()->getAttitude(); + MWBase::Environment::get().getWorld()->rotateWorldObject(ptr, attitude * rot); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6cf1ead87..55e2e5dbc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1342,6 +1342,15 @@ namespace MWWorld rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust); } + void World::rotateWorldObject (const Ptr& ptr, osg::Quat rotate) + { + if(ptr.getRefData().getBaseNode() != 0) + { + mRendering->rotateObject(ptr, rotate); + mPhysics->updateRotation(ptr); + } + } + MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) { return copyObjectToCell(ptr,cell,pos,ptr.getRefData().getCount(),false); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0d168c912..1d22b96bc 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -214,6 +214,8 @@ namespace MWWorld void setWaterHeight(const float height) override; + void rotateWorldObject (const MWWorld::Ptr& ptr, osg::Quat rotate) override; + bool toggleWater() override; bool toggleWorld() override; From 84c8fb9df7c63796662a3644e1db11ea48988e93 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Jun 2018 12:41:31 +0400 Subject: [PATCH 205/321] Add pursue package only when crime was reported (bug #4433) --- .../mwmechanics/mechanicsmanagerimp.cpp | 63 ++++++++++++------- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index df93d875d..05a7e97cd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1194,16 +1194,41 @@ namespace MWMechanics reportCrime(player, victim, type, arg); else if (type == OT_Assault && !victim.isEmpty()) { + bool reported = false; if (victim.getClass().isClass(victim, "guard") && !victim.getClass().getCreatureStats(victim).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) - reportCrime(player, victim, type, arg); - else + reported = reportCrime(player, victim, type, arg); + + if (!reported) startCombat(victim, player); // TODO: combat should be started with an "unaware" flag, which makes the victim flee? } return crimeSeen; } - void MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg) + bool MechanicsManager::canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set &playerFollowers) + { + if (actor == getPlayer() + || !actor.getClass().isNpc() || actor.getClass().getCreatureStats(actor).isDead()) + return false; + + if (actor.getClass().getCreatureStats(actor).getAiSequence().isInCombat(victim)) + return false; + + // Unconsious actor can not report about crime and should not become hostile + if (actor.getClass().getCreatureStats(actor).getKnockedDown()) + return false; + + // Player's followers should not attack player, or try to arrest him + if (actor.getClass().getCreatureStats(actor).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) + { + if (playerFollowers.find(actor) != playerFollowers.end()) + return false; + } + + return true; + } + + bool MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg) { const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); @@ -1278,29 +1303,15 @@ namespace MWMechanics bool reported = false; + std::set playerFollowers; + getActorsSidingWith(player, playerFollowers); + // Tell everyone (including the original reporter) in alarm range for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if (*it == player - || !it->getClass().isNpc() || it->getClass().getCreatureStats(*it).isDead()) continue; - - if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) - continue; - - // Unconsious actor can not report about crime and should not become hostile - if (it->getClass().getCreatureStats(*it).getKnockedDown()) + if (!canReportCrime(*it, victim, playerFollowers)) continue; - // Player's followers should not attack player, or try to arrest him - if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) - { - std::set playerFollowers; - getActorsSidingWith(player, playerFollowers); - - if (playerFollowers.find(*it) != playerFollowers.end()) - continue; - } - // Will the witness report the crime? if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) { @@ -1309,8 +1320,14 @@ namespace MWMechanics if (type == OT_Trespassing) MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); } + } + + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + { + if (!canReportCrime(*it, victim, playerFollowers)) + continue; - if (it->getClass().isClass(*it, "guard")) + if (it->getClass().isClass(*it, "guard") && reported) { // Mark as Alarmed for dialogue it->getClass().getCreatureStats(*it).setAlarmed(true); @@ -1398,6 +1415,8 @@ namespace MWMechanics victim.getClass().getNpcStats(victim).setCrimeId(id); } } + + return reported; } bool MechanicsManager::actorAttacked(const MWWorld::Ptr &target, const MWWorld::Ptr &attacker) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 4bf47cb16..2e16c2793 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -224,7 +224,9 @@ namespace MWMechanics virtual bool isSneaking(const MWWorld::Ptr& ptr); private: - void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, + bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set &playerFollowers); + + bool reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); From be394870e49daa642a3998aa2f4a6d47e267e518 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Jun 2018 19:28:06 +0400 Subject: [PATCH 206/321] Fix regressions in spell resistance --- apps/openmw/mwmechanics/spellcasting.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1f78e296f..d71b4c8ba 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -221,7 +221,6 @@ namespace MWMechanics if (effects) magicEffects = effects; - float resisted = 0; // Effects with no resistance attribute belonging to them can not be resisted if (ESM::MagicEffect::getResistanceEffect(effectId) == -1) return 0.f; @@ -256,10 +255,7 @@ namespace MWMechanics } x = std::min(x + resistance, 100.f); - - resisted = x; - - return resisted; + return x; } float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, @@ -456,10 +452,11 @@ namespace MWMechanics float magnitudeMult = 1; - if (!absorbed) + if (!absorbed && target.getClass().isActor()) { + bool isHarmful = magicEffect->mData.mFlags & ESM::MagicEffect::Harmful; // Reflect harmful effects - if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && !reflected && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) + if (isHarmful && !reflected && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); bool isReflected = (Misc::Rng::roll0to99() < reflect); @@ -483,17 +480,17 @@ namespace MWMechanics else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); } - else if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && castByPlayer && target != caster) + else if (isHarmful && castByPlayer && target != caster) { // If player is attempting to cast a harmful spell and it wasn't fully resisted, show the target's HP bar MWBase::Environment::get().getWindowManager()->setEnemy(target); } - if (target == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) + if (target == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState() && isHarmful) magnitudeMult = 0; // Notify the target actor they've been hit - if (target != caster && !caster.isEmpty() && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + if (target != caster && !caster.isEmpty() && isHarmful) target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true); } From dba79f4d4dd2e59f3f1ce41c9dacdd55c99c32eb Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 2 Jun 2018 14:28:05 +0300 Subject: [PATCH 207/321] Fix warnings: catching polymorphic type by value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openmw/apps/openmw/mwworld/worldimp.cpp: In member function ‘virtual bool MWWorld::World::findExteriorPosition(const string&, ESM::Position&)’: openmw/apps/openmw/mwworld/worldimp.cpp:2650:25: warning: catching polymorphic type ‘class std::invalid_argument’ by value [-Wcatch-value=] catch (std::invalid_argument) ^~~~~~~~~~~~~~~~ openmw/apps/openmw/mwworld/worldimp.cpp:2654:25: warning: catching polymorphic type ‘class std::out_of_range’ by value [-Wcatch-value=] catch (std::out_of_range) ^~~~~~~~~~~~ openmw/components/widgets/numericeditbox.cpp: In member function ‘void Gui::NumericEditBox::onEditTextChange(MyGUI::EditBox*)’: openmw/components/widgets/numericeditbox.cpp:41:21: warning: catching polymorphic type ‘class std::invalid_argument’ by value [-Wcatch-value=] catch (std::invalid_argument) ^~~~~~~~~~~~~~~~ openmw/components/widgets/numericeditbox.cpp:45:21: warning: catching polymorphic type ‘class std::out_of_range’ by value [-Wcatch-value=] catch (std::out_of_range) ^~~~~~~~~~~~ --- apps/openmw/mwworld/worldimp.cpp | 4 ++-- components/widgets/numericeditbox.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6cf1ead87..6579996d2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2601,11 +2601,11 @@ namespace MWWorld int y = std::stoi(name.substr(name.find(',')+1)); ext = getExterior(x, y)->getCell(); } - catch (std::invalid_argument) + catch (const std::invalid_argument&) { // This exception can be ignored, as this means that name probably refers to a interior cell instead of comma separated coordinates } - catch (std::out_of_range) + catch (const std::out_of_range&) { throw std::runtime_error("Cell coordinates out of range."); } diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index ee2c30a7b..efe480653 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -38,11 +38,11 @@ namespace Gui setCaption(MyGUI::utility::toString(mValue)); } } - catch (std::invalid_argument) + catch (const std::invalid_argument&) { setCaption(MyGUI::utility::toString(mValue)); } - catch (std::out_of_range) + catch (const std::out_of_range&) { setCaption(MyGUI::utility::toString(mValue)); } From eecde340cf33dbf2d30a696e68948253c710f01e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 2 Jun 2018 15:41:05 +0300 Subject: [PATCH 208/321] Make weapon health short unsigned (fixes #4435) --- components/esm/loadweap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index eddcaee4f..8b48b71b7 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -57,7 +57,7 @@ struct Weapon float mWeight; int mValue; short mType; - short mHealth; + unsigned short mHealth; float mSpeed, mReach; short mEnchant; // Enchantment points. The real value is mEnchant/10.f unsigned char mChop[2], mSlash[2], mThrust[2]; // Min and max From e26c67582920709344036f54bb245086195408f7 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 2 Jun 2018 17:29:35 -0500 Subject: [PATCH 209/321] Changing join to detach so that the thread will not block the UI --- apps/launcher/datafilespage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 1f46c7156..bcb2966d5 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -335,7 +335,7 @@ void Launcher::DataFilesPage::slotAddonDataChanged() // Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a // barely perceptible UI lag. Splitting into its own thread to alleviate that. std::thread loadCellsThread(&DataFilesPage::reloadCells, this, selectedFiles); - loadCellsThread.join(); + loadCellsThread.detach(); } } From 191cc76378a71966dda8e11e4933b78034a483bc Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 3 Jun 2018 09:46:12 +0300 Subject: [PATCH 210/321] Consider faction ownerships in item stolen checks (fixes #4293) --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 3 +-- apps/openmw/mwgui/tradewindow.cpp | 3 +-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 9 +++++++-- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index e40bf56bb..f15a86918 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -239,7 +239,7 @@ namespace MWBase virtual std::vector > getStolenItemOwners(const std::string& itemid) = 0; /// Has the player stolen this item from the given owner? - virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; + virtual bool isItemStolenFrom(const std::string& itemid, const MWWorld::Ptr& ptr) = 0; virtual bool isBoundItem(const MWWorld::Ptr& item) = 0; virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3616b8b62..f7764e0f1 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -339,8 +339,7 @@ namespace MWGui for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); - if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), - mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr)) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2eeeafe0d..0a9fe1b4a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -311,8 +311,7 @@ namespace MWGui // check if the player is attempting to sell back an item stolen from this actor for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { - if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), - mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr)) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index df93d875d..25fc5c704 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -992,14 +992,19 @@ namespace MWMechanics } } - bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid) + bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const MWWorld::Ptr& ptr) { StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); if (it == mStolenItems.end()) return false; + const OwnerMap& owners = it->second; + const std::string ownerid = ptr.getCellRef().getRefId(); + const std::string factionid = ptr.getClass().getPrimaryFaction(ptr); OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); - return ownerFound != owners.end(); + OwnerMap::const_iterator factionOwnerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); + + return ownerFound != owners.end() || factionOwnerFound != owners.end(); } void MechanicsManager::confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 4bf47cb16..ede83b962 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -205,7 +205,7 @@ namespace MWMechanics virtual std::vector > getStolenItemOwners(const std::string& itemid); /// Has the player stolen this item from the given owner? - virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + virtual bool isItemStolenFrom(const std::string& itemid, const MWWorld::Ptr& ptr); virtual bool isBoundItem(const MWWorld::Ptr& item); From 3810ade67a7f473fcc8da9fc20afd8943e74784a Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 3 Jun 2018 10:50:10 +0300 Subject: [PATCH 211/321] Don't make unnecessary faction ID searches --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 25fc5c704..8da2c86d2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1000,11 +1000,18 @@ namespace MWMechanics const OwnerMap& owners = it->second; const std::string ownerid = ptr.getCellRef().getRefId(); - const std::string factionid = ptr.getClass().getPrimaryFaction(ptr); OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); - OwnerMap::const_iterator factionOwnerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); + if (ownerFound != owners.end()) + return true; - return ownerFound != owners.end() || factionOwnerFound != owners.end(); + const std::string factionid = ptr.getClass().getPrimaryFaction(ptr); + if (!factionid.empty()) + { + OwnerMap::const_iterator factionOwnerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); + return factionOwnerFound != owners.end(); + } + + return false; } void MechanicsManager::confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) From c71df7249da6295774df2c3f156730157ef9c792 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 26 May 2018 16:09:12 +0300 Subject: [PATCH 212/321] Fix UTF-8 econding To be able run gcovr --- extern/oics/ICSInputControlSystem_mouse.cpp | 4 ++-- extern/oics/tinystr.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index 5decaf1eb..e389bc981 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -268,11 +268,11 @@ namespace ICS ctrl->setIgnoreAutoReverse(true); if(mouseBinderItem.direction == Control::INCREASE) { - ctrl->setValue( float( (evt.state.Z.abs) / float(evt.state.width?) ) ); + ctrl->setValue( float( (evt.state.Z.abs) / float(evt.state.¿width?) ) ); } else if(mouseBinderItem.direction == Control::DECREASE) { - ctrl->setValue( float( (1 - evt.state.Z.abs) / float(evt.state.width?) ) ); + ctrl->setValue( float( (1 - evt.state.Z.abs) / float(evt.state.¿width?) ) ); } }*/ } diff --git a/extern/oics/tinystr.cpp b/extern/oics/tinystr.cpp index 681250714..635e84b5f 100644 --- a/extern/oics/tinystr.cpp +++ b/extern/oics/tinystr.cpp @@ -23,7 +23,7 @@ distribution. */ /* - * THIS FILE WAS ALTERED BY Tyge Lvset, 7. April 2005. + * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. */ From c14536a399b317d2a2d724333ca17602fbd92307 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 3 Jun 2018 13:02:27 +0300 Subject: [PATCH 213/321] Update faction-owned items confiscation --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8da2c86d2..4a773bdc7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1029,6 +1029,13 @@ namespace MWMechanics owner.first = victim.getCellRef().getRefId(); owner.second = false; + const std::string victimFaction = victim.getClass().getPrimaryFaction(victim); + if (!victimFaction.empty() && Misc::StringUtils::ciEqual(item.getCellRef().getFaction(), victimFaction)) // Is the item faction-owned? + { + owner.first = victimFaction; + owner.second = true; + } + Misc::StringUtils::lowerCaseInPlace(owner.first); // decrease count of stolen items From 103a7ac62882d196b9fd12c9afa374f17a5e856f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 3 Jun 2018 16:32:12 -0500 Subject: [PATCH 214/321] Using a mutex lock to prevent race conditions --- apps/launcher/datafilespage.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index bcb2966d5..76ca893c4 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -339,8 +339,16 @@ void Launcher::DataFilesPage::slotAddonDataChanged() } } +// Mutex lock to run reloadCells synchronously. +std::mutex _reloadCellsMutex; + void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles) { + // Use a mutex lock so that we can prevent two threads from executing the rest of this code at the same time + // Based on https://stackoverflow.com/a/5429695/531762 + std::unique_lock lock(_reloadCellsMutex); + + // The following code will run only if there is not another thread currently running it CellNameLoader cellNameLoader; QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles)); std::sort(cellNamesList.begin(), cellNamesList.end()); From e282ece3d14bda73938cce38412a932d74826246 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 3 Jun 2018 16:58:18 -0500 Subject: [PATCH 215/321] Fixing bug with autocomplete not loading correctly during startup --- apps/launcher/advancedpage.hpp | 11 +++++------ apps/launcher/datafilespage.cpp | 3 +++ apps/launcher/maindialog.cpp | 3 --- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/launcher/advancedpage.hpp b/apps/launcher/advancedpage.hpp index 82b9c3b65..59de3d319 100644 --- a/apps/launcher/advancedpage.hpp +++ b/apps/launcher/advancedpage.hpp @@ -23,12 +23,6 @@ namespace Launcher bool loadSettings(); void saveSettings(); - /** - * Load the cells associated with the given content files for use in autocomplete - * @param filePaths the file paths of the content files to be examined - */ - void loadCellsForAutocomplete(QStringList filePaths); - public slots: void slotLoadedCellsChanged(QStringList cellNames); @@ -41,6 +35,11 @@ namespace Launcher Config::GameSettings &mGameSettings; Settings::Manager &mEngineSettings; + /** + * Load the cells associated with the given content files for use in autocomplete + * @param filePaths the file paths of the content files to be examined + */ + void loadCellsForAutocomplete(QStringList filePaths); void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group); void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group); }; diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 76ca893c4..b3c8fb14a 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "utils/textinputdialog.hpp" #include "utils/profilescombobox.hpp" @@ -47,6 +48,8 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config: // the addons and don't want to get signals of the system doing it during startup. connect(mSelector, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex)), this, SLOT(slotAddonDataChanged())); + // Call manually to indicate all changes to addon data during startup. + slotAddonDataChanged(); } void Launcher::DataFilesPage::buildView() diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 79f3e5c67..a70f6ff7f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -125,9 +125,6 @@ void Launcher::MainDialog::createPages() mPlayPage->setProfilesModel(mDataFilesPage->profilesModel()); mPlayPage->setProfilesIndex(mDataFilesPage->profilesIndex()); - // Load cells for the "Start default character at" field - mAdvancedPage->loadCellsForAutocomplete(mDataFilesPage->selectedFilePaths()); - // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); pagesWidget->addWidget(mDataFilesPage); From d46590934af75c265b6fd1894acbdc306b470c7d Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 3 Jun 2018 16:59:27 -0500 Subject: [PATCH 216/321] Importing mutex --- apps/launcher/datafilespage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index b3c8fb14a..6c23b3285 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include From cae744161bfe7b22612ce54a96399d919fd5b2ed Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Jun 2018 15:08:22 +0200 Subject: [PATCH 217/321] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cd1082f0..15ca3efb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 43) +set(OPENMW_VERSION_MINOR 44) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index 368609332..d6a3323a1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.43.0 +* Version: 0.44.0 * License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information) * Website: https://www.openmw.org * IRC: #openmw on irc.freenode.net From 2193983a6941d21739723fc0def7fa04640dfe2b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Jun 2018 15:14:35 +0200 Subject: [PATCH 218/321] updated changelog --- CHANGELOG.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac2a5472e..3dcad4598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,101 @@ +0.44.0 +------ + + Bug #1428: Daedra summoning scripts aren't executed when the item is taken through the inventory + Bug #1987: Some glyphs are not supported + Bug #2254: Magic related visual effects are not rendered when loading a saved game + Bug #2485: Journal alphabetical index doesn't match "Morrowind content language" setting + Bug #2703: OnPCHitMe is not handled correctly + Bug #2829: Incorrect order for content list consisting of a game file and an esp without dependencies + Bug #2841: "Total eclipse" happens if weather settings are not defined. + Bug #2897: Editor: Rename "Original creature" field + Bug #3278: Editor: Unchecking "Auto Calc" flag changes certain values + Bug #3343: Editor: ID sorting is case-sensitive in certain tables + Bug #3557: Resource priority confusion when using the local data path as installation root + Bug #3587: Pathgrid and Flying Creatures wrong behaviour – abotWhereAreAllBirdsGoing + Bug #3603: SetPos should not skip weather transitions + Bug #3618: Myar Aranath total conversion can't be started due to capital-case extension of the master file + Bug #3638: Fast forwarding can move NPC inside objects + Bug #3664: Combat music does not start in dialogue + Bug #3696: Newlines are accompanied by empty rectangle glyph in dialogs + Bug #3708: Controllers broken on macOS + Bug #3726: Items with suppressed activation can be picked up via the inventory menu + Bug #3783: [Mod] Abot's Silt Striders 1.16 - silt strider "falls" to ground and glides on floor during travel + Bug #3863: Can be forced to not resist arrest if you cast Calm Humanoid on aggroed death warrant guards + Bug #3884: Incorrect enemy behavior when exhausted + Bug #3926: Installation Wizard places Morrowind.esm after Tribunal/Bloodmoon if it has a later file creation date + Bug #4061: Scripts error on special token included in name + Bug #4111: Crash when mouse over soulgem with a now-missing soul + Bug #4122: Swim animation should not be interrupted during underwater attack + Bug #4134: Battle music behaves different than vanilla + Bug #4135: Reflecting an absorb spell different from vanilla + Bug #4136: Enchanted weapons without "ignore normal weapons" flag don't bypass creature "ignore normal weapons" effect + Bug #4143: Antialiasing produces graphical artifacts when used with shader lighting + Bug #4159: NPCs' base skeleton files should not be optimized + Bug #4177: Jumping/landing animation interference/flickering + Bug #4179: NPCs do not face target + Bug #4180: Weapon switch sound playing even though no weapon is switched + Bug #4184: Guards can initiate dialogue even though you are far above them + Bug #4190: Enchanted clothes changes visibility with Chameleon on equip/unequip + Bug #4191: "screenshot saved" message also appears in the screenshot image + Bug #4192: Archers in OpenMW have shorter attack range than archers in Morrowind + Bug #4210: Some dialogue topics are not highlighted on first encounter + Bug #4211: FPS drops after minimizing the game during rainy weather + Bug #4216: Thrown weapon projectile doesn't rotate + Bug #4223: Displayed spell casting chance must be 0 if player doesn't have enough magicka to cast it + Bug #4225: Double "Activate" key presses with Mouse and Gamepad. + Bug #4226: The current player's class should be default value in the class select menu + Bug #4229: Tribunal/Bloodmoon summoned creatures fight other summons + Bug #4233: W and A keys override S and D Keys + Bug #4235: Wireframe mode affects local map + Bug #4239: Quick load from container screen causes crash + Bug #4242: Crime greetings display in Journal + Bug #4245: Merchant NPCs sell ingredients growing on potted plants they own + Bug #4246: Take armor condition into account when calcuting armor rating + Bug #4250: Jumping is not as fluid as it was pre-0.43.0 + Bug #4252: "Error in frame: FFmpeg exception: Failed to allocate input stream" message spam if OpenMW encounter non-music file in the Music folder + Bug #4261: Magic effects from eaten ingredients always have 1 sec duration + Bug #4263: Arrow position is incorrect in 3rd person view during attack for beast races + Bug #4264: Player in god mode can be affected by some negative spell effects + Bug #4269: Crash when hovering the faction section and the 'sAnd' GMST is missing (as in MW 1.0) + Bug #4272: Root note transformations are discarded again + Bug #4279: Sometimes cells are not marked as explored on the map + Bug #4298: Problem with MessageBox and chargen menu interaction order + Bug #4301: Optimizer breaks LOD nodes + Bug #4308: PlaceAtMe doesn't inherit scale of calling object + Bug #4309: Only harmful effects with resistance effect set are resistable + Bug #4313: Non-humanoid creatures are capable of opening doors + Bug #4314: Rainy weather slows down the game when changing from indoors/outdoors + Bug #4319: Collisions for certain meshes are incorrectly ignored + Bug #4320: Using mouse 1 to move forward causes selection dialogues to jump selections forward. + Bug #4322: NPC disposition: negative faction reaction modifier doesn't take PC rank into account + Bug #4328: Ownership by dead actors is not cleared from picked items + Bug #4334: Torch and shield usage inconsistent with original game + Bug #4336: Wizard: Incorrect Morrowind assets path autodetection + Bug #4343: Error message for coc and starting cell shouldn't imply that it only works for interior cells + Bug #4346: Count formatting does not work well with very high numbers + Bug #4351: Using AddSoulgem fills all soul gems of the specified type + Bug #4391: No visual indication is provided when an unavailable spell fails to be chosen via a quick key + Bug #4392: Inventory filter breaks after loading a game + Bug #4405: No default terrain in empty cells when distant terrain is enabled + Bug #4410: [Mod] Arktwend: OpenMW does not use default marker definitions + Bug #4412: openmw-iniimporter ignores data paths from config + Bug #4413: Moving with 0 strength uses all of your fatigue + Bug #4420: Camera flickering when I open up and close menus while sneaking + Bug #4435: Item health is considered a signed integer + Feature #1786: Round up encumbrance value in the encumbrance bar + Feature #2694: Editor: rename "model" column to make its purpose clear + Feature #3870: Editor: Terrain Texture Brush Button + Feature #3872: Editor: Edit functions in terrain texture editing mode + Feature #4054: Launcher: Create menu for settings.cfg options + Feature #4064: Option for fast travel services to charge for the first companion + Feature #4142: Implement fWereWolfHealth GMST + Feature #4174: Multiple quicksaves + Feature #4407: Support NiLookAtController + Feature #4423: Rebalance soul gem values + Task #4015: Use AppVeyor build artifact features to make continuous builds available + Editor: New (and more complete) icon set + 0.43.0 ------ From 13f7b53b1caeec5abc3e07e1c4f7c3e50a1ae249 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Jun 2018 17:08:09 +0200 Subject: [PATCH 219/321] Revert "Don't force DDS file usage (fixes #1392)" This reverts commit 90f3ff2da4b37a6766e0eb369150d866ec488d06. --- components/misc/resourcehelpers.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index f38387ff8..5cf4378b8 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -63,16 +63,28 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev std::string origExt = correctedPath; - if (vfs->exists(origExt) - || (changeExtensionToDds(correctedPath) && vfs->exists(correctedPath))) + // since we know all (GOTY edition or less) textures end + // in .dds, we change the extension + bool changedToDds = changeExtensionToDds(correctedPath); + if (vfs->exists(correctedPath)) return correctedPath; + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if (changedToDds && vfs->exists(origExt)) + return origExt; // fall back to a resource in the top level directory if it exists - std::string fallback = topLevelDirectory + "\\" + getBasename(origExt); - if (vfs->exists(fallback) - || (changeExtensionToDds(fallback) && vfs->exists(fallback))) + std::string fallback = topLevelDirectory + "\\" + getBasename(correctedPath); + if (vfs->exists(fallback)) return fallback; + if (changedToDds) + { + fallback = topLevelDirectory + "\\" + getBasename(origExt); + if (vfs->exists(fallback)) + return fallback; + } + return correctedPath; } From 7605d928dbcc4c4fa6b0022fc40afa8d5e3e26c0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Jun 2018 11:03:04 +0200 Subject: [PATCH 220/321] added section for 0.45 to changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dcad4598..49c0f3ef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +0.45.0 +------ + + 0.44.0 ------ From 04a202534085186d93911c7195489e79c384e596 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 5 Jun 2018 18:09:10 +0300 Subject: [PATCH 221/321] Fix crash when adding items to certain disabled creatures (bug #4441) --- apps/openmw/mwrender/objects.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f0a3d2e38..db6772eaa 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -123,11 +123,12 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr) mObjects.erase(iter); - if (ptr.getClass().isNpc()) + if (ptr.getClass().isActor()) { - MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr); - store.setInvListener(NULL, ptr); - store.setContListener(NULL); + if (ptr.getClass().hasInventoryStore(ptr)) + ptr.getClass().getInventoryStore(ptr).setInvListener(NULL, ptr); + + ptr.getClass().getContainerStore(ptr).setContListener(NULL); } ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); From 98063c5afcd4b967dd66b83f1fb1c37288c95031 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 6 Jun 2018 09:50:33 +0200 Subject: [PATCH 222/321] updated changelog with last-minute crash-bug fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49c0f3ef3..7a958fbc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ Bug #4413: Moving with 0 strength uses all of your fatigue Bug #4420: Camera flickering when I open up and close menus while sneaking Bug #4435: Item health is considered a signed integer + Bug #4441: Adding items to currently disabled weapon-wielding creatures crashes the game Feature #1786: Round up encumbrance value in the encumbrance bar Feature #2694: Editor: rename "model" column to make its purpose clear Feature #3870: Editor: Terrain Texture Brush Button From fb3facde548c1b79fa640f1d927cabbc24b85c7a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jun 2018 13:21:14 +0200 Subject: [PATCH 223/321] updated changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a958fbc0..8cbef559d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ 0.45.0 ------ - + Bug #4293: Faction members are not aware of faction ownerships in barter + Bug #4426: RotateWorld behavior is incorrect + Bug #4433: Guard behaviour is incorrect with Alarm = 0 0.44.0 ------ From ab433102a49057d8ae4eb7219674e75960313045 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 9 May 2018 10:31:53 +0400 Subject: [PATCH 224/321] Increase hit distance for player by halfExtents --- apps/openmw/mwworld/worldimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 13970ee13..61bed46f7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1074,6 +1074,7 @@ namespace MWWorld osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); + osg::Vec3f halfExtents = mPhysics->getHalfExtents(ptr); if (ptr == getPlayerPtr()) pos = getActorHeadTransform(ptr).getTrans(); // special cased for better aiming with the camera @@ -1082,11 +1083,12 @@ namespace MWWorld // general case, compatible with all types of different creatures // note: we intentionally do *not* use the collision box offset here, this is required to make // some flying creatures work that have their collision box offset in the air - osg::Vec3f halfExtents = mPhysics->getHalfExtents(ptr); pos.z() += halfExtents.z() * 2 * 0.75; - distance += halfExtents.y(); } + // the origin of hitbox is an actor's front, not center + distance += halfExtents.y(); + std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance, targets); if(result.first.isEmpty()) return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); From f5dc9f01620306c147c1428a1bb39eee0c286acf Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 9 May 2018 10:53:53 +0400 Subject: [PATCH 225/321] Use hitbox cone only as fallback --- apps/openmw/mwphysics/physicssystem.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f3c34bc4e..4830760af 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -846,6 +846,16 @@ namespace MWPhysics const osg::Quat &orient, float queryDistance, std::vector targets) { + // First of all, try to hit where you aim to + int hitmask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; + RayResult result = castRay(origin, origin + (orient * osg::Vec3f(0.0f, queryDistance, 0.0f)), actor, targets, 0xff, hitmask); + + if (result.mHit) + { + return std::make_pair(result.mHitObject, result.mHitPos); + } + + // Use cone shape as fallback const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); btConeShape shape (osg::DegreesToRadians(store.find("fCombatAngleXY")->getFloat()/2.0f), queryDistance); From 9e5d577a71dab1fffec695121b400e9b4f675b93 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 9 May 2018 11:35:51 +0400 Subject: [PATCH 226/321] Aim from center of attacker to center of target --- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 61bed46f7..586fc7816 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1083,7 +1083,7 @@ namespace MWWorld // general case, compatible with all types of different creatures // note: we intentionally do *not* use the collision box offset here, this is required to make // some flying creatures work that have their collision box offset in the air - pos.z() += halfExtents.z() * 2 * 0.75; + pos.z() += halfExtents.z(); } // the origin of hitbox is an actor's front, not center @@ -3468,7 +3468,7 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const ConstPtr &actor, const MWWorld::ConstPtr& target) { osg::Vec3f weaponPos = actor.getRefData().getPosition().asVec3(); - weaponPos.z() += mPhysics->getHalfExtents(actor).z() * 2 * 0.75; + weaponPos.z() += mPhysics->getHalfExtents(actor).z(); osg::Vec3f targetPos = mPhysics->getCollisionObjectPosition(target); return (targetPos - weaponPos); } @@ -3477,7 +3477,7 @@ namespace MWWorld { osg::Vec3f weaponPos = actor.getRefData().getPosition().asVec3(); osg::Vec3f halfExtents = mPhysics->getHalfExtents(actor); - weaponPos.z() += halfExtents.z() * 2 * 0.75; + weaponPos.z() += halfExtents.z(); return mPhysics->getHitDistance(weaponPos, target) - halfExtents.y(); } From 4666a6a0abc221806fda56c85c5d5b910ef5f51d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 9 May 2018 12:53:58 +0400 Subject: [PATCH 227/321] Use default hit formula as fallback --- apps/openmw/mwworld/worldimp.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 586fc7816..8423adedc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1073,21 +1073,28 @@ namespace MWWorld osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); osg::Vec3f halfExtents = mPhysics->getHalfExtents(ptr); + // the origin of hitbox is an actor's front, not center + distance += halfExtents.y(); + + // special cased for better aiming with the camera + // if we do not hit anything, will use the default approach as fallback if (ptr == getPlayerPtr()) - pos = getActorHeadTransform(ptr).getTrans(); // special cased for better aiming with the camera - else { - // general case, compatible with all types of different creatures - // note: we intentionally do *not* use the collision box offset here, this is required to make - // some flying creatures work that have their collision box offset in the air - pos.z() += halfExtents.z(); + osg::Vec3f pos = getActorHeadTransform(ptr).getTrans(); + + std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance, targets); + if(!result.first.isEmpty()) + return std::make_pair(result.first, result.second); } - // the origin of hitbox is an actor's front, not center - distance += halfExtents.y(); + osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); + + // general case, compatible with all types of different creatures + // note: we intentionally do *not* use the collision box offset here, this is required to make + // some flying creatures work that have their collision box offset in the air + pos.z() += halfExtents.z(); std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance, targets); if(result.first.isEmpty()) From bde1d07d4eb756da90f31698aa154920fa102cd1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 15 May 2018 18:57:36 +0400 Subject: [PATCH 228/321] Use hitboxes and focused object for touch spells (bug #3374) --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 94 +++++++++++++------------ 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 4830760af..625ae5573 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -848,7 +848,7 @@ namespace MWPhysics { // First of all, try to hit where you aim to int hitmask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; - RayResult result = castRay(origin, origin + (orient * osg::Vec3f(0.0f, queryDistance, 0.0f)), actor, targets, 0xff, hitmask); + RayResult result = castRay(origin, origin + (orient * osg::Vec3f(0.0f, queryDistance, 0.0f)), actor, targets, CollisionType_Actor, hitmask); if (result.mHit) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8423adedc..cbd5b9340 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2761,64 +2761,66 @@ namespace MWWorld { MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - // Get the target to use for "on touch" effects, using the facing direction from Head node - MWWorld::Ptr target; - float distance = getActivationDistancePlusTelekinesis(); - - osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - osg::Vec3f origin = getActorHeadTransform(actor).getTrans(); - - osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) - * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); - - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); - osg::Vec3f dest = origin + direction * distance; - // For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result. std::vector targetActors; if (!actor.isEmpty() && actor != MWMechanics::getPlayer()) actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors); - // For actor targets, we want to use bounding boxes (physics raycast). - // This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise. - // For object targets, we want the detailed shapes (rendering raycast). - // If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf. + const float fCombatDistance = getStore().get().find("fCombatDistance")->getFloat(); - MWPhysics::PhysicsSystem::RayResult result1 = mPhysics->castRay(origin, dest, actor, targetActors, MWPhysics::CollisionType_Actor); - - MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); + osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - float dist1 = std::numeric_limits::max(); - float dist2 = std::numeric_limits::max(); + // for player we can take faced object first + MWWorld::Ptr target; + if (actor == MWMechanics::getPlayer()) + target = getFacedObject(); - if (result1.mHit) - dist1 = (origin - result1.mHitPos).length(); - if (result2.mHit) - dist2 = (origin - result2.mHitPointWorld).length(); + // if the faced object can not be activated, do not use it + if (!target.isEmpty() && !target.getClass().canBeActivated(target)) + target = NULL; - if (result1.mHit) - { - target = result1.mHitObject; - hitPosition = result1.mHitPos; - if (dist1 > getMaxActivationDistance() && !target.isEmpty() && (target.getClass().isActor() || !target.getClass().canBeActivated(target))) - target = NULL; - } - else if (result2.mHit) + if (target.isEmpty()) { - target = result2.mHitObject; - hitPosition = result2.mHitPointWorld; - if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target)) - target = NULL; - } + // For actor targets, we want to use hit contact with bounding boxes. + // This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise. + // For object targets, we want the detailed shapes (rendering raycast). + // If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf. + std::pair result1 = getHitContact(actor, fCombatDistance, targetActors); - // When targeting an actor that is in combat with an "on touch" spell, - // compare against the minimum of activation distance and combat distance. + // Get the target to use for "on touch" effects, using the facing direction from Head node + osg::Vec3f origin = getActorHeadTransform(actor).getTrans(); - if (!target.isEmpty() && target.getClass().isActor() && target.getClass().getCreatureStats (target).getAiSequence().isInCombat()) - { - distance = std::min (distance, getStore().get().find("fCombatDistance")->getFloat()); - if (distance < dist1) - target = NULL; + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); + + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + float distance = getMaxActivationDistance(); + osg::Vec3f dest = origin + direction * distance; + + MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); + + float dist1 = std::numeric_limits::max(); + float dist2 = std::numeric_limits::max(); + + if (!result1.first.isEmpty() && result1.first.getClass().isActor()) + dist1 = (origin - result1.second).length(); + if (result2.mHit) + dist2 = (origin - result2.mHitPointWorld).length(); + + if (!result1.first.isEmpty() && result1.first.getClass().isActor()) + { + target = result1.first; + hitPosition = result1.second; + if (dist1 > getMaxActivationDistance()) + target = NULL; + } + else if (result2.mHit) + { + target = result2.mHitObject; + hitPosition = result2.mHitPointWorld; + if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target)) + target = NULL; + } } std::string selectedSpell = stats.getSpells().getSelectedSpell(); From 1b9edbe119a16bb132d75380b62e3f4e0d02597c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 2 May 2018 14:13:49 +0400 Subject: [PATCH 229/321] Add unequip animation during stance switching (bug #4327) --- apps/openmw/mwmechanics/character.cpp | 93 +++++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 68dc17915..a0aad8b1b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -749,6 +749,7 @@ void CharacterController::playRandomDeath(float startpoint) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim) : mPtr(ptr) + , mWeapon(MWWorld::Ptr()) , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) @@ -1156,17 +1157,26 @@ bool CharacterController::updateWeaponState() const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf(); - std::string soundid; + std::string upSoundId; + std::string downSoundId; if (mPtr.getClass().hasInventoryStore(mPtr)) { MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); - MWWorld::ConstContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); - if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell)) - { - soundid = (weaptype == WeapType_None) ? - weapon->getClass().getDownSoundId(*weapon) : - weapon->getClass().getUpSoundId(*weapon); - } + MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + if(stats.getDrawState() == DrawState_Spell) + weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if(weapon != inv.end() && mWeaponType != WeapType_HandToHand && weaptype > WeapType_HandToHand && weaptype < WeapType_Spell) + upSoundId = weapon->getClass().getUpSoundId(*weapon); + + if(weapon != inv.end() && mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell) + downSoundId = weapon->getClass().getDownSoundId(*weapon); + + // weapon->HtH switch: weapon is empty already, so we need to take sound from previous weapon + if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == WeapType_HandToHand && mWeaponType != WeapType_Spell) + downSoundId = mWeapon.getClass().getDownSoundId(mWeapon); + + mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr(); } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); @@ -1181,34 +1191,51 @@ bool CharacterController::updateWeaponState() if(weaptype != mWeaponType && !isKnockedOut() && !isKnockedDown() && !isRecovery()) { - forcestateupdate = true; - - mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype)); - std::string weapgroup; - if(weaptype == WeapType_None) + if ((!isWerewolf || mWeaponType != WeapType_Spell) + && mUpperBodyState != UpperCharState_UnEquipingWeap + && !isStillWeapon) { - if (!isWerewolf || mWeaponType != WeapType_Spell) + // Note: we do not disable unequipping animation automatically to avoid body desync + getWeaponGroup(mWeaponType, weapgroup); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, false, + 1.0f, "unequip start", "unequip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_UnEquipingWeap; + + if(!downSoundId.empty()) { - getWeaponGroup(mWeaponType, weapgroup); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "unequip start", "unequip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_UnEquipingWeap; + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, downSoundId, 1.0f, 1.0f); } } - else + + float complete; + bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); + if (!animPlaying || complete >= 1.0f) { + mUpperBodyState = UpperCharState_Nothing; + forcestateupdate = true; + mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype)); + getWeaponGroup(weaptype, weapgroup); mAnimation->setWeaponGroup(weapgroup); if (!isStillWeapon) { - mAnimation->showWeapons(false); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "equip start", "equip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_EquipingWeap; + if (weaptype == WeapType_None) + { + // Disable current weapon animation manually + mAnimation->disable(mCurrentWeapon); + } + else + { + mAnimation->showWeapons(false); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, + 1.0f, "equip start", "equip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_EquipingWeap; + } } if(isWerewolf) @@ -1221,16 +1248,16 @@ bool CharacterController::updateWeaponState() sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f); } } - } - if(!soundid.empty() && !isStillWeapon) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); - } + mWeaponType = weaptype; + getWeaponGroup(mWeaponType, mCurrentWeapon); - mWeaponType = weaptype; - getWeaponGroup(mWeaponType, mCurrentWeapon); + if(!upSoundId.empty() && !isStillWeapon) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f); + } + } } if(isWerewolf) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cab51b82f..a172620b9 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -152,6 +152,7 @@ struct WeaponInfo; class CharacterController : public MWRender::Animation::TextKeyListener { MWWorld::Ptr mPtr; + MWWorld::Ptr mWeapon; MWRender::Animation *mAnimation; struct AnimationQueueEntry From 6eb531c6ace5411767ede50d4f1eec478a927533 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Jun 2018 16:22:52 +0400 Subject: [PATCH 230/321] Add missing changelog entries --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbef559d..3b38b6bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ 0.45.0 ------ + Bug #2835: Player able to slowly move when overencumbered Bug #4293: Faction members are not aware of faction ownerships in barter + Bug #4327: Missing animations during spell/weapon stance switching Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 From a1ab1dc7fe19b231de3629cbaeb9467a2b9300e5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 7 Jun 2018 15:28:45 +0100 Subject: [PATCH 231/321] Add easily understood error messages to the prebuild script instead of vague/silent failures. --- CI/before_script.msvc.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 16def0f8c..dd8d830b8 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -1,5 +1,23 @@ #!/bin/bash +MISSINGTOOLS=0 + +command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; } +command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; } + +if [ $MISSINGTOOLS -ne 0 ]; then + exit 1 +fi + +WORKINGDIR="$(pwd)" +case "$WORKINGDIR" in + *[[:space:]]*) + echo "Error: Working directory contains spaces." + exit 1 + ;; +esac + + set -euo pipefail APPVEYOR=${APPVEYOR:-} From 02f1f712219544e1e9a110492794c88466d0effd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Jun 2018 18:42:09 +0400 Subject: [PATCH 232/321] Use link to OpenMW Wiki page instead of direct NifSkope page --- docs/source/reference/modding/convert_bump_mapped_mods.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/source/reference/modding/convert_bump_mapped_mods.rst b/docs/source/reference/modding/convert_bump_mapped_mods.rst index 1891b5c4d..421fa67a7 100644 --- a/docs/source/reference/modding/convert_bump_mapped_mods.rst +++ b/docs/source/reference/modding/convert_bump_mapped_mods.rst @@ -22,7 +22,7 @@ General introduction to normal map conversion This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. -*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope. There are binaries available for Windows, but not for Mac or Linux. Reports say that NifSkope versions 1.X will compile on Linux as long as you have Qt packages installed, while the later 2.X versions will not compile. +*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope_. *Another note:* I will use the terms bump mapping and normal mapping simultaneously. Normal mapping is one form of bump mapping. In other words, normal mapping is bump mapping, but bump mapping isn't necessarily normal mapping. There are several techniques for bump mapping, and normal mapping is the most common one today. @@ -160,8 +160,6 @@ Converting Apel's Various Things - Sacks In part one of this tutorial, we converted a mod that only included modified Morrowind model (``.nif``) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time. -Before we begin, you need to know that unless you want to build the NifSkope application from source yourself, you will be needing a Windows OS to do this part, since the application only has binaries available for Windows. - Tutorial - MCP, Part 2 ********************** @@ -196,7 +194,7 @@ Since these models have one or two textures applied to them, the fix was not tha .. _`Multiple data folders`: https://wiki.openmw.org/index.php?title=Mod_installation .. _`Various Things - Sacks`: https://www.nexusmods.com/morrowind/mods/42558/? .. _Lead: https://imgur.com/bwpcYlc -.. _NifSkope: http://niftools.sourceforge.net/wiki/NifSkope +.. _NifSkope: https://wiki.openmw.org/index.php?title=Tools#NifSkope .. _Blocks: https://imgur.com/VmQC0WG .. _`no longer have shiny models`: https://imgur.com/vu1k7n1 .. _`we are done`: https://imgur.com/yyZxlTw From 937cbfa0a12ae3de5de08198472225cc1a3082bb Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 7 Jun 2018 17:09:39 +0200 Subject: [PATCH 233/321] small commit to rigger AV --- CI/before_script.msvc.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index dd8d830b8..38b304bf9 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -17,7 +17,6 @@ case "$WORKINGDIR" in ;; esac - set -euo pipefail APPVEYOR=${APPVEYOR:-} From 57b2948ee1f6a961cf44c4e5fd73dd82ea75c63b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Jun 2018 20:34:34 +0400 Subject: [PATCH 234/321] Update AppVeyor build status link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6a3323a1..cc600fdbe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/scrawl/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/github/openmw/openmw?svg=true)](https://ci.appveyor.com/project/psi29a/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) OpenMW is a recreation of the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. From 05026b891ea52b06d056e080cfb4e264c71a9ce9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Jun 2018 20:42:18 +0400 Subject: [PATCH 235/321] Add changelog entries --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbef559d..30b2af930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ 0.45.0 ------ + Bug #3374: Touch spells not hitting kwama foragers + Bug #3591: Angled hit distance too low Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 From 1a354f88acace854cc7cbb6c04e0cf8c57cce4fc Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 7 Jun 2018 22:05:55 +0300 Subject: [PATCH 236/321] Make choices trigger goodbye if Goodbye is used (fixes #3897) --- CHANGELOG.md | 1 + apps/openmw/mwgui/dialogue.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbef559d..0fbc5092f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 0.45.0 ------ + Feature #3897: Have Goodbye give all choices the effects of Goodbye Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 14bbe81ef..450799f29 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -635,6 +635,11 @@ namespace MWGui void DialogueWindow::onChoiceActivated(int id) { + if (mGoodbye) + { + onGoodbyeActivated(); + return; + } MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); updateTopics(); } From 7cafec9861eea5b44effdc3feb31ebdaec69e310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric?= Date: Thu, 7 Jun 2018 15:30:10 +0200 Subject: [PATCH 237/321] Add support for msvc with cmake version pre 3.9 (fixes #4429) --- cmake/OpenMWMacros.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index fe2837a09..2fa86094f 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -172,7 +172,7 @@ macro (get_generator_is_multi_config VALUE) if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) + list(LENGTH CMAKE_CONFIGURATION_TYPES ${VALUE}) endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) endif (DEFINED generator_is_multi_config_var) endmacro (get_generator_is_multi_config) From 4a9b790dbea1023290e6e31a7ee69015661b385c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric?= Date: Fri, 8 Jun 2018 06:36:11 +0200 Subject: [PATCH 238/321] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbef559d..d423e1ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ------ Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect + Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 Bug #4433: Guard behaviour is incorrect with Alarm = 0 0.44.0 From b784c7873da469f457a1219bea30af772acf2dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric?= Date: Fri, 8 Jun 2018 06:36:43 +0200 Subject: [PATCH 239/321] Update authors --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 17f11730d..faa59670f 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -37,6 +37,7 @@ Programmers Britt Mathis (galdor557) Capostrophic cc9cii + Cédric Mocquillon Chris Boyce (slothlife) Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) From 53e888236636d544bdc15353546aa102672bd6ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 8 Jun 2018 11:44:49 +0200 Subject: [PATCH 240/321] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbef559d..d88fce1d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 0.45.0 ------ + Bug #4221: Characters get stuck in V-shaped terrain Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 From 2fada9487927be1932e0eb1a134ce69473b62a81 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Jun 2018 15:44:35 +0400 Subject: [PATCH 241/321] Improve MRK NiStringExtraData handling (bug #4419) --- CHANGELOG.md | 1 + components/nifosg/nifloader.cpp | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d88fce1d0..08c81f60a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ------ Bug #4221: Characters get stuck in V-shaped terrain Bug #4293: Faction members are not aware of faction ownerships in barter + Bug #4419: MRK NiStringExtraData is handled incorrectly Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 0add92f29..aada21fce 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -261,7 +261,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, imageManager, std::vector(), 0, false, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, imageManager, std::vector(), 0, false, false, false, &textkeys->mTextKeys); if (nif->getUseSkinning()) { @@ -463,7 +463,7 @@ namespace NifOsg } osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, - std::vector boundTextures, int animflags, bool skipMeshes, bool isAnimated, TextKeyMap* textKeys, osg::Node* rootNode=NULL) + std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool isAnimated, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { if (rootNode != NULL && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box")) return NULL; @@ -510,7 +510,7 @@ namespace NifOsg if(sd->string == "MRK" && !Loader::getShowMarkers()) { // Marker objects. These meshes are only visible in the editor. - skipMeshes = true; + hasMarkers = true; } } } @@ -542,7 +542,7 @@ namespace NifOsg node->setNodeMask(0x1); } - if (skipMeshes && isAnimated) // make sure the empty node is not optimized away so the physicssystem can find it. + if ((skipMeshes || hasMarkers) && isAnimated) // make sure the empty node is not optimized away so the physicssystem can find it. { node->setDataVariance(osg::Object::DYNAMIC); } @@ -554,13 +554,18 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); - if (triShape->skin.empty()) - handleTriShape(triShape, node, composite, boundTextures, animflags); - else - handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); + const std::string nodeName = Misc::StringUtils::lowerCase(triShape->name); + static const std::string pattern = "tri editormarker"; + if (!hasMarkers || nodeName.compare(0, pattern.size(), pattern) != 0) + { + if (triShape->skin.empty()) + handleTriShape(triShape, node, composite, boundTextures, animflags); + else + handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); - if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, node, composite, boundTextures, animflags); + if (!nifNode->controller.empty()) + handleMeshControllers(nifNode, node, composite, boundTextures, animflags); + } } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) @@ -598,7 +603,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, skipMeshes, isAnimated, textKeys, rootNode); + handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, skipMeshes, hasMarkers, isAnimated, textKeys, rootNode); } } From 11103211c5e6a875e8d18743df71875b3dff087a Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Jun 2018 14:56:09 +0300 Subject: [PATCH 242/321] Make Goodbye and Choice choices mutually exclusive --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index de9ca83ca..da6e80e79 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -431,9 +431,11 @@ namespace MWDialogue void DialogueManager::addChoice (const std::string& text, int choice) { - mIsInChoice = true; - - mChoices.push_back(std::make_pair(text, choice)); + if (!mGoodbye) + { + mIsInChoice = true; + mChoices.push_back(std::make_pair(text, choice)); + } } const std::vector >& DialogueManager::getChoices() @@ -448,8 +450,8 @@ namespace MWDialogue void DialogueManager::goodbye() { - mIsInChoice = false; - mGoodbye = true; + if (!mIsInChoice) + mGoodbye = true; } void DialogueManager::persuade(int type, ResponseCallback* callback) From 0db702dfa78ca04423bafbe8d8243695206a9d10 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Jun 2018 15:05:00 +0300 Subject: [PATCH 243/321] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d88fce1d0..35d8ac4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Bug #4443: Goodbye option and dialogue choices are not mutually exclusive 0.44.0 ------ From fea34bd73f8302071d248f6f2fb199eb7afd3269 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 30 May 2018 08:54:43 +0400 Subject: [PATCH 244/321] Added support for per-group animation files --- CHANGELOG.md | 1 + apps/openmw/mwrender/animation.cpp | 41 +++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++ .../reference/modding/settings/game.rst | 13 ++++++ files/settings-default.cfg | 3 ++ 5 files changed, 63 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d88fce1d0..ff3feec75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Feature #4444: Per-group KF-animation files support 0.44.0 ------ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1bd839ead..3ccc06665 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -31,6 +31,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -466,6 +468,8 @@ namespace MWRender mAnimationTimePtr[i].reset(new AnimationTime); mLightListCallback = new SceneUtil::LightListCallback; + + mUseAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game"); } Animation::~Animation() @@ -536,6 +540,35 @@ namespace MWRender return mKeyframes->mTextKeys; } + void Animation::loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel) + { + const std::map& index = mResourceSystem->getVFS()->getIndex(); + + std::string animationPath = model; + if (animationPath.find("meshes") == 0) + { + animationPath.replace(0, 6, "animations"); + } + animationPath.replace(animationPath.size()-3, 3, "/"); + + mResourceSystem->getVFS()->normalizeFilename(animationPath); + + std::map::const_iterator found = index.lower_bound(animationPath); + while (found != index.end()) + { + const std::string& name = found->first; + if (name.size() >= animationPath.size() && name.substr(0, animationPath.size()) == animationPath) + { + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".kf") == 0) + addSingleAnimSource(name, baseModel); + } + else + break; + ++found; + } + } + void Animation::addAnimSource(const std::string &model, const std::string& baseModel) { std::string kfname = model; @@ -546,6 +579,14 @@ namespace MWRender else return; + addSingleAnimSource(kfname, baseModel); + + if (mUseAdditionalSources) + loadAllAnimationsInFolder(kfname, baseModel); + } + + void Animation::addSingleAnimSource(const std::string &kfname, const std::string& baseModel) + { if(!mResourceSystem->getVFS()->exists(kfname)) return; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cff98a4b7..43a626899 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -275,6 +275,8 @@ protected: osg::ref_ptr mLightListCallback; + bool mUseAdditionalSources; + const NodeMap& getNodeMap() const; /* Sets the appropriate animations on the bone groups based on priority. @@ -309,12 +311,15 @@ protected: */ void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); + void loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel); + /** Adds the keyframe controllers in the specified model as a new animation source. * @note Later added animation sources have the highest priority when it comes to finding a particular animation. * @param model The file to add the keyframes for. Note that the .nif file extension will be replaced with .kf. * @param baseModel The filename of the mObjectRoot, only used for error messages. */ void addAnimSource(const std::string &model, const std::string& baseModel); + void addSingleAnimSource(const std::string &model, const std::string& baseModel); /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 7a9b89295..416f1bc1a 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -157,3 +157,16 @@ Otherwise they wait for the enemies or the player to do an attack first. Please note this setting has not been extensively tested and could have side effects with certain quests. This setting can only be configured by editing the settings configuration file. + +use additional anim sources +--------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow to load additional animation sources when enabled. +For example, if the main animation mesh has name Meshes/x.nif, an engine will load all KF-files from Animations/x folder and its child folders. +Can be useful if you want to use several animation replacers without merging them. +Attention: animations from AnimKit have own format and are not supposed to be directly loaded in-game! +This setting can only be configured by editing the settings configuration file. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index b10b91eb1..09283bfc9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -219,6 +219,9 @@ can loot during death animation = true # Makes the value of filled soul gems dependent only on soul magnitude (with formula from the Morrowind Code Patch) rebalance soul gem values = false +# Allow to load per-group KF-files from Animations folder +use additional anim sources = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). From de5a3eaae9d55c8f4046426c349253a844926c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric?= Date: Fri, 8 Jun 2018 17:08:44 +0200 Subject: [PATCH 245/321] Fix indentation issue: replace tab by spaces --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index faa59670f..b029140c7 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -37,7 +37,7 @@ Programmers Britt Mathis (galdor557) Capostrophic cc9cii - Cédric Mocquillon + Cédric Mocquillon Chris Boyce (slothlife) Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) From fed10e87aa10bf82b6e193c4df8eda90e10c7ac9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 20:00:51 +0400 Subject: [PATCH 246/321] Store integer actor ID in AI packages (bug #4036) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/aicombat.cpp | 7 +-- apps/openmw/mwmechanics/aicombat.hpp | 3 -- apps/openmw/mwmechanics/aiescort.cpp | 22 ++++---- apps/openmw/mwmechanics/aiescort.hpp | 6 +-- apps/openmw/mwmechanics/aifollow.cpp | 67 ++++++++++++------------ apps/openmw/mwmechanics/aifollow.hpp | 11 ++-- apps/openmw/mwmechanics/aipackage.cpp | 25 ++++++++- apps/openmw/mwmechanics/aipackage.hpp | 3 ++ apps/openmw/mwmechanics/aipursue.cpp | 4 +- apps/openmw/mwmechanics/aipursue.hpp | 4 -- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwmechanics/summoning.cpp | 2 +- components/esm/aisequence.cpp | 4 ++ components/esm/aisequence.hpp | 2 + components/esm/savedgame.cpp | 2 +- 16 files changed, 93 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc2a9acc1..62a011859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.45.0 ------ Bug #2835: Player able to slowly move when overencumbered + Bug #4036: Weird behaviour of AI packages if package target has non-unique ID Bug #4221: Characters get stuck in V-shaped terrain Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4327: Missing animations during spell/weapon stance switching diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 83ebc67d9..06248fa10 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -103,9 +103,10 @@ namespace MWMechanics bool isFleeing(); }; - AiCombat::AiCombat(const MWWorld::Ptr& actor) : - mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()) - {} + AiCombat::AiCombat(const MWWorld::Ptr& actor) + { + mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); + } AiCombat::AiCombat(const ESM::AiSequence::AiCombat *combat) { diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index e7d74248b..6e1f0c623 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -54,9 +54,6 @@ namespace MWMechanics virtual bool shouldCancelPreviousAi() const { return false; } private: - - int mTargetActorId; - /// Returns true if combat should end bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 103ef32e1..a86d13d75 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -22,28 +22,32 @@ namespace MWMechanics { AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) - : mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast(duration)) + : mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { + mTargetActorRefId = actorId; mMaxDist = 450; } - AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z) - : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast(duration)) + AiEscort::AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z) + : mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { + mTargetActorRefId = actorId; mMaxDist = 450; } AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort) - : mActorId(escort->mTargetId), mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ) + : mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ) , mMaxDist(450) , mRemainingDuration(escort->mRemainingDuration) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { + mTargetActorRefId = escort->mTargetId; + mTargetActorId = escort->mTargetActorId; // mDuration isn't saved in the save file, so just giving it "1" for now if the package has a duration. // The exact value of mDuration only matters for repeating packages. if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves. @@ -78,7 +82,7 @@ namespace MWMechanics actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); - const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false); + const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mTargetActorRefId, false); const float* const leaderPos = actor.getRefData().getPosition().pos; const float* const followerPos = follower.getRefData().getPosition().pos; double differenceBetween[3]; @@ -119,18 +123,14 @@ namespace MWMechanics return TypeIdEscort; } - MWWorld::Ptr AiEscort::getTarget() const - { - return MWBase::Environment::get().getWorld()->getPtr(mActorId, false); - } - void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const { std::unique_ptr escort(new ESM::AiSequence::AiEscort()); escort->mData.mX = mX; escort->mData.mY = mY; escort->mData.mZ = mZ; - escort->mTargetId = mActorId; + escort->mTargetId = mTargetActorRefId; + escort->mTargetActorId = mTargetActorId; escort->mRemainingDuration = mRemainingDuration; escort->mCellId = mCellId; diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 719582271..82dba960e 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -24,11 +24,11 @@ namespace MWMechanics /// Implementation of AiEscort /** The Actor will escort the specified actor to the world position x, y, z until they reach their position, or they run out of time \implement AiEscort **/ - AiEscort(const std::string &actorId,int duration, float x, float y, float z); + AiEscort(const std::string &actorId, int duration, float x, float y, float z); /// Implementation of AiEscortCell /** The Actor will escort the specified actor to the cell position x, y, z until they reach their position, or they run out of time \implement AiEscortCell **/ - AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z); + AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z); AiEscort(const ESM::AiSequence::AiEscort* escort); @@ -38,7 +38,6 @@ namespace MWMechanics virtual int getTypeId() const; - MWWorld::Ptr getTarget() const; virtual bool sideWithTarget() const { return true; } void writeState(ESM::AiSequence::AiSequence &sequence) const; @@ -46,7 +45,6 @@ namespace MWMechanics void fastForward(const MWWorld::Ptr& actor, AiState& state); private: - std::string mActorId; std::string mCellId; float mX; float mY; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index fd5f9c7fe..13de01f9a 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -35,32 +35,53 @@ struct AiFollowStorage : AiTemporaryBase int AiFollow::mFollowIndexCounter = 0; -AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) +AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z) : mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z) -, mActorRefId(actorId), mActorId(-1), mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) +, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) { + mTargetActorRefId = actorId; } -AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z) +AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z) : mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z) -, mActorRefId(actorId), mActorId(-1), mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++) +, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++) { + mTargetActorRefId = actorId; } -AiFollow::AiFollow(const std::string &actorId, bool commanded) +AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z) +: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z) +, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) +{ + mTargetActorRefId = actor.getCellRef().getRefId(); + mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); +} + +AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float duration, float x, float y, float z) +: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z) +, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++) +{ + mTargetActorRefId = actor.getCellRef().getRefId(); + mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); +} + +AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded) : mAlwaysFollow(true), mCommanded(commanded), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0) -, mActorRefId(actorId), mActorId(-1), mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) +, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++) { + mTargetActorRefId = actor.getCellRef().getRefId(); + mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); } AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) : mAlwaysFollow(follow->mAlwaysFollow), mCommanded(follow->mCommanded), mRemainingDuration(follow->mRemainingDuration) , mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ) - , mActorRefId(follow->mTargetId), mActorId(-1) , mCellId(follow->mCellId), mActive(follow->mActive), mFollowIndex(mFollowIndexCounter++) { -// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration. -// The exact value of mDuration only matters for repeating packages. + mTargetActorRefId = follow->mTargetId; + mTargetActorId = follow->mTargetActorId; + // mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration. + // The exact value of mDuration only matters for repeating packages. if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves. mDuration = 1; else @@ -204,7 +225,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte std::string AiFollow::getFollowedActor() { - return mActorRefId; + return mTargetActorRefId; } AiFollow *MWMechanics::AiFollow::clone() const @@ -228,7 +249,8 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const follow->mData.mX = mX; follow->mData.mY = mY; follow->mData.mZ = mZ; - follow->mTargetId = mActorRefId; + follow->mTargetId = mTargetActorRefId; + follow->mTargetActorId = mTargetActorId; follow->mRemainingDuration = mRemainingDuration; follow->mCellId = mCellId; follow->mAlwaysFollow = mAlwaysFollow; @@ -241,29 +263,6 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const sequence.mPackages.push_back(package); } -MWWorld::Ptr AiFollow::getTarget() const -{ - if (mActorId == -2) - return MWWorld::Ptr(); - - if (mActorId == -1) - { - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mActorRefId, false); - if (target.isEmpty()) - { - mActorId = -2; - return target; - } - else - mActorId = target.getClass().getCreatureStats(target).getActorId(); - } - - if (mActorId != -1) - return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); - else - return MWWorld::Ptr(); -} - int AiFollow::getFollowIndex() const { return mFollowIndex; diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 051a4a2ce..f0d43c9a7 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -25,16 +25,17 @@ namespace MWMechanics class AiFollow : public AiPackage { public: + AiFollow(const std::string &actorId, float duration, float x, float y, float z); + AiFollow(const std::string &actorId, const std::string &CellId, float duration, float x, float y, float z); /// Follow Actor for duration or until you arrive at a world position - AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z); + AiFollow(const MWWorld::Ptr& actor, float duration, float X, float Y, float Z); /// Follow Actor for duration or until you arrive at a position in a cell - AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z); + AiFollow(const MWWorld::Ptr& actor, const std::string &CellId, float duration, float X, float Y, float Z); /// Follow Actor indefinitively - AiFollow(const std::string &ActorId, bool commanded=false); + AiFollow(const MWWorld::Ptr& actor, bool commanded=false); AiFollow(const ESM::AiSequence::AiFollow* follow); - MWWorld::Ptr getTarget() const; virtual bool sideWithTarget() const { return true; } virtual bool followTargetThroughDoors() const { return true; } virtual bool shouldCancelPreviousAi() const { return !mCommanded; } @@ -66,8 +67,6 @@ namespace MWMechanics float mX; float mY; float mZ; - std::string mActorRefId; - mutable int mActorId; std::string mCellId; bool mActive; // have we spotted the target? int mFollowIndex; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 38f641b94..6a0f5b013 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -27,15 +27,36 @@ MWMechanics::AiPackage::~AiPackage() {} MWMechanics::AiPackage::AiPackage() : mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild + mTargetActorRefId(""), + mTargetActorId(-1), mRotateOnTheRunChecks(0), mIsShortcutting(false), - mShortcutProhibited(false), mShortcutFailPos() + mShortcutProhibited(false), + mShortcutFailPos() { } MWWorld::Ptr MWMechanics::AiPackage::getTarget() const { - return MWWorld::Ptr(); + if (mTargetActorId == -2) + return MWWorld::Ptr(); + + if (mTargetActorId == -1) + { + MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetActorRefId, false); + if (target.isEmpty()) + { + mTargetActorId = -2; + return target; + } + else + mTargetActorId = target.getClass().getCreatureStats(target).getActorId(); + } + + if (mTargetActorId != -1) + return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); + else + return MWWorld::Ptr(); } bool MWMechanics::AiPackage::sideWithTarget() const diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 06b4adf61..b4987e954 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -128,6 +128,9 @@ namespace MWMechanics float mTimer; + std::string mTargetActorRefId; + mutable int mTargetActorId; + osg::Vec3f mLastActorPos; short mRotateOnTheRunChecks; // attempts to check rotation to the pathpoint on the run possibility diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index fd8b5752a..f46594655 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -15,13 +15,13 @@ namespace MWMechanics { AiPursue::AiPursue(const MWWorld::Ptr& actor) - : mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()) { + mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); } AiPursue::AiPursue(const ESM::AiSequence::AiPursue *pursue) - : mTargetActorId(pursue->mTargetActorId) { + mTargetActorId = pursue->mTargetActorId; } AiPursue *MWMechanics::AiPursue::clone() const diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index cb93e9636..455b0a2fd 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -40,10 +40,6 @@ namespace MWMechanics virtual bool canCancel() const { return false; } virtual bool shouldCancelPreviousAi() const { return false; } - - private: - - int mTargetActorId; // The actor to pursue }; } #endif diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d71b4c8ba..f6d92726d 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -547,7 +547,7 @@ namespace MWMechanics || (effectIt->mEffectID == ESM::MagicEffect::CommandCreature && target.getTypeName() == typeid(ESM::Creature).name())) && !caster.isEmpty() && caster.getClass().isActor() && target != getPlayer() && magnitude >= target.getClass().getCreatureStats(target).getLevel()) { - MWMechanics::AiFollow package(caster.getCellRef().getRefId(), true); + MWMechanics::AiFollow package(caster, true); target.getClass().getCreatureStats(target).getAiSequence().stack(package, target); } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index fad7bc96d..71c49f9df 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -59,7 +59,7 @@ namespace MWMechanics MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); // Make the summoned creature follow its master and help in fights - AiFollow package(mActor.getCellRef().getRefId()); + AiFollow package(mActor); summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); creatureActorId = summonedCreatureStats.getActorId(); diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index c39ef8269..90992bed3 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -46,6 +46,7 @@ namespace AiSequence { esm.getHNT (mData, "DATA"); mTargetId = esm.getHNString("TARG"); + esm.getHNOT (mTargetActorId, "TAID"); esm.getHNT (mRemainingDuration, "DURA"); mCellId = esm.getHNOString ("CELL"); } @@ -54,6 +55,7 @@ namespace AiSequence { esm.writeHNT ("DATA", mData); esm.writeHNString ("TARG", mTargetId); + esm.writeHNT ("TAID", mTargetActorId); esm.writeHNT ("DURA", mRemainingDuration); if (!mCellId.empty()) esm.writeHNString ("CELL", mCellId); @@ -63,6 +65,7 @@ namespace AiSequence { esm.getHNT (mData, "DATA"); mTargetId = esm.getHNString("TARG"); + esm.getHNOT (mTargetActorId, "TAID"); esm.getHNT (mRemainingDuration, "DURA"); mCellId = esm.getHNOString ("CELL"); esm.getHNT (mAlwaysFollow, "ALWY"); @@ -76,6 +79,7 @@ namespace AiSequence { esm.writeHNT ("DATA", mData); esm.writeHNString("TARG", mTargetId); + esm.writeHNT ("TAID", mTargetActorId); esm.writeHNT ("DURA", mRemainingDuration); if (!mCellId.empty()) esm.writeHNString ("CELL", mCellId); diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index 52446d38f..3c4cf2406 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -89,6 +89,7 @@ namespace ESM { AiEscortData mData; + int mTargetActorId; std::string mTargetId; std::string mCellId; float mRemainingDuration; @@ -101,6 +102,7 @@ namespace ESM { AiEscortData mData; + int mTargetActorId; std::string mTargetId; std::string mCellId; float mRemainingDuration; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 3220f496e..c96261c64 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 3; +int ESM::SavedGame::sCurrentFormat = 4; void ESM::SavedGame::load (ESMReader &esm) { From b7026df551e56181f87aa1929348b5b661c422ea Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 25 Mar 2018 13:05:42 +0300 Subject: [PATCH 247/321] Improve the offered price formula (Fixes #2222) --- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 94317bbf2..0a3f8cad6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -629,22 +629,12 @@ namespace MWMechanics float d = static_cast(std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); float npcTerm = (d + e + f) * sellerStats.getFatigueTerm(); - float buyTerm = 0.01f * (100 - 0.5f * (pcTerm - npcTerm)); - float sellTerm = 0.01f * (50 - 0.5f * (npcTerm - pcTerm)); - - float x; - if(buying) x = buyTerm; - else x = std::min(buyTerm, sellTerm); - int offerPrice; - if (x < 1) - offerPrice = int(x * basePrice); - else - offerPrice = basePrice + int((x - 1) * basePrice); - offerPrice = std::max(1, offerPrice); - return offerPrice; + float buyTerm = 0.01f * std::max(75.f, (100 - 0.5f * (pcTerm - npcTerm))); + float sellTerm = 0.01f * std::min(75.f, (50 - 0.5f * (npcTerm - pcTerm))); + int offerPrice = int(basePrice * (buying ? buyTerm : sellTerm)); + return std::max(1, offerPrice); } int MechanicsManager::countDeaths (const std::string& id) const From 24c1ee774477c44736f30881e4211d99693da115 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 4 Apr 2018 15:34:34 +0300 Subject: [PATCH 248/321] Use relative stat difference for haggling --- apps/openmw/mwmechanics/trading.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/trading.cpp b/apps/openmw/mwmechanics/trading.cpp index ede0d2de7..eee5e6449 100644 --- a/apps/openmw/mwmechanics/trading.cpp +++ b/apps/openmw/mwmechanics/trading.cpp @@ -32,7 +32,6 @@ namespace MWMechanics // Is the player buying? bool buying = (merchantOffer < 0); - int a = std::abs(merchantOffer); int b = std::abs(playerOffer); int d = (buying) @@ -56,7 +55,7 @@ namespace MWMechanics float npcTerm = (d1 + e1 + f1) * merchantStats.getFatigueTerm(); float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat() - + std::abs(int(pcTerm - npcTerm)); + + int(pcTerm - npcTerm); int roll = Misc::Rng::rollDice(100) + 1; From 01f12a6bd55ede0372265d368d6d1d30b2bbf159 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Jun 2018 19:01:48 +0300 Subject: [PATCH 249/321] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc2a9acc1..d1ec6e58e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 0.45.0 ------ + Bug #2222: Fatigue's effect on selling price is backwards Bug #2835: Player able to slowly move when overencumbered Bug #4221: Characters get stuck in V-shaped terrain Bug #4293: Faction members are not aware of faction ownerships in barter From 99781ab70c11c25bb92c1fadb75b7173676328ae Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Jun 2018 19:15:31 +0300 Subject: [PATCH 250/321] Fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fbc5092f..333ae6f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ 0.45.0 ------ - Feature #3897: Have Goodbye give all choices the effects of Goodbye + Bug #3897: Have Goodbye give all choices the effects of Goodbye Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4426: RotateWorld behavior is incorrect Bug #4433: Guard behaviour is incorrect with Alarm = 0 From b274931165c85b0ead18f4fc89c7e2ae6b83e036 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Jun 2018 19:18:53 +0300 Subject: [PATCH 251/321] Revert erroneous changes --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index da6e80e79..fb492ff3b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -431,11 +431,8 @@ namespace MWDialogue void DialogueManager::addChoice (const std::string& text, int choice) { - if (!mGoodbye) - { - mIsInChoice = true; - mChoices.push_back(std::make_pair(text, choice)); - } + mIsInChoice = true; + mChoices.push_back(std::make_pair(text, choice)); } const std::vector >& DialogueManager::getChoices() @@ -450,8 +447,8 @@ namespace MWDialogue void DialogueManager::goodbye() { - if (!mIsInChoice) - mGoodbye = true; + mIsInChoice = false; + mGoodbye = true; } void DialogueManager::persuade(int type, ResponseCallback* callback) From 9d27eb197fceb00cf37b836bdfd649088f64635c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 12:05:05 +0400 Subject: [PATCH 252/321] AiWander: return to initial position only after combat --- apps/openmw/mwmechanics/aiwander.cpp | 68 +++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 - .../mwmechanics/mechanicsmanagerimp.cpp | 18 ++++- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8199170dc..3ad45e2c3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -59,7 +59,7 @@ namespace MWMechanics float mTargetAngleRadians; bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently - + AiWander::GreetingState mSaidGreeting; int mGreetingTimer; @@ -70,7 +70,7 @@ namespace MWMechanics bool mIsWanderingManually; bool mCanWanderAlongPathGrid; - + unsigned short mIdleAnimation; std::vector mBadIdles; // Idle animations that when called cause errors @@ -86,7 +86,7 @@ namespace MWMechanics float mDoorCheckDuration; int mStuckCount; - + AiWanderStorage(): mTargetAngleRadians(0), mTurnActorGivingGreetingToFacePlayer(false), @@ -111,7 +111,7 @@ namespace MWMechanics mIsWanderingManually = isManualWander; } }; - + AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)) @@ -201,7 +201,18 @@ namespace MWMechanics stopWalking(actor, storage); currentCell = actor.getCell(); storage.mPopulateAvailableNodes = true; - mStoredInitialActorPosition = false; + } + + // Here we should reset an initial position, if a current cell was REALLY changed + // We do not store AiStorage in a savegame, so cellChange is not help us in this case + // TODO: find a more simple and fast solution, or do not store the mInitialActorPosition at all + if (mStoredInitialActorPosition) + { + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(mInitialActorPosition.x(),mInitialActorPosition.y(),cx,cy); + MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if (cell != currentCell) + mStoredInitialActorPosition = false; } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); @@ -223,7 +234,7 @@ namespace MWMechanics if (mPathFinder.isPathConstructed()) storage.setState(Wander_Walking); } - + doPerFrameActionsForState(actor, duration, storage, pos); playIdleDialogueRandomly(actor); @@ -298,13 +309,6 @@ namespace MWMechanics if(mDistance && cellChange) mDistance = 0; - // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere - if (mDistance == 0 && !cellChange - && (pos.asVec3() - mInitialActorPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE)) - { - returnToStartLocation(actor, storage, pos); - } - // Allow interrupting a walking actor to trigger a greeting WanderState& wanderState = storage.mState; if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) @@ -321,7 +325,7 @@ namespace MWMechanics { setPathToAnAllowedNode(actor, storage, pos); } - } + } } else if (storage.mIsWanderingManually && mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { completeManualWalking(actor, storage); } @@ -330,8 +334,8 @@ namespace MWMechanics } bool AiWander::getRepeat() const - { - return mRepeat; + { + return mRepeat; } @@ -350,27 +354,6 @@ namespace MWMechanics return false; } - void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) - { - if (!mPathFinder.isPathConstructed()) - { - mDestination = mInitialActorPosition; - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination)); - - // actor position is already in world coordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); - - if (mPathFinder.isPathConstructed()) - { - storage.setState(Wander_Walking); - mHasDestination = true; - } - } - } - /* * Commands actor to walk to a random location near original spawn location. */ @@ -497,7 +480,7 @@ namespace MWMechanics } } - void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, + void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { // Is there no destination or are we there yet? @@ -873,7 +856,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } @@ -914,7 +897,7 @@ namespace MWMechanics // get NPC's position in local (i.e. cell) coordinates osg::Vec3f npcPos(mInitialActorPosition); CoordinateConverter(cell).toLocal(npcPos); - + // Find closest pathgrid point int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, npcPos); @@ -945,7 +928,7 @@ namespace MWMechanics storage.mPopulateAvailableNodes = false; } - // When only one path grid point in wander distance, + // When only one path grid point in wander distance, // additional points for NPC to wander to are: // 1. NPC's initial location // 2. Partway along the path between the point and its connected points. @@ -969,7 +952,7 @@ namespace MWMechanics delta.normalize(); int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE); - + // must not travel longer than distance between waypoints or NPC goes past waypoint distance = std::min(distance, static_cast(length)); delta *= distance; @@ -1041,4 +1024,3 @@ namespace MWMechanics init(); } } - diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 6266a7708..3f69d107d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -85,7 +85,6 @@ namespace MWMechanics bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos, float duration); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance); bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination); bool destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 94317bbf2..bddcf83d6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -22,6 +22,7 @@ #include "aicombat.hpp" #include "aipursue.hpp" +#include "aitravel.hpp" #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" @@ -1598,9 +1599,22 @@ namespace MWMechanics void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) { - if (ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(target)) + MWMechanics::AiSequence& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + + if (aiSequence.isInCombat(target)) return; - ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); + + // we should return a wandering actor back after combat + // TODO: only for stationary wander? + if (!aiSequence.isInCombat() && aiSequence.getLastRunTypeId() == MWMechanics::AiPackage::TypeIdWander) + { + osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); + + MWMechanics::AiTravel travelPackage(pos.x(), pos.y(), pos.z()); + aiSequence.stack(travelPackage, ptr); + } + + aiSequence.stack(MWMechanics::AiCombat(target), ptr); if (target == getPlayer()) { // if guard starts combat with player, guards pursuing player should do the same From 18ff097e4a2ab38bb3d46e3164e26fa89de8317e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 12:06:09 +0400 Subject: [PATCH 253/321] Add the parameter to AiSequence::stack() to control ability to cancel other AI packages --- apps/openmw/mwmechanics/aisequence.cpp | 4 ++-- apps/openmw/mwmechanics/aisequence.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2a2d598f5..b38111f7b 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -298,7 +298,7 @@ void AiSequence::clear() mPackages.clear(); } -void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) +void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, bool cancelOther) { if (actor == getPlayer()) throw std::runtime_error("Can't add AI packages to player"); @@ -308,7 +308,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) stopCombat(); // remove previous packages if required - if (package.shouldCancelPreviousAi()) + if (cancelOther && package.shouldCancelPreviousAi()) { for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) { diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 41d204ee2..d725409de 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -115,7 +115,7 @@ namespace MWMechanics ///< Add \a package to the front of the sequence /** Suspends current package @param actor The actor that owns this AiSequence **/ - void stack (const AiPackage& package, const MWWorld::Ptr& actor); + void stack (const AiPackage& package, const MWWorld::Ptr& actor, bool cancelOther=true); /// Return the current active package. /** If there is no active package, it will throw an exception **/ diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bddcf83d6..d032ed632 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1611,7 +1611,7 @@ namespace MWMechanics osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); MWMechanics::AiTravel travelPackage(pos.x(), pos.y(), pos.z()); - aiSequence.stack(travelPackage, ptr); + aiSequence.stack(travelPackage, ptr, false); } aiSequence.stack(MWMechanics::AiCombat(target), ptr); From 81f29d8dcd131bc123fbed5858f49fa049c060d9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 18:53:31 +0400 Subject: [PATCH 254/321] AiWander: resume moving to destination after combat --- apps/openmw/mwmechanics/aipackage.hpp | 3 +++ apps/openmw/mwmechanics/aiwander.cpp | 15 ++++++++++++--- apps/openmw/mwmechanics/aiwander.hpp | 6 ++++-- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 ++++++++++++++---- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 06b4adf61..d9a7fa386 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -79,6 +79,9 @@ namespace MWMechanics /// Get the target actor the AI is targeted at (not applicable to all AI packages, default return empty Ptr) virtual MWWorld::Ptr getTarget() const; + /// Get the destination point of the AI package (not applicable to all AI packages, default return (0, 0, 0)) + virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); }; + /// Return true if having this AiPackage makes the actor side with the target in fights (default false) virtual bool sideWithTarget() const; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3ad45e2c3..2e832dc3f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -335,9 +335,18 @@ namespace MWMechanics bool AiWander::getRepeat() const { - return mRepeat; + return mRepeat; } + osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const + { + if (mHasDestination) + return mDestination; + + const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos; + const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ); + return currentPositionVec3f; + } bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) { @@ -346,8 +355,8 @@ namespace MWMechanics // End package if duration is complete if (mRemainingDuration <= 0) { - stopWalking(actor, storage); - return true; + stopWalking(actor, storage); + return true; } } // if get here, not yet completed diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3f69d107d..d96d93165 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -47,9 +47,11 @@ namespace MWMechanics virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); - + bool getRepeat() const; - + + osg::Vec3f getDestination(const MWWorld::Ptr& actor) const; + enum GreetingState { Greet_None, Greet_InProgress, diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d032ed632..55aace8e7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1605,12 +1605,22 @@ namespace MWMechanics return; // we should return a wandering actor back after combat - // TODO: only for stationary wander? - if (!aiSequence.isInCombat() && aiSequence.getLastRunTypeId() == MWMechanics::AiPackage::TypeIdWander) + // the same thing for actors without AI packages + if (!aiSequence.isInCombat() && aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) { - osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); + int typeId = aiSequence.getTypeId(); + osg::Vec3f dest; + if (typeId == MWMechanics::AiPackage::TypeIdNone) + { + dest = ptr.getRefData().getPosition().asVec3(); + } + else if (typeId == MWMechanics::AiPackage::TypeIdWander) + { + AiPackage* activePackage = aiSequence.getActivePackage(); + dest = activePackage->getDestination(ptr); + } - MWMechanics::AiTravel travelPackage(pos.x(), pos.y(), pos.z()); + MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z()); aiSequence.stack(travelPackage, ptr, false); } From 5105c676422fa2664d4605717a04d9aea500e157 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 19:58:42 +0400 Subject: [PATCH 255/321] Add mHidden field to AiTravel --- apps/openmw/mwmechanics/aipackage.hpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 8 ++++---- apps/openmw/mwmechanics/aitravel.hpp | 4 +++- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index d9a7fa386..829bbe898 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -48,7 +48,8 @@ namespace MWMechanics TypeIdPursue = 6, TypeIdAvoidDoor = 7, TypeIdFace = 8, - TypeIdBreathe = 9 + TypeIdBreathe = 9, + TypeIdInternalTravel = 10 }; ///Default constructor diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 36b96101f..ea14407ca 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -28,15 +28,14 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) namespace MWMechanics { - AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z) + AiTravel::AiTravel(float x, float y, float z, bool hidden) + : mX(x),mY(y),mZ(z),mHidden(hidden) { } AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel) : mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ) { - } AiTravel *MWMechanics::AiTravel::clone() const @@ -64,7 +63,8 @@ namespace MWMechanics int AiTravel::getTypeId() const { - return TypeIdTravel; + // TODO: store mHidden in the savegame? + return mHidden ? TypeIdInternalTravel : TypeIdTravel; } void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 8c75bded1..c297771d0 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -20,7 +20,7 @@ namespace MWMechanics { public: /// Default constructor - AiTravel(float x, float y, float z); + AiTravel(float x, float y, float z, bool hidden = false); AiTravel(const ESM::AiSequence::AiTravel* travel); /// Simulates the passing of time @@ -38,6 +38,8 @@ namespace MWMechanics float mX; float mY; float mZ; + + bool mHidden; }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 55aace8e7..dc3695239 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1620,7 +1620,7 @@ namespace MWMechanics dest = activePackage->getDestination(ptr); } - MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z()); + MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true); aiSequence.stack(travelPackage, ptr, false); } From 57d686131e89ec4f18ab97bcab7fa7443d7df20e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 20:01:15 +0400 Subject: [PATCH 256/321] Remove redundant condition --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dc3695239..fbf989d05 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1606,7 +1606,7 @@ namespace MWMechanics // we should return a wandering actor back after combat // the same thing for actors without AI packages - if (!aiSequence.isInCombat() && aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) + if (aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) { int typeId = aiSequence.getTypeId(); osg::Vec3f dest; From 2f5beb885371aa2daed3b999b78cda24ec3abcfc Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 20:38:10 +0400 Subject: [PATCH 257/321] Remove unnecessary hack --- apps/openmw/mwmechanics/aiwander.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2e832dc3f..ee680159e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -201,18 +201,7 @@ namespace MWMechanics stopWalking(actor, storage); currentCell = actor.getCell(); storage.mPopulateAvailableNodes = true; - } - - // Here we should reset an initial position, if a current cell was REALLY changed - // We do not store AiStorage in a savegame, so cellChange is not help us in this case - // TODO: find a more simple and fast solution, or do not store the mInitialActorPosition at all - if (mStoredInitialActorPosition) - { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(mInitialActorPosition.x(),mInitialActorPosition.y(),cx,cy); - MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); - if (cell != currentCell) - mStoredInitialActorPosition = false; + mStoredInitialActorPosition = false; } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); From 3a0ee78d2b300301a16e4739cd11de14195f9d0d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 25 May 2018 19:31:31 +0400 Subject: [PATCH 258/321] AiTravel: store mHidden flag in savegame --- apps/openmw/mwmechanics/aisequence.cpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- components/esm/aisequence.cpp | 2 ++ components/esm/aisequence.hpp | 1 + components/esm/savedgame.cpp | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index b38111f7b..2c48eacf8 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -184,7 +184,8 @@ bool isActualAiPackage(int packageTypeId) && packageTypeId != AiPackage::TypeIdPursue && packageTypeId != AiPackage::TypeIdAvoidDoor && packageTypeId != AiPackage::TypeIdFace - && packageTypeId != AiPackage::TypeIdBreathe); + && packageTypeId != AiPackage::TypeIdBreathe + && packageTypeId != AiPackage::TypeIdInternalTravel); } void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index ea14407ca..72e6ced19 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -34,7 +34,7 @@ namespace MWMechanics } AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel) - : mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ) + : mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(travel->mHidden) { } @@ -63,7 +63,6 @@ namespace MWMechanics int AiTravel::getTypeId() const { - // TODO: store mHidden in the savegame? return mHidden ? TypeIdInternalTravel : TypeIdTravel; } @@ -83,6 +82,7 @@ namespace MWMechanics travel->mData.mX = mX; travel->mData.mY = mY; travel->mData.mZ = mZ; + travel->mHidden = mHidden; ESM::AiSequence::AiPackageContainer package; package.mType = ESM::AiSequence::Ai_Travel; diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index c39ef8269..196c1754f 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -35,11 +35,13 @@ namespace AiSequence void AiTravel::load(ESMReader &esm) { esm.getHNT (mData, "DATA"); + esm.getHNOT (mHidden, "HIDD"); } void AiTravel::save(ESMWriter &esm) const { esm.writeHNT ("DATA", mData); + esm.writeHNT ("HIDD", mHidden); } void AiEscort::load(ESMReader &esm) diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index 52446d38f..d4315062b 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -80,6 +80,7 @@ namespace ESM struct AiTravel : AiPackage { AiTravelData mData; + bool mHidden; void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 3220f496e..c96261c64 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 3; +int ESM::SavedGame::sCurrentFormat = 4; void ESM::SavedGame::load (ESMReader &esm) { From 3d0631cfcc01fdb5032ac3df2be00a1beadd1e6a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 25 May 2018 20:07:08 +0400 Subject: [PATCH 259/321] Store last AI package in savegame --- apps/openmw/mwmechanics/aisequence.cpp | 6 +++++- components/esm/aisequence.cpp | 4 ++++ components/esm/aisequence.hpp | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2c48eacf8..51c82f6ed 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -393,6 +393,8 @@ void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const { (*iter)->writeState(sequence); } + + sequence.mLastAiPackage = mLastAiPackage; } void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) @@ -404,7 +406,7 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) int count = 0; for (std::vector::const_iterator it = sequence.mPackages.begin(); it != sequence.mPackages.end(); ++it) - { + { if (isActualAiPackage(it->mType)) count++; } @@ -463,6 +465,8 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) mPackages.push_back(package.release()); } + + mLastAiPackage = sequence.mLastAiPackage; } void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state) diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index 196c1754f..43712d9ea 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -156,6 +156,8 @@ namespace AiSequence break; } } + + esm.writeHNT ("LAST", mLastAiPackage); } void AiSequence::load(ESMReader &esm) @@ -223,6 +225,8 @@ namespace AiSequence return; } } + + esm.getHNOT (mLastAiPackage, "LAST"); } } } diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index d4315062b..0cbde1b8e 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -148,10 +148,14 @@ namespace ESM struct AiSequence { - AiSequence() {} + AiSequence() + { + mLastAiPackage = -1; + } ~AiSequence(); std::vector mPackages; + int mLastAiPackage; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 74a2cbe6960ce178fb426f86430532c561cb0da7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Jun 2018 09:30:44 +0400 Subject: [PATCH 260/321] AI: return back after pursuit --- apps/openmw/mwmechanics/aisequence.cpp | 23 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.cpp | 20 ---------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 51c82f6ed..84ddf8fdf 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -308,6 +308,29 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo if (isActualAiPackage(package.getTypeId())) stopCombat(); + // we should return a wandering actor back after combat or pursuit + // the same thing for actors without AI packages + int currentTypeId = getTypeId(); + int newTypeId = package.getTypeId(); + if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander + && (newTypeId <= MWMechanics::AiPackage::TypeIdCombat + || newTypeId == MWMechanics::AiPackage::TypeIdPursue)) + { + osg::Vec3f dest; + if (currentTypeId == MWMechanics::AiPackage::TypeIdWander) + { + AiPackage* activePackage = getActivePackage(); + dest = activePackage->getDestination(actor); + } + else + { + dest = actor.getRefData().getPosition().asVec3(); + } + + MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true); + stack(travelPackage, actor, false); + } + // remove previous packages if required if (cancelOther && package.shouldCancelPreviousAi()) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index fbf989d05..89e1bef06 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1604,26 +1604,6 @@ namespace MWMechanics if (aiSequence.isInCombat(target)) return; - // we should return a wandering actor back after combat - // the same thing for actors without AI packages - if (aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) - { - int typeId = aiSequence.getTypeId(); - osg::Vec3f dest; - if (typeId == MWMechanics::AiPackage::TypeIdNone) - { - dest = ptr.getRefData().getPosition().asVec3(); - } - else if (typeId == MWMechanics::AiPackage::TypeIdWander) - { - AiPackage* activePackage = aiSequence.getActivePackage(); - dest = activePackage->getDestination(ptr); - } - - MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true); - aiSequence.stack(travelPackage, ptr, false); - } - aiSequence.stack(MWMechanics::AiCombat(target), ptr); if (target == getPlayer()) { From 6ed27732995c2a87f2e62c4966c24a729a60b158 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Jun 2018 12:05:10 +0400 Subject: [PATCH 261/321] Do not stack return packages --- apps/openmw/mwmechanics/aisequence.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 84ddf8fdf..85afbc453 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -308,11 +308,13 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo if (isActualAiPackage(package.getTypeId())) stopCombat(); - // we should return a wandering actor back after combat or pursuit - // the same thing for actors without AI packages + // We should return a wandering actor back after combat or pursuit. + // The same thing for actors without AI packages. + // Also there is no point to stack return packages. int currentTypeId = getTypeId(); int newTypeId = package.getTypeId(); if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander + && !hasPackage(MWMechanics::AiPackage::TypeIdInternalTravel) && (newTypeId <= MWMechanics::AiPackage::TypeIdCombat || newTypeId == MWMechanics::AiPackage::TypeIdPursue)) { From 2e6cf2a4149ae87ca932833c70f594725475c5a1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Jun 2018 20:39:59 +0400 Subject: [PATCH 262/321] Add changelog entries --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb72c7cac..82410813e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,15 @@ 0.45.0 ------ + Bug #2835: Player able to slowly move when overencumbered + Bug #3997: Almalexia doesn't pace Bug #4221: Characters get stuck in V-shaped terrain + Bug #4251: Stationary NPCs do not return to their position after combat Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4327: Missing animations during spell/weapon stance switching Bug #4426: RotateWorld behavior is incorrect Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 + Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 Bug #4443: Goodbye option and dialogue choices are not mutually exclusive Feature #4444: Per-group KF-animation files support From 6277f5511c4346a4038dda8401edf241b8a88b51 Mon Sep 17 00:00:00 2001 From: wareya Date: Fri, 8 Jun 2018 17:52:46 -0400 Subject: [PATCH 263/321] fix #3876 and #3993 --- components/esmterrain/storage.cpp | 34 ++++++++++++++++++++++++------- components/terrain/material.cpp | 3 +++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index dc144d119..a1b4856e1 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -430,15 +430,23 @@ namespace ESMTerrain // Second iteration - create and fill in the blend maps const int blendmapSize = (realTextureSize-1) * chunkSize + 1; + // We need to upscale the blendmap 2x with nearest neighbor sampling to look like Vanilla + const int imageScaleFactor = 2; + const int blendmapImageSize = blendmapSize * imageScaleFactor; + + + const bool largeImage = true; for (int i=0; i image (new osg::Image); - image->allocateImage(blendmapSize, blendmapSize, 1, format, GL_UNSIGNED_BYTE); + if(!largeImage) + image->allocateImage(blendmapSize, blendmapSize, 1, format, GL_UNSIGNED_BYTE); + else + image->allocateImage(blendmapImageSize, blendmapImageSize, 1, format, GL_UNSIGNED_BYTE); unsigned char* pData = image->data(); - for (int y=0; ysecond; int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; - - if (blendIndex == i) - pData[(blendmapSize - y - 1)*blendmapSize*channels + x*channels + channel] = 255; + + int alpha = (blendIndex == i) ? 255 : 0; + + if(!largeImage) + pData[((blendmapSize - y - 1)*blendmapSize + x)*channels + channel] = alpha; else - pData[(blendmapSize - y - 1)*blendmapSize*channels + x*channels + channel] = 0; + { + int realY = (blendmapSize - y - 1)*imageScaleFactor; + int realX = x*imageScaleFactor; + if(true) + pData[((realY+0)*blendmapImageSize + realX + 0)*channels + channel] = alpha; + if(realY+1 < blendmapImageSize) + pData[((realY+1)*blendmapImageSize + realX + 0)*channels + channel] = alpha; + if(realX+1 < blendmapImageSize) + pData[((realY+0)*blendmapImageSize + realX + 1)*channels + channel] = alpha; + if(realY+1 < blendmapImageSize && realX+1 < blendmapImageSize) + pData[((realY+1)*blendmapImageSize + realX + 1)*channels + channel] = alpha; + } } } - blendmaps.push_back(image); } } diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 640f2932b..56ace0e5a 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -25,6 +25,9 @@ namespace Terrain matrix.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); matrix.preMultScale(osg::Vec3f(scale, scale, 1.f)); matrix.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); + // We need to nudge the blendmap to look like vanilla. + // This causes visible seams unless the blendmap's resolution is doubled, but Vanilla also doubles the blendmap, apparently. + matrix.preMultTranslate(osg::Vec3f(1.0f/blendmapScale/4.0f, 1.0f/blendmapScale/4.0f, 0.f)); texMat = new osg::TexMat(matrix); From 62c4eb8d6abbb4b3ebf5af951801dc0ce17bbc1f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Fri, 8 Jun 2018 19:16:24 -0500 Subject: [PATCH 264/321] Explicitly flagging loaded cells changed as queued --- apps/launcher/maindialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index a70f6ff7f..90197b157 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -139,7 +139,8 @@ void Launcher::MainDialog::createPages() connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int))); connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int))); - connect(mDataFilesPage, SIGNAL(signalSelectedFilesChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList))); + // Using Qt::QueuedConnection because signal is emitted in a subthread and slot is in the main thread + connect(mDataFilesPage, SIGNAL(signalSelectedFilesChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection); } From dfa99685658318a27fa79e59f7060aa8fbebb68c Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Fri, 8 Jun 2018 19:18:23 -0500 Subject: [PATCH 265/321] Renaming Launcher::DataFilesPage::signalSelectedFilesChanged to signalLoadedCellsChanged --- apps/launcher/datafilespage.cpp | 2 +- apps/launcher/datafilespage.hpp | 2 +- apps/launcher/maindialog.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 6c23b3285..7b703a924 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -356,5 +356,5 @@ void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles) CellNameLoader cellNameLoader; QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles)); std::sort(cellNamesList.begin(), cellNamesList.end()); - emit signalSelectedFilesChanged(cellNamesList); + emit signalLoadedCellsChanged(cellNamesList); } \ No newline at end of file diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index d871eeee0..2cbace38e 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -50,7 +50,7 @@ namespace Launcher signals: void signalProfileChanged (int index); - void signalSelectedFilesChanged(QStringList selectedFiles); + void signalLoadedCellsChanged(QStringList selectedFiles); public slots: void slotProfileChanged (int index); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 90197b157..27fa2d903 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -140,7 +140,7 @@ void Launcher::MainDialog::createPages() connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int))); connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int))); // Using Qt::QueuedConnection because signal is emitted in a subthread and slot is in the main thread - connect(mDataFilesPage, SIGNAL(signalSelectedFilesChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection); + connect(mDataFilesPage, SIGNAL(signalLoadedCellsChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection); } From 4ba361fea6d1ecef2e13e2bad2267c6644df5e6a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 10 Apr 2018 07:06:44 +0400 Subject: [PATCH 266/321] Unhardcode sunset and sunrise settings (bug #1990) --- apps/openmw/mwworld/weather.cpp | 119 ++++++++++++++++++++++---------- apps/openmw/mwworld/weather.hpp | 43 +++++++++++- 2 files changed, 123 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 155e4340a..d12e633be 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -43,49 +42,67 @@ namespace } template -T TimeOfDayInterpolator::getValue(const float gameHour, const TimeOfDaySettings& timeSettings) const +T TimeOfDayInterpolator::getValue(const float gameHour, const TimeOfDaySettings& timeSettings, const std::string& prefix) const { - // TODO: use pre/post sunset/sunrise time values in [Weather] section + WeatherSetting setting = timeSettings.getSetting(prefix); + float preSunriseTime = setting.mPreSunriseTime; + float postSunriseTime = setting.mPostSunriseTime; + float preSunsetTime = setting.mPreSunsetTime; + float postSunsetTime = setting.mPostSunsetTime; // night - if (gameHour <= timeSettings.mNightEnd || gameHour >= timeSettings.mNightStart + 1) + if (gameHour < timeSettings.mNightEnd - preSunriseTime || gameHour > timeSettings.mNightStart + postSunsetTime) return mNightValue; // sunrise - else if (gameHour >= timeSettings.mNightEnd && gameHour <= timeSettings.mDayStart + 1) + else if (gameHour >= timeSettings.mNightEnd - preSunriseTime && gameHour <= timeSettings.mDayStart + postSunriseTime) { - if (gameHour <= timeSettings.mSunriseTime) + float duration = timeSettings.mDayStart + postSunriseTime - timeSettings.mNightEnd + preSunriseTime; + float middle = timeSettings.mNightEnd - preSunriseTime + duration / 2.f; + + if (gameHour <= middle) { // fade in - float advance = timeSettings.mSunriseTime - gameHour; - float factor = advance / 0.5f; + float advance = middle - gameHour; + float factor = 0.f; + if (duration > 0) + factor = advance / duration * 2; return lerp(mSunriseValue, mNightValue, factor); } else { // fade out - float advance = gameHour - timeSettings.mSunriseTime; - float factor = advance / 3.f; + float advance = gameHour - middle; + float factor = 1.f; + if (duration > 0) + factor = advance / duration * 2; return lerp(mSunriseValue, mDayValue, factor); } } // day - else if (gameHour >= timeSettings.mDayStart + 1 && gameHour <= timeSettings.mDayEnd - 1) + else if (gameHour > timeSettings.mDayStart + postSunriseTime && gameHour < timeSettings.mDayEnd - preSunsetTime) return mDayValue; // sunset - else if (gameHour >= timeSettings.mDayEnd - 1 && gameHour <= timeSettings.mNightStart + 1) + else if (gameHour >= timeSettings.mDayEnd - preSunsetTime && gameHour <= timeSettings.mNightStart + postSunsetTime) { - if (gameHour <= timeSettings.mDayEnd + 1) + float duration = timeSettings.mNightStart + postSunsetTime - timeSettings.mDayEnd + preSunsetTime; + float middle = timeSettings.mDayEnd - preSunsetTime + duration / 2.f; + + if (gameHour <= middle) { // fade in - float advance = (timeSettings.mDayEnd + 1) - gameHour; - float factor = (advance / 2); + float advance = middle - gameHour; + float factor = 0.f; + if (duration > 0) + factor = advance / duration * 2; return lerp(mSunsetValue, mDayValue, factor); } else { // fade out - float advance = gameHour - (timeSettings.mDayEnd + 1); - float factor = advance / 2.f; + float advance = gameHour - middle; + float factor = 1.f; + if (duration > 0) + factor = advance / duration * 2; return lerp(mSunsetValue, mNightValue, factor); } } @@ -539,10 +556,28 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall , mPlayingSoundID() { mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; - mTimeSettings.mNightEnd = mSunriseTime - 0.5f; + mTimeSettings.mNightEnd = mSunriseTime; mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration; mTimeSettings.mDayEnd = mSunsetTime; - mTimeSettings.mSunriseTime = mSunriseTime; + + mTimeSettings.addSetting(fallback, "Sky"); + mTimeSettings.addSetting(fallback, "Ambient"); + mTimeSettings.addSetting(fallback, "Fog"); + mTimeSettings.addSetting(fallback, "Sun"); + + // Morrowind handles stars settings differently for other ones + mTimeSettings.mStarsPostSunsetStart = fallback.getFallbackFloat("Weather_Stars_Post-Sunset_Start"); + mTimeSettings.mStarsPreSunriseFinish = fallback.getFallbackFloat("Weather_Stars_Pre-Sunrise_Finish"); + mTimeSettings.mStarsFadingDuration = fallback.getFallbackFloat("Weather_Stars_Fading_Duration"); + + WeatherSetting starSetting = { + mTimeSettings.mStarsPreSunriseFinish, + mTimeSettings.mStarsFadingDuration - mTimeSettings.mStarsPreSunriseFinish, + mTimeSettings.mStarsPostSunsetStart, + mTimeSettings.mStarsFadingDuration - mTimeSettings.mStarsPostSunsetStart + }; + + mTimeSettings.mSunriseTransitions["Stars"] = starSetting; mWeatherSettings.reserve(10); // These distant land fog factor and offset values are the defaults MGE XE provides. Should be @@ -698,10 +733,13 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, const float nightDuration = 24.f - dayDuration; double theta; - if ( !is_night ) { + if ( !is_night ) + { theta = static_cast(osg::PI) * (adjustedHour - mSunriseTime) / dayDuration; - } else { - theta = static_cast(osg::PI) * (1.f - (adjustedHour - adjustedNightStart) / nightDuration); + } + else + { + theta = static_cast(osg::PI) + static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; } osg::Vec3f final( @@ -711,7 +749,7 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, mRendering.setSunDirection( final * -1 ); } - float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings); + float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings, "Fog"); float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) @@ -784,7 +822,7 @@ unsigned int WeatherManager::getWeatherID() const bool WeatherManager::useTorches(float hour) const { - bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart - 1; + bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart; return isDark && !mPrecipitation; } @@ -1060,20 +1098,25 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mParticleEffect = current.mParticleEffect; mResult.mRainEffect = current.mRainEffect; - mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); + mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart + mTimeSettings.mStarsPostSunsetStart - mTimeSettings.mStarsFadingDuration); - mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings); + mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings, "Fog"); + mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings, "Fog"); + mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings, "Ambient"); + mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings, "Sun"); + mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings, "Sky"); + mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings, "Stars"); mResult.mDLFogFactor = current.mDL.FogFactor; mResult.mDLFogOffset = current.mDL.FogOffset; - mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); - mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); - mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); - mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings); - mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings); - if (gameHour >= mSunsetTime - mSunPreSunsetTime) + WeatherSetting setting = mTimeSettings.getSetting("Sun"); + float preSunsetTime = setting.mPreSunsetTime; + + if (gameHour >= mTimeSettings.mDayEnd - preSunsetTime) { - float factor = (gameHour - (mSunsetTime - mSunPreSunsetTime)) / mSunPreSunsetTime; + float factor = 1.f; + if (preSunsetTime > 0) + factor = (gameHour - (mTimeSettings.mDayEnd - preSunsetTime)) / preSunsetTime; factor = std::min(1.f, factor); mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor); // The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because @@ -1087,15 +1130,17 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam else mResult.mSunDiscColor = osg::Vec4f(1,1,1,1); - if (gameHour >= mSunsetTime) + if (gameHour >= mTimeSettings.mDayEnd) { - float fade = std::min(1.f, (gameHour - mSunsetTime) / 2.f); + // sunset + float fade = std::min(1.f, (gameHour - mTimeSettings.mDayEnd) / (mTimeSettings.mNightStart - mTimeSettings.mDayEnd)); fade = fade*fade; mResult.mSunDiscColor.a() = 1.f - fade; } - else if (gameHour >= mSunriseTime && gameHour <= mSunriseTime + 1) + else if (gameHour >= mTimeSettings.mNightEnd && gameHour <= mTimeSettings.mNightEnd + mSunriseDuration / 2.f) { - mResult.mSunDiscColor.a() = gameHour - mSunriseTime; + // sunrise + mResult.mSunDiscColor.a() = gameHour - mTimeSettings.mNightEnd; } else mResult.mSunDiscColor.a() = 1; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4be0d3e20..cf6868356 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -7,6 +7,8 @@ #include +#include + #include "../mwbase/soundmanager.hpp" #include "../mwrender/sky.hpp" @@ -38,6 +40,13 @@ namespace MWWorld { class TimeStamp; + struct WeatherSetting + { + float mPreSunriseTime; + float mPostSunriseTime; + float mPreSunsetTime; + float mPostSunsetTime; + }; struct TimeOfDaySettings { @@ -45,7 +54,37 @@ namespace MWWorld float mNightEnd; float mDayStart; float mDayEnd; - float mSunriseTime; + + std::map mSunriseTransitions; + + float mStarsPostSunsetStart; + float mStarsPreSunriseFinish; + float mStarsFadingDuration; + + WeatherSetting getSetting(const std::string& type) const + { + std::map::const_iterator it = mSunriseTransitions.find(type); + if (it != mSunriseTransitions.end()) + { + return it->second; + } + else + { + return { 1.f, 1.f, 1.f, 1.f }; + } + } + + void addSetting(const Fallback::Map& fallback, const std::string& type) + { + WeatherSetting setting = { + fallback.getFallbackFloat("Weather_" + type + "_Pre-Sunrise_Time"), + fallback.getFallbackFloat("Weather_" + type + "_Post-Sunrise_Time"), + fallback.getFallbackFloat("Weather_" + type + "_Pre-Sunset_Time"), + fallback.getFallbackFloat("Weather_" + type + "_Post-Sunset_Time") + }; + + mSunriseTransitions[type] = setting; + } }; /// Interpolates between 4 data points (sunrise, day, sunset, night) based on the time of day. @@ -59,7 +98,7 @@ namespace MWWorld { } - T getValue (const float gameHour, const TimeOfDaySettings& timeSettings) const; + T getValue (const float gameHour, const TimeOfDaySettings& timeSettings, const std::string& prefix) const; private: T mSunriseValue, mDayValue, mSunsetValue, mNightValue; From 5ead6353ac38cd3df0a09287034ee69da8bee554 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Jun 2018 16:44:46 +0400 Subject: [PATCH 267/321] Add missing changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd1acff2a..f36636571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.45.0 ------ + Bug #1990: Sunrise/sunset not set correct Bug #2835: Player able to slowly move when overencumbered Bug #3374: Touch spells not hitting kwama foragers Bug #3591: Angled hit distance too low From ae87e0d3fcbd1ba6348f51fcbb05a693741deda3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Jun 2018 15:34:08 +0400 Subject: [PATCH 268/321] Do not reset mUpperBodyState for weapon->weapon switch (regression #4446) --- apps/openmw/mwmechanics/character.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a0aad8b1b..07e5fa7d6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1214,7 +1214,6 @@ bool CharacterController::updateWeaponState() bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); if (!animPlaying || complete >= 1.0f) { - mUpperBodyState = UpperCharState_Nothing; forcestateupdate = true; mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype)); From fba0c155df01481b8f6bf534b9c20c5ebeb903c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Jun 2018 17:07:38 +0400 Subject: [PATCH 269/321] Fix assertion fail related to NiLookAtController --- components/nif/controller.cpp | 4 ++-- components/nif/controller.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index ddfa02a09..49f591b47 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -104,13 +104,13 @@ namespace Nif void NiLookAtController::read(NIFStream *nif) { Controller::read(nif); - data.read(nif); + target.read(nif); } void NiLookAtController::post(NIFFile *nif) { Controller::post(nif); - data.post(nif); + target.post(nif); } void NiPathController::read(NIFStream *nif) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index ce8bff041..f22d10622 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -102,7 +102,7 @@ public: class NiLookAtController : public Controller { public: - NiKeyframeDataPtr data; + NodePtr target; void read(NIFStream *nif); void post(NIFFile *nif); From 8f45b0d53a3c398df88d83681c24a25863b910ba Mon Sep 17 00:00:00 2001 From: wareya Date: Sat, 9 Jun 2018 10:11:43 -0400 Subject: [PATCH 270/321] remove unnecessary conditions --- components/esmterrain/storage.cpp | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index a1b4856e1..fd04d90b9 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -434,19 +434,14 @@ namespace ESMTerrain const int imageScaleFactor = 2; const int blendmapImageSize = blendmapSize * imageScaleFactor; - - const bool largeImage = true; - for (int i=0; i image (new osg::Image); - if(!largeImage) - image->allocateImage(blendmapSize, blendmapSize, 1, format, GL_UNSIGNED_BYTE); - else - image->allocateImage(blendmapImageSize, blendmapImageSize, 1, format, GL_UNSIGNED_BYTE); + image->allocateImage(blendmapImageSize, blendmapImageSize, 1, format, GL_UNSIGNED_BYTE); unsigned char* pData = image->data(); + for (int y=0; y Date: Sat, 9 Jun 2018 10:31:51 -0400 Subject: [PATCH 271/321] remove indentation from blank lines --- components/esmterrain/storage.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index fd04d90b9..dadc64f57 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -433,7 +433,7 @@ namespace ESMTerrain // We need to upscale the blendmap 2x with nearest neighbor sampling to look like Vanilla const int imageScaleFactor = 2; const int blendmapImageSize = blendmapSize * imageScaleFactor; - + for (int i=0; i image (new osg::Image); image->allocateImage(blendmapImageSize, blendmapImageSize, 1, format, GL_UNSIGNED_BYTE); unsigned char* pData = image->data(); - + for (int y=0; ysecond; int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; - + int alpha = (blendIndex == i) ? 255 : 0; - + int realY = (blendmapSize - y - 1)*imageScaleFactor; int realX = x*imageScaleFactor; - + pData[((realY+0)*blendmapImageSize + realX + 0)*channels + channel] = alpha; pData[((realY+1)*blendmapImageSize + realX + 0)*channels + channel] = alpha; pData[((realY+0)*blendmapImageSize + realX + 1)*channels + channel] = alpha; From a9ca528fb8a6afdb2d88cbde023e84a862e74004 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 9 Jun 2018 19:42:24 -0500 Subject: [PATCH 272/321] Adding version number of macOS build of OpenMW --- files/mac/openmw-Info.plist.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mac/openmw-Info.plist.in b/files/mac/openmw-Info.plist.in index b4a8af480..7583b45ad 100644 --- a/files/mac/openmw-Info.plist.in +++ b/files/mac/openmw-Info.plist.in @@ -18,6 +18,8 @@ APPL CFBundleSignature ???? + CFBundleShortVersionString + ${OPENMW_VERSION} CFBundleVersion ${OPENMW_VERSION} CSResourcesFileMapped From dbc87e7c7dc9d7adebda34d0458b972a682038ec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Jun 2018 11:28:22 +0200 Subject: [PATCH 273/321] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd1acff2a..a3101056e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Bug #3897: Have Goodbye give all choices the effects of Goodbye Bug #3997: Almalexia doesn't pace Bug #4036: Weird behaviour of AI packages if package target has non-unique ID + Bug #4047: OpenMW not reporting its version number in MacOS; OpenMW-CS not doing it fully Bug #4221: Characters get stuck in V-shaped terrain Bug #4251: Stationary NPCs do not return to their position after combat Bug #4293: Faction members are not aware of faction ownerships in barter From 0375bedab229358b8fe04c29cd16d382623f4370 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:57:36 +0400 Subject: [PATCH 274/321] Equip previous item after a bound item expires (bug #2326) --- apps/openmw/mwmechanics/actors.cpp | 106 +++++++++++++++++++++++------ apps/openmw/mwmechanics/actors.hpp | 4 ++ 2 files changed, 91 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7990373a7..10e9b7afc 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -50,27 +50,36 @@ bool isConscious(const MWWorld::Ptr& ptr) return !stats.isDead() && !stats.getKnockedDown(); } -void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& actor) +int getBoundItemSlot (const std::string& itemId) { - if (bound) + static std::map boundItemsMap; + if (boundItemsMap.empty()) { - if (actor.getClass().getContainerStore(actor).count(item) == 0) - { - MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); - MWWorld::Ptr newPtr = *store.MWWorld::ContainerStore::add(item, 1, actor); - MWWorld::ActionEquip action(newPtr); - action.execute(actor); - MWWorld::ConstContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - // change draw state only if the item is in player's right hand - if (actor == MWMechanics::getPlayer() - && rightHand != store.end() && newPtr == *rightHand) - { - MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - } - } + std::string boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundBootsID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Boots; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundCuirassID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Cuirass; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundLeftGauntletID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_LeftGauntlet; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundRightGauntletID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_RightGauntlet; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundHelmID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Helmet; + + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundShieldID")->getString(); + boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_CarriedLeft; } - else - actor.getClass().getInventoryStore(actor).remove(item, 1, actor, true); + + int slot = MWWorld::InventoryStore::Slot_CarriedRight; + std::map::iterator it = boundItemsMap.find(itemId); + if (it != boundItemsMap.end()) + slot = it->second; + + return slot; } class CheckActorCommanded : public MWMechanics::EffectSourceVisitor @@ -139,7 +148,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float namespace MWMechanics { - const float aiProcessingDistance = 7168; const float sqrAiProcessingDistance = aiProcessingDistance*aiProcessingDistance; @@ -227,6 +235,65 @@ namespace MWMechanics } }; + void Actors::adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor) + { + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + + if (bound) + { + if (actor.getClass().getContainerStore(actor).count(itemId) != 0) + return; + + int slot = getBoundItemSlot(itemId); + + MWWorld::Ptr prevItem = *store.getSlot(slot); + + MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); + MWWorld::ActionEquip action(boundPtr); + action.execute(actor); + + if (actor != MWMechanics::getPlayer()) + return; + + MWWorld::Ptr newItem = *store.getSlot(slot); + + if (newItem.isEmpty() || boundPtr != newItem) + return; + + // change draw state only if the item is in player's right hand + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + + mPreviousItems[slot] = std::make_pair(itemId, prevItem.isEmpty() ? "" : prevItem.getCellRef().getRefId()); + } + else + { + store.remove(itemId, 1, actor, true); + + if (actor != MWMechanics::getPlayer()) + return; + + int slot = getBoundItemSlot(itemId); + + std::pair prevItem = mPreviousItems[slot]; + + if (prevItem.first != itemId) + return; + + MWWorld::Ptr ptr = MWWorld::Ptr(); + if (prevItem.second != "") + ptr = store.search (prevItem.second); + + mPreviousItems.erase(slot); + + if (ptr.isEmpty()) + return; + + MWWorld::ActionEquip action(ptr); + action.execute(actor); + } + } + void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) { // magic effects @@ -1875,6 +1942,7 @@ namespace MWMechanics } mActors.clear(); mDeathCount.clear(); + mPreviousItems.clear(); } void Actors::updateMagicEffects(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 15f2d3dc8..f0e157db1 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,6 +25,10 @@ namespace MWMechanics class Actors { std::map mDeathCount; + typedef std::map> PreviousItems; + PreviousItems mPreviousItems; + + void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); void updateNpc(const MWWorld::Ptr &ptr, float duration); From 9b72a6ac69ddd4b282ff3c9ed46ca4d8b7cde44c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 27 Nov 2017 13:00:14 +0400 Subject: [PATCH 275/321] Use the MWWorld::Ptr() instead of string ID --- apps/openmw/mwmechanics/actors.cpp | 23 +++++++++++++++-------- apps/openmw/mwmechanics/actors.hpp | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 10e9b7afc..76c5744b3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -264,7 +264,7 @@ namespace MWMechanics if (slot == MWWorld::InventoryStore::Slot_CarriedRight) MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - mPreviousItems[slot] = std::make_pair(itemId, prevItem.isEmpty() ? "" : prevItem.getCellRef().getRefId()); + mPreviousItems[slot] = std::make_pair(itemId, prevItem); } else { @@ -275,21 +275,28 @@ namespace MWMechanics int slot = getBoundItemSlot(itemId); - std::pair prevItem = mPreviousItems[slot]; + std::pair prevItem = mPreviousItems[slot]; if (prevItem.first != itemId) return; - MWWorld::Ptr ptr = MWWorld::Ptr(); - if (prevItem.second != "") - ptr = store.search (prevItem.second); - mPreviousItems.erase(slot); - if (ptr.isEmpty()) + if (prevItem.second.isEmpty()) + return; + + // check if the item is still in the player's inventory + MWWorld::ContainerStoreIterator it = store.begin(); + for (; it != store.end(); ++it) + { + if (*it == prevItem.second) + break; + } + + if (it == store.end()) return; - MWWorld::ActionEquip action(ptr); + MWWorld::ActionEquip action(prevItem.second); action.execute(actor); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f0e157db1..40e9e1d21 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,7 +25,7 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map> PreviousItems; + typedef std::map> PreviousItems; PreviousItems mPreviousItems; void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); From d1b1cb748d94cda070c5383973329613620097d0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Dec 2017 16:26:43 +0400 Subject: [PATCH 276/321] Reequip previous item only if the expired bound item was equipped --- apps/openmw/mwmechanics/actors.cpp | 41 +++++++++++++++--------------- apps/openmw/mwmechanics/actors.hpp | 2 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 76c5744b3..4019067e3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -238,15 +238,14 @@ namespace MWMechanics void Actors::adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor) { MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + int slot = getBoundItemSlot(itemId); if (bound) { if (actor.getClass().getContainerStore(actor).count(itemId) != 0) return; - int slot = getBoundItemSlot(itemId); - - MWWorld::Ptr prevItem = *store.getSlot(slot); + MWWorld::ContainerStoreIterator prevItem = store.getSlot(slot); MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); MWWorld::ActionEquip action(boundPtr); @@ -264,39 +263,40 @@ namespace MWMechanics if (slot == MWWorld::InventoryStore::Slot_CarriedRight) MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - mPreviousItems[slot] = std::make_pair(itemId, prevItem); + if (prevItem != store.end()) + mPreviousItems[itemId] = *prevItem; } else { + MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); + + bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); + store.remove(itemId, 1, actor, true); if (actor != MWMechanics::getPlayer()) return; - int slot = getBoundItemSlot(itemId); + MWWorld::Ptr prevItem = mPreviousItems[itemId]; - std::pair prevItem = mPreviousItems[slot]; + mPreviousItems.erase(itemId); - if (prevItem.first != itemId) - return; - - mPreviousItems.erase(slot); - - if (prevItem.second.isEmpty()) + if (prevItem.isEmpty()) return; // check if the item is still in the player's inventory MWWorld::ContainerStoreIterator it = store.begin(); for (; it != store.end(); ++it) { - if (*it == prevItem.second) + if (*it == prevItem) break; } - if (it == store.end()) + // we should equip previous item only if expired bound item was equipped. + if (it == store.end() || !wasEquipped) return; - MWWorld::ActionEquip action(prevItem.second); + MWWorld::ActionEquip action(prevItem); action.execute(actor); } } @@ -830,9 +830,15 @@ namespace MWMechanics float magnitude = effects.get(it->first).getMagnitude(); if (found != (magnitude > 0)) { + if (magnitude > 0) + creatureStats.mBoundItems.insert(it->first); + else + creatureStats.mBoundItems.erase(it->first); + std::string itemGmst = it->second; std::string item = MWBase::Environment::get().getWorld()->getStore().get().find( itemGmst)->getString(); + if (it->first == ESM::MagicEffect::BoundGloves) { item = MWBase::Environment::get().getWorld()->getStore().get().find( @@ -844,11 +850,6 @@ namespace MWMechanics } else adjustBoundItem(item, magnitude > 0, ptr); - - if (magnitude > 0) - creatureStats.mBoundItems.insert(it->first); - else - creatureStats.mBoundItems.erase(it->first); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 40e9e1d21..e696abf01 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,7 +25,7 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map> PreviousItems; + typedef std::map PreviousItems; PreviousItems mPreviousItems; void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); From 4de9d9fa778402eff3de8c9e8d56b44132aaca80 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Dec 2017 17:18:16 +0400 Subject: [PATCH 277/321] Split adjustBoundItem() --- apps/openmw/mwmechanics/actors.cpp | 96 +++++++++++++++--------------- apps/openmw/mwmechanics/actors.hpp | 3 +- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4019067e3..d1e74e576 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -235,70 +235,71 @@ namespace MWMechanics } }; - void Actors::adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor) + void Actors::addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) { MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); int slot = getBoundItemSlot(itemId); - if (bound) - { - if (actor.getClass().getContainerStore(actor).count(itemId) != 0) - return; + if (actor.getClass().getContainerStore(actor).count(itemId) != 0) + return; - MWWorld::ContainerStoreIterator prevItem = store.getSlot(slot); + MWWorld::ContainerStoreIterator prevItem = store.getSlot(slot); - MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); - MWWorld::ActionEquip action(boundPtr); - action.execute(actor); + MWWorld::Ptr boundPtr = *store.MWWorld::ContainerStore::add(itemId, 1, actor); + MWWorld::ActionEquip action(boundPtr); + action.execute(actor); - if (actor != MWMechanics::getPlayer()) - return; + if (actor != MWMechanics::getPlayer()) + return; - MWWorld::Ptr newItem = *store.getSlot(slot); + MWWorld::Ptr newItem = *store.getSlot(slot); - if (newItem.isEmpty() || boundPtr != newItem) - return; + if (newItem.isEmpty() || boundPtr != newItem) + return; - // change draw state only if the item is in player's right hand - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + // change draw state only if the item is in player's right hand + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); - if (prevItem != store.end()) - mPreviousItems[itemId] = *prevItem; - } - else - { - MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); + if (prevItem != store.end()) + mPreviousItems[itemId] = *prevItem; + } - bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); + void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) + { + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + int slot = getBoundItemSlot(itemId); - store.remove(itemId, 1, actor, true); + MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); - if (actor != MWMechanics::getPlayer()) - return; + bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); - MWWorld::Ptr prevItem = mPreviousItems[itemId]; + store.remove(itemId, 1, actor, true); - mPreviousItems.erase(itemId); + if (actor != MWMechanics::getPlayer()) + return; - if (prevItem.isEmpty()) - return; + MWWorld::Ptr prevItem = mPreviousItems[itemId]; - // check if the item is still in the player's inventory - MWWorld::ContainerStoreIterator it = store.begin(); - for (; it != store.end(); ++it) - { - if (*it == prevItem) - break; - } + mPreviousItems.erase(itemId); - // we should equip previous item only if expired bound item was equipped. - if (it == store.end() || !wasEquipped) - return; + if (prevItem.isEmpty()) + return; - MWWorld::ActionEquip action(prevItem); - action.execute(actor); + // check if the item is still in the player's inventory + MWWorld::ContainerStoreIterator it = store.begin(); + for (; it != store.end(); ++it) + { + if (*it == prevItem) + break; } + + // we should equip previous item only if expired bound item was equipped. + if (it == store.end() || !wasEquipped) + return; + + MWWorld::ActionEquip action(prevItem); + action.execute(actor); } void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) @@ -839,17 +840,14 @@ namespace MWMechanics std::string item = MWBase::Environment::get().getWorld()->getStore().get().find( itemGmst)->getString(); + magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr); + if (it->first == ESM::MagicEffect::BoundGloves) { - item = MWBase::Environment::get().getWorld()->getStore().get().find( - "sMagicBoundLeftGauntletID")->getString(); - adjustBoundItem(item, magnitude > 0, ptr); item = MWBase::Environment::get().getWorld()->getStore().get().find( "sMagicBoundRightGauntletID")->getString(); - adjustBoundItem(item, magnitude > 0, ptr); + magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr); } - else - adjustBoundItem(item, magnitude > 0, ptr); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index e696abf01..b3e1f95db 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -28,7 +28,8 @@ namespace MWMechanics typedef std::map PreviousItems; PreviousItems mPreviousItems; - void adjustBoundItem (const std::string& itemId, bool bound, const MWWorld::Ptr& actor); + void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); + void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void updateNpc(const MWWorld::Ptr &ptr, float duration); From f977c6876ff391cc4624483647bf3197791482c5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 23 Feb 2018 14:48:40 +0400 Subject: [PATCH 278/321] Bound items: store item ID instead of pointer --- apps/openmw/mwmechanics/actors.cpp | 28 ++++++++++++++++++---------- apps/openmw/mwmechanics/actors.hpp | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d1e74e576..8a13b492f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,7 +262,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); if (prevItem != store.end()) - mPreviousItems[itemId] = *prevItem; + mPreviousItems[itemId] = (*prevItem).getCellRef().getRefId(); } void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) @@ -279,26 +279,34 @@ namespace MWMechanics if (actor != MWMechanics::getPlayer()) return; - MWWorld::Ptr prevItem = mPreviousItems[itemId]; + std::string prevItemId = mPreviousItems[itemId]; mPreviousItems.erase(itemId); - if (prevItem.isEmpty()) + if (prevItemId.empty()) return; - // check if the item is still in the player's inventory - MWWorld::ContainerStoreIterator it = store.begin(); - for (; it != store.end(); ++it) + // Find the item by id + MWWorld::Ptr item; + for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) { - if (*it == prevItem) - break; + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), prevItemId)) + { + if (item.isEmpty() || + // Prefer the stack with the lowest remaining uses + !item.getClass().hasItemHealth(*iter) || + iter->getClass().getItemHealth(*iter) < item.getClass().getItemHealth(item)) + { + item = *iter; + } + } } // we should equip previous item only if expired bound item was equipped. - if (it == store.end() || !wasEquipped) + if (item.isEmpty() || !wasEquipped) return; - MWWorld::ActionEquip action(prevItem); + MWWorld::ActionEquip action(item); action.execute(actor); } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index b3e1f95db..90b646f0e 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,7 +25,7 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map PreviousItems; + typedef std::map PreviousItems; PreviousItems mPreviousItems; void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); From 9fd2d57b8663dee2df8ca739f15d7b39b769b3a6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 9 Mar 2018 08:56:04 +0400 Subject: [PATCH 279/321] Move previous items to player --- apps/openmw/mwmechanics/actors.cpp | 14 ++++++++------ apps/openmw/mwmechanics/actors.hpp | 3 --- apps/openmw/mwworld/player.cpp | 16 ++++++++++++++++ apps/openmw/mwworld/player.hpp | 9 +++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8a13b492f..6549c169b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,7 +262,10 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); if (prevItem != store.end()) - mPreviousItems[itemId] = (*prevItem).getCellRef().getRefId(); + { + MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); + player->setPreviousItem(itemId, prevItem->getCellRef().getRefId()); + } } void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) @@ -272,16 +275,16 @@ namespace MWMechanics MWWorld::ContainerStoreIterator currentItem = store.getSlot(slot); - bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual((*currentItem).getCellRef().getRefId(), itemId); + bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual(currentItem->getCellRef().getRefId(), itemId); store.remove(itemId, 1, actor, true); if (actor != MWMechanics::getPlayer()) return; - std::string prevItemId = mPreviousItems[itemId]; - - mPreviousItems.erase(itemId); + MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); + std::string prevItemId = player->getPreviousItem(itemId); + player->erasePreviousItem(itemId); if (prevItemId.empty()) return; @@ -1956,7 +1959,6 @@ namespace MWMechanics } mActors.clear(); mDeathCount.clear(); - mPreviousItems.clear(); } void Actors::updateMagicEffects(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 90b646f0e..0de1f4d6c 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "../mwbase/world.hpp" @@ -25,8 +24,6 @@ namespace MWMechanics class Actors { std::map mDeathCount; - typedef std::map PreviousItems; - PreviousItems mPreviousItems; void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 34c5f713d..193663098 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -287,6 +287,7 @@ namespace MWWorld mAttackingOrSpell = false; mCurrentCrimeId = -1; mPaidCrimeId = -1; + mPreviousItems.clear(); mLastKnownExteriorPosition = osg::Vec3f(0,0,0); for (int i=0; i + #include "../mwworld/refdata.hpp" #include "../mwworld/livecellref.hpp" @@ -46,6 +48,9 @@ namespace MWWorld int mCurrentCrimeId; // the id assigned witnesses int mPaidCrimeId; // the last id paid off (0 bounty) + typedef std::map PreviousItems; // previous equipped items, needed for bound spells + PreviousItems mPreviousItems; + // Saved stats prior to becoming a werewolf MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; @@ -120,6 +125,10 @@ namespace MWWorld int getNewCrimeId(); // get new id for witnesses void recordCrimeId(); // record the paid crime id when bounty is 0 int getCrimeId() const; // get the last paid crime id + + void setPreviousItem(const std::string& boundItemId, const std::string& previousItemId); + std::string getPreviousItem(const std::string& boundItemId); + void erasePreviousItem(const std::string& boundItemId); }; } #endif From acd3cba5fae441602389bd2dbef4579e8e70a842 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 9 Mar 2018 10:20:17 +0400 Subject: [PATCH 280/321] Store previous items in the savegame --- CHANGELOG.md | 1 + apps/openmw/mwworld/player.cpp | 4 ++++ components/esm/player.cpp | 18 ++++++++++++++++++ components/esm/player.hpp | 3 +++ components/esm/savedgame.cpp | 2 +- 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3101056e..a19b012c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.45.0 ------ + Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped Bug #2835: Player able to slowly move when overencumbered Bug #3374: Touch spells not hitting kwama foragers Bug #3591: Angled hit distance too low diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 193663098..5439447fd 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -342,6 +342,8 @@ namespace MWWorld for (int i=0; ifirst); + esm.writeHNString ("PREV", it->second); + } + for (int i=0; i mSaveAttributes[ESM::Attribute::Length]; StatState mSaveSkills[ESM::Skill::Length]; + typedef std::map PreviousItems; // previous equipped items, needed for bound spells + PreviousItems mPreviousItems; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index c96261c64..ea9fef4fb 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 4; +int ESM::SavedGame::sCurrentFormat = 5; void ESM::SavedGame::load (ESMReader &esm) { From ab03d238bbacb0ae3ef967d005e6bc375f99ed3b Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 10 Jun 2018 07:43:38 -0500 Subject: [PATCH 281/321] Adding Feature #4345 Implemented as part of #1623, but not added. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3101056e..8c8a7eb90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Feature #4345: Add equivalents for the command line commands to Launcher Feature #4444: Per-group KF-animation files support 0.44.0 From d43766d3c9936c3875c1f2bcd0d88c68558dc9f6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 10 Jun 2018 17:47:05 +0300 Subject: [PATCH 282/321] Make WakeUpPC interrupt waiting if it was supposed to be (fixes #3629) --- CHANGELOG.md | 1 + apps/openmw/mwgui/waitdialog.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3101056e..5a22b9d47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Bug #2835: Player able to slowly move when overencumbered Bug #3374: Touch spells not hitting kwama foragers Bug #3591: Angled hit distance too low + Bug #3629: DB assassin attack never triggers creature spawning Bug #3897: Have Goodbye give all choices the effects of Goodbye Bug #3997: Almalexia doesn't pace Bug #4036: Weird behaviour of AI packages if package target has non-unique ID diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 61febf315..52575e25c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -310,8 +310,10 @@ namespace MWGui void WaitDialog::wakeUp () { mSleeping = false; - mTimeAdvancer.stop(); - stopWaiting(); + if (mInterruptAt != -1) + onWaitingInterrupted(); + else + stopWaiting(); } } From 66a46ff03cf997197dcbfd9e7494de716cee58c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 11 Jun 2018 11:22:56 +0400 Subject: [PATCH 283/321] Do not show any book text after last
tag. --- CHANGELOG.md | 1 + apps/openmw/mwgui/formatting.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3101056e..356be37a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Bug #3997: Almalexia doesn't pace Bug #4036: Weird behaviour of AI packages if package target has non-unique ID Bug #4047: OpenMW not reporting its version number in MacOS; OpenMW-CS not doing it fully + Bug #4215: OpenMW shows book text after last
tag Bug #4221: Characters get stuck in V-shaped terrain Bug #4251: Stationary NPCs do not return to their position after combat Bug #4293: Faction members are not aware of faction ownerships in barter diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index a9319048e..16568e2f3 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -31,6 +31,14 @@ namespace MWGui boost::algorithm::replace_all(mText, "\r", ""); + // vanilla game does not show any text after last
tag. + const std::string lowerText = Misc::StringUtils::lowerCase(mText); + int index = lowerText.rfind("
"); + if (index == -1) + mText = ""; + else + mText = mText.substr(0, index+4); + registerTag("br", Event_BrTag); registerTag("p", Event_PTag); registerTag("img", Event_ImgTag); From 5fba1c599b761fd9e81ee2d0d3f898be49bc8abf Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 05:52:19 +0000 Subject: [PATCH 284/321] Update README.md with an important distinction. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc600fdbe..7d92879e2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ OpenMW [![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/github/openmw/openmw?svg=true)](https://ci.appveyor.com/project/psi29a/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) -OpenMW is a recreation of the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. +OpenMW is a open-source game engine that supports playing Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. From 7502a7dc4d299cdacbf46275ad2c820e71c0e125 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 07:52:53 +0000 Subject: [PATCH 285/321] what does this give us from a CI perspective? --- .gitlab-ci.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..90525e5a9 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,26 @@ +# use the official gcc image, based on debian +# can use verions as well, like gcc:5.2 +# see https://hub.docker.com/_/gcc/ +image: gcc + +build: + stage: build + # instead of calling g++ directly you can also use some build toolkit like make + # install the necessary build tools when needed + # before_script: + - apt update && apt -y install build-essential cmake git + script: + - whois + # artifacts: + # paths: + # - mybinary + # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time + # cache: + # paths: + # - "*.o" + +# run tests using the binary built before +test: + stage: test + script: + - whois From 04dc74a1d6898dbd26961cfb13127117b74cc0fc Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 08:05:30 +0000 Subject: [PATCH 286/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 90525e5a9..3b0dca5fe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,12 +8,12 @@ build: # instead of calling g++ directly you can also use some build toolkit like make # install the necessary build tools when needed # before_script: - - apt update && apt -y install build-essential cmake git + # - apt update && apt -y install make autoconf script: - whois - # artifacts: - # paths: - # - mybinary +# artifacts: +# paths: +# - mybinary # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time # cache: # paths: From 8714f48ce7b1bed792e6cd582710a1ad3da72fbd Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 08:22:44 +0000 Subject: [PATCH 287/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3b0dca5fe..394f07136 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ build: # before_script: # - apt update && apt -y install make autoconf script: - - whois + - ls /etc # artifacts: # paths: # - mybinary @@ -23,4 +23,4 @@ build: test: stage: test script: - - whois + - ls From d986354d53af6a22162257eebfb146f46237adc1 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 08:30:18 +0000 Subject: [PATCH 288/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 394f07136..b614160e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,13 @@ build: # before_script: # - apt update && apt -y install make autoconf script: + - ls ./ - ls /etc + - ls /bin + - ls /usr/bin + - cat /etc/lsb-release + - apt-get install -y cmake + - mkdir build; cd build; cmake ../openmw # artifacts: # paths: # - mybinary From de1cad86abb974e0d88c33d030cf518624204737 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 08:37:26 +0000 Subject: [PATCH 289/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b614160e9..f8df83a5f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,9 +14,8 @@ build: - ls /etc - ls /bin - ls /usr/bin - - cat /etc/lsb-release - apt-get install -y cmake - - mkdir build; cd build; cmake ../openmw + - mkdir build; cd build; cmake ../ # artifacts: # paths: # - mybinary From 8c4731728c97822af846ae8e3322e1b77bdd568b Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 08:41:07 +0000 Subject: [PATCH 290/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f8df83a5f..7d1adb5ab 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,6 +14,8 @@ build: - ls /etc - ls /bin - ls /usr/bin + - apt-get update + - apt-cache search cmake - apt-get install -y cmake - mkdir build; cd build; cmake ../ # artifacts: From 20d8a424d6a5dd32aa373321a8f21aeba454f0ab Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 09:09:37 +0000 Subject: [PATCH 291/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7d1adb5ab..262c8147c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,8 +16,14 @@ build: - ls /usr/bin - apt-get update - apt-cache search cmake - - apt-get install -y cmake + - apt-get install -y cmake + - apt-get install -y libunshield-dev libtinyxml-dev + - apt-get install -y libboost-filesystem-dev libboost-program-options-dev libboost-system-dev + - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev + - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev + - apt-get install -y libbullet-dev libopenscenegraph-3.4-dev libmygui-dev - mkdir build; cd build; cmake ../ + - make -j4 # artifacts: # paths: # - mybinary From a89441e879d0bf31a7f1d9502a367371d5bd0b6d Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 09:26:10 +0000 Subject: [PATCH 292/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 262c8147c..28fdec103 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,11 +17,13 @@ build: - apt-get update - apt-cache search cmake - apt-get install -y cmake - - apt-get install -y libunshield-dev libtinyxml-dev + - apt-get install -y - apt-get install -y libboost-filesystem-dev libboost-program-options-dev libboost-system-dev - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev - - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev - - apt-get install -y libbullet-dev libopenscenegraph-3.4-dev libmygui-dev + - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libmygui-dev libunshield-dev libtinyxml-dev + - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb + - dpkg -i *.deb - mkdir build; cd build; cmake ../ - make -j4 # artifacts: From e5dff83e38583a968f95217dd8c4fc183ef8c7ec Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 09:26:42 +0000 Subject: [PATCH 293/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 28fdec103..67481a71f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,7 +17,6 @@ build: - apt-get update - apt-cache search cmake - apt-get install -y cmake - - apt-get install -y - apt-get install -y libboost-filesystem-dev libboost-program-options-dev libboost-system-dev - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libmygui-dev libunshield-dev libtinyxml-dev From bc0eb3349bf037ca599da1db2f21a15d17dc747c Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 10:33:35 +0000 Subject: [PATCH 294/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 67481a71f..b372e6dbf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,24 +10,22 @@ build: # before_script: # - apt update && apt -y install make autoconf script: - - ls ./ - - ls /etc - - ls /bin - - ls /usr/bin - apt-get update - - apt-cache search cmake - - apt-get install -y cmake - - apt-get install -y libboost-filesystem-dev libboost-program-options-dev libboost-system-dev + - apt-get install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev - - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libmygui-dev libunshield-dev libtinyxml-dev + - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev + - apt-get install -y libmygui-dev libullet-dev # to be updated to latest below because stretch is too old - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - dpkg -i *.deb - mkdir build; cd build; cmake ../ - make -j4 -# artifacts: -# paths: -# - mybinary + artifacts: + paths: + - build # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time # cache: # paths: From e3832cd2e2cbb3b46d3c71db14cf54289acf4ad4 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 11:24:27 +0000 Subject: [PATCH 295/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b372e6dbf..f6e599a09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ build: - apt-get install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev - - apt-get install -y libmygui-dev libullet-dev # to be updated to latest below because stretch is too old + - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb From dddceba8f2d2911f4340094307e8e27536001e12 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 11:32:37 +0000 Subject: [PATCH 296/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f6e599a09..be9986e6d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,10 +17,11 @@ build: - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb +# - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - - dpkg -i *.deb + - dpkg -i *.deb --ignore-depends - mkdir build; cd build; cmake ../ - make -j4 artifacts: From a166534226dd34d7ca2e5da8a9ee805c8e9b02a7 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 11:41:19 +0000 Subject: [PATCH 297/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index be9986e6d..fed43f495 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ build: - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - - dpkg -i *.deb --ignore-depends + - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb - mkdir build; cd build; cmake ../ - make -j4 artifacts: From 1c736ea06448ee9660668fc31e1ca4f92d593550 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 12:46:19 +0000 Subject: [PATCH 298/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fed43f495..ac0fb1175 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,10 +5,6 @@ image: gcc build: stage: build - # instead of calling g++ directly you can also use some build toolkit like make - # install the necessary build tools when needed - # before_script: - # - apt update && apt -y install make autoconf script: - apt-get update - apt-get install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev @@ -17,23 +13,23 @@ build: - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb -# - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.ogreplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb - mkdir build; cd build; cmake ../ - make -j4 + - DESTDIR=artifacts make install artifacts: paths: - - build + - build/artifacts/ # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time - # cache: - # paths: - # - "*.o" + cache: + paths: + - "*.o" # run tests using the binary built before -test: - stage: test - script: - - ls +#test: +# stage: test +# script: +# - ls From 816a1733dcf6adc8edf17ed5ebd9c1d16daed7e6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Jun 2018 15:29:28 +0200 Subject: [PATCH 299/321] Allow comma after Begin and End script instruction (Fixes #4451) --- components/compiler/fileparser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 52a9a63f1..c9e205b8a 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -119,6 +119,11 @@ namespace Compiler return false; } } + else if (code==Scanner::S_comma && (mState==NameState || mState==EndNameState)) + { + // ignoring comma (for now) + return true; + } return Parser::parseSpecial (code, loc, scanner); } From 296ad8424e998cb0215fc2e62a99c3a1bdd6f377 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Jun 2018 17:06:09 +0200 Subject: [PATCH 300/321] updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e199d0827..346d2c53c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ Bug #3374: Touch spells not hitting kwama foragers Bug #3591: Angled hit distance too low Bug #3629: DB assassin attack never triggers creature spawning + Bug #3876: Landscape texture painting is misaligned Bug #3897: Have Goodbye give all choices the effects of Goodbye + Bug #3993: Terrain texture blending map is not upscaled Bug #3997: Almalexia doesn't pace Bug #4036: Weird behaviour of AI packages if package target has non-unique ID Bug #4047: OpenMW not reporting its version number in MacOS; OpenMW-CS not doing it fully From 565922f9ad910473e9a8430bc860171187978782 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Jun 2018 17:52:16 +0200 Subject: [PATCH 301/321] naked expressions beginning with the member operator were allowed erroneously outside of the console (Fixes issue #2971) --- components/compiler/lineparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index c7f82a3d0..2d551348d 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -512,7 +512,7 @@ namespace Compiler return true; } - if (code==Scanner::S_member && mState==PotentialExplicitState) + if (code==Scanner::S_member && mState==PotentialExplicitState && mAllowExpression) { mState = MemberState; parseExpression (scanner, loc); From 1c8a20a54afc3958e3e622a331fe798c45e9f43d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 12 Jun 2018 19:33:41 +0300 Subject: [PATCH 302/321] Set ok button focus in settings window by default (fixes #4368) --- CHANGELOG.md | 1 + apps/openmw/mwgui/settingswindow.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 346d2c53c..f407a156e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Bug #4251: Stationary NPCs do not return to their position after combat Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4327: Missing animations during spell/weapon stance switching + Bug #4368: Settings window ok button doesn't have key focus by default Bug #4419: MRK NiStringExtraData is handled incorrectly Bug #4426: RotateWorld behavior is incorrect Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 9bf6e4385..677ddefb3 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -562,8 +562,9 @@ namespace MWGui void SettingsWindow::onOpen() { - updateControlsBox (); + updateControlsBox(); resetScrollbars(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); } void SettingsWindow::onWindowResize(MyGUI::Window *_sender) From 6114cff8422ee2e2dfc5b53852452a7be55bfe86 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Jun 2018 19:14:32 +0200 Subject: [PATCH 303/321] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index b029140c7..b13953824 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -63,6 +63,7 @@ Programmers Evgeniy Mineev (sandstranger) Federico Guerra (FedeWar) Fil Krynicki (filkry) + Florian Weber (Florianjw) Gašper Sedej gugus/gus Hallfaer Tuilinn From 9c45cc7e48897171fc27c219bd1e7d9533b81ff9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 12 Jun 2018 22:05:00 +0400 Subject: [PATCH 304/321] Use player reference instead of pointer --- apps/openmw/mwmechanics/actors.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6549c169b..de394c446 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -257,15 +257,14 @@ namespace MWMechanics if (newItem.isEmpty() || boundPtr != newItem) return; + MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + // change draw state only if the item is in player's right hand if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + player.setDrawState(MWMechanics::DrawState_Weapon); if (prevItem != store.end()) - { - MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); - player->setPreviousItem(itemId, prevItem->getCellRef().getRefId()); - } + player.setPreviousItem(itemId, prevItem->getCellRef().getRefId()); } void Actors::removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor) @@ -282,9 +281,9 @@ namespace MWMechanics if (actor != MWMechanics::getPlayer()) return; - MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); - std::string prevItemId = player->getPreviousItem(itemId); - player->erasePreviousItem(itemId); + MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + std::string prevItemId = player.getPreviousItem(itemId); + player.erasePreviousItem(itemId); if (prevItemId.empty()) return; From cc396f4dfdace36c9efd12526d52eefb5392a762 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 19:06:59 +0000 Subject: [PATCH 305/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ac0fb1175..5f2cbf912 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,7 @@ image: gcc build: stage: build script: + - nproc - apt-get update - apt-get install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev @@ -18,7 +19,7 @@ build: - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb - mkdir build; cd build; cmake ../ - - make -j4 + - make -j3 - DESTDIR=artifacts make install artifacts: paths: @@ -29,7 +30,7 @@ build: - "*.o" # run tests using the binary built before -#test: -# stage: test -# script: -# - ls +test: + stage: test + script: + - true From 3c933ebaad915b6726e55aff10b228df4fce9b34 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 12 Jun 2018 19:10:15 +0000 Subject: [PATCH 306/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5f2cbf912..2a4607a38 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,4 +33,4 @@ build: test: stage: test script: - - true + - ls From 058cfb553ce2a20a0150793796b4b5c32527eb9b Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 12 Jun 2018 22:18:06 -0500 Subject: [PATCH 307/321] Adding CFBundleIdentifier to OpenMW's Info.plist file for Macs --- files/mac/openmw-Info.plist.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mac/openmw-Info.plist.in b/files/mac/openmw-Info.plist.in index 7583b45ad..20dc36afa 100644 --- a/files/mac/openmw-Info.plist.in +++ b/files/mac/openmw-Info.plist.in @@ -8,6 +8,8 @@ English CFBundleExecutable openmw-launcher + CFBundleIdentifier + org.openmw.openmw CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString From b37f3251263ec86d2c8c1622989616d1c674d64e Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 12 Jun 2018 22:20:16 -0500 Subject: [PATCH 308/321] #4324/Updating Changelog.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f407a156e..95a947d70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts Feature #4345: Add equivalents for the command line commands to Launcher Feature #4444: Per-group KF-animation files support From 2e2be76e3ff700a3348d6420571b650a9e2cdd40 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 08:20:31 +0000 Subject: [PATCH 309/321] Update .gitlab-ci.yml --- .gitlab-ci.yml | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2a4607a38..18ae73124 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,23 +3,29 @@ # see https://hub.docker.com/_/gcc/ image: gcc +cache: + key: apt-cache + paths: + - apt-cache/ + +before_script: + - export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR + - apt-get update -yq + - apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev +# - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old + - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb + - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb + - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb + build: stage: build script: - nproc - - apt-get update - - apt-get install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev - - apt-get install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev - - apt-get install -y libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev - - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - - curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - - curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb - - mkdir build; cd build; cmake ../ - - make -j3 + - mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../ + - make -j2 - DESTDIR=artifacts make install artifacts: paths: From a49649c313ce267318d203a0687afe53ac37d70b Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 09:29:30 +0000 Subject: [PATCH 310/321] Try to get it to run and build on my docker instance. --- .gitlab-ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 18ae73124..961965763 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,6 +3,11 @@ # see https://hub.docker.com/_/gcc/ image: gcc +job: + tags: + - openmw + - debian + cache: key: apt-cache paths: @@ -25,7 +30,7 @@ build: script: - nproc - mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../ - - make -j2 + - make -j4 - DESTDIR=artifacts make install artifacts: paths: From 559754fa7683dd33084013e977689fdc7dbf06dc Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 09:31:39 +0000 Subject: [PATCH 311/321] try this dance again --- .gitlab-ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 961965763..2c47affd6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,11 +3,6 @@ # see https://hub.docker.com/_/gcc/ image: gcc -job: - tags: - - openmw - - debian - cache: key: apt-cache paths: From da37585a8e708fd974d99ffd3f01a55ae16fac1f Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 10:15:07 +0000 Subject: [PATCH 312/321] Update .gitlab-ci.yml so that we only build with -j2 --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2c47affd6..18ae73124 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,7 +25,7 @@ build: script: - nproc - mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../ - - make -j4 + - make -j2 - DESTDIR=artifacts make install artifacts: paths: From 3f4d5598a524790b33eaace4be7d5b20335817d0 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 11:55:33 +0000 Subject: [PATCH 313/321] Update README.md to be more generic about OpenMW --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7d92879e2..a6d0cacd5 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ OpenMW [![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/github/openmw/openmw?svg=true)](https://ci.appveyor.com/project/psi29a/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) -OpenMW is a open-source game engine that supports playing Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. +OpenMW is an open-source game engine that supports playing Morrowind by Bethesda Softworks. You need to own the game for OpenMW to play Morrowind. -OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. +OpenMW also comes with OpenMW-CS, a replacement for Bethesda's Construction Set. * Version: 0.44.0 * License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information) From 032768a505e041a627dd455d1973c1b99f32f95d Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 12:38:03 +0000 Subject: [PATCH 314/321] try to use as many cores as possible --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 18ae73124..74bc74ca8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,9 +23,9 @@ before_script: build: stage: build script: - - nproc + - cores_to_use=$((`nproc`-2)); if (( $cores_to_use < 1 )); then cores_to_use=1; fi - mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../ - - make -j2 + - make -j$cores_to_use - DESTDIR=artifacts make install artifacts: paths: From 7d2394273e3a85739a2bc4834937e6c21a633cf3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 13 Jun 2018 14:55:03 +0200 Subject: [PATCH 315/321] added statusbar to search window (Fixes #3276) --- CHANGELOG.md | 1 + apps/opencs/view/tools/searchsubview.cpp | 22 ++++++++++++++++++++++ apps/opencs/view/tools/searchsubview.hpp | 10 ++++++++++ 3 files changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cc66bc61..8a436b4ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts Feature #4345: Add equivalents for the command line commands to Launcher Feature #4444: Per-group KF-animation files support diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 493defa5a..b50e78227 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -8,6 +8,9 @@ #include "../../model/world/idtablebase.hpp" #include "../../model/prefs/state.hpp" +#include "../world/tablebottombox.hpp" +#include "../world/creator.hpp" + #include "reporttable.hpp" #include "searchbox.hpp" @@ -73,6 +76,9 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: layout->addWidget (mTable = new ReportTable (document, id, true), 2); + layout->addWidget (mBottom = + new CSVWorld::TableBottomBox (CSVWorld::NullCreatorFactory(), document, id, this), 0); + QWidget *widget = new QWidget; widget->setLayout (layout); @@ -93,6 +99,12 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: this, SLOT (startSearch (const CSMTools::Search&))); connect (&mSearchBox, SIGNAL (replaceAll()), this, SLOT (replaceAllRequest())); + + connect (document.getReport (id), SIGNAL (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (tableSizeUpdate())); + + connect (document.getReport (id), SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (tableSizeUpdate())); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -101,6 +113,11 @@ void CSVTools::SearchSubView::setEditLock (bool locked) mSearchBox.setEditLock (locked); } +void CSVTools::SearchSubView::setStatusBar (bool show) +{ + mBottom->setStatusBar(show); +} + void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) { mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); @@ -126,3 +143,8 @@ void CSVTools::SearchSubView::replaceAllRequest() { replace (false); } + +void CSVTools::SearchSubView::tableSizeUpdate() +{ + mBottom->tableSizeChanged (mDocument.getReport (getUniversalId())->rowCount(), 0, 0); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index ac0a5a762..d22367722 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -15,6 +15,11 @@ namespace CSMDoc class Document; } +namespace CSVWorld +{ + class TableBottomBox; +} + namespace CSVTools { class ReportTable; @@ -28,6 +33,7 @@ namespace CSVTools CSMDoc::Document& mDocument; CSMTools::Search mSearch; bool mLocked; + CSVWorld::TableBottomBox *mBottom; private: @@ -43,6 +49,8 @@ namespace CSVTools virtual void setEditLock (bool locked); + virtual void setStatusBar (bool show); + private slots: void stateChanged (int state, CSMDoc::Document *document); @@ -52,6 +60,8 @@ namespace CSVTools void replaceRequest(); void replaceAllRequest(); + + void tableSizeUpdate(); }; } From 9bd940e1535667faa87b1c2971c2672c9b10e894 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 13:06:37 +0000 Subject: [PATCH 316/321] Update README.md to indicate that our gitlab pipeline is building --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6d0cacd5..9af9ef976 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/github/openmw/openmw?svg=true)](https://ci.appveyor.com/project/psi29a/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/github/openmw/openmw?svg=true)](https://ci.appveyor.com/project/psi29a/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) [![pipeline status](https://gitlab.com/OpenMW/openmw/badges/master/pipeline.svg)](https://gitlab.com/OpenMW/openmw/commits/master) OpenMW is an open-source game engine that supports playing Morrowind by Bethesda Softworks. You need to own the game for OpenMW to play Morrowind. From 81b78a82e822941f35e73e531c89c975d1241536 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 10:07:02 +0400 Subject: [PATCH 317/321] AI: try to open doors every AI_REACTION_TIME seconds (bug #4454) --- CHANGELOG.md | 1 + apps/openmw/mwclass/container.cpp | 15 +++--- apps/openmw/mwclass/door.cpp | 19 +++---- apps/openmw/mwmechanics/aipackage.cpp | 69 +++++++++++++------------- apps/openmw/mwmechanics/aipackage.hpp | 1 + apps/openmw/mwmechanics/obstacle.cpp | 21 +++++--- apps/openmw/mwmechanics/obstacle.hpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 2 +- 8 files changed, 66 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cc66bc61..90a198bea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Bug #4454: AI opens doors too slow Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts Feature #4345: Add equivalents for the command line commands to Launcher Feature #4444: Per-group KF-animation files support diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b6a46cff8..1d51a7830 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -139,24 +139,21 @@ namespace MWClass const std::string trapActivationSound = "Disarm Trap Fail"; MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - const MWWorld::InventoryStore& invStore = player.getClass().getInventoryStore(player); + MWWorld::InventoryStore& invStore = player.getClass().getInventoryStore(player); bool isLocked = ptr.getCellRef().getLockLevel() > 0; bool isTrapped = !ptr.getCellRef().getTrap().empty(); bool hasKey = false; std::string keyName; - // make key id lowercase - std::string keyId = ptr.getCellRef().getKey(); - Misc::StringUtils::lowerCaseInPlace(keyId); - for (MWWorld::ConstContainerStoreIterator it = invStore.cbegin(); it != invStore.cend(); ++it) + const std::string keyId = ptr.getCellRef().getKey(); + if (!keyId.empty()) { - std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::lowerCaseInPlace(refId); - if (refId == keyId) + MWWorld::Ptr keyPtr = invStore.search(keyId); + if (!keyPtr.isEmpty()) { hasKey = true; - keyName = it->getClass().getName(*it); + keyName = keyPtr.getClass().getName(keyPtr); } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 903ec4958..eba87a47b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -114,7 +114,7 @@ namespace MWClass const std::string lockedSound = "LockedDoor"; const std::string trapActivationSound = "Disarm Trap Fail"; - const MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor); + MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor); bool isLocked = ptr.getCellRef().getLockLevel() > 0; bool isTrapped = !ptr.getCellRef().getTrap().empty(); @@ -135,21 +135,14 @@ namespace MWClass animation->addSpellCastGlow(effect, 1); // 1 second glow to match the time taken for a door opening or closing } - // make key id lowercase - std::string keyId = ptr.getCellRef().getKey(); + const std::string keyId = ptr.getCellRef().getKey(); if (!keyId.empty()) { - Misc::StringUtils::lowerCaseInPlace(keyId); - for (MWWorld::ConstContainerStoreIterator it = invStore.cbegin(); it != invStore.cend(); ++it) + MWWorld::Ptr keyPtr = invStore.search(keyId); + if (!keyPtr.isEmpty()) { - std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::lowerCaseInPlace(refId); - if (refId == keyId) - { - hasKey = true; - keyName = it->getClass().getName(*it); - break; - } + hasKey = true; + keyName = keyPtr.getClass().getName(keyPtr); } } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 6a0f5b013..e6cca0523 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -120,6 +120,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr if (!isDestReached && mTimer > AI_REACTION_TIME) { + if (actor.getClass().isBipedal(actor)) + openDoors(actor); + bool wasShortcutting = mIsShortcutting; bool destInLOS = false; @@ -209,41 +212,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur // first check if obstacle is a door static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); - MWWorld::Ptr door = getNearbyDoor(actor, distance); - if (door != MWWorld::Ptr() && actor.getClass().isBipedal(actor)) + const MWWorld::Ptr door = getNearbyDoor(actor, distance); + if (!door.isEmpty() && actor.getClass().isBipedal(actor)) { - // note: AiWander currently does not open doors - if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) - { - if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) - { - MWBase::Environment::get().getWorld()->activate(door, actor); - return; - } - - std::string keyId = door.getCellRef().getKey(); - if (keyId.empty()) - return; - - bool hasKey = false; - const MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor); - - // make key id lowercase - Misc::StringUtils::lowerCaseInPlace(keyId); - for (MWWorld::ConstContainerStoreIterator it = invStore.cbegin(); it != invStore.cend(); ++it) - { - std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::lowerCaseInPlace(refId); - if (refId == keyId) - { - hasKey = true; - break; - } - } - - if (hasKey) - MWBase::Environment::get().getWorld()->activate(door, actor); - } + openDoors(actor); } else { @@ -251,6 +223,35 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur } } +void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) +{ + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + + const MWWorld::Ptr door = getNearbyDoor(actor, distance); + if (door == MWWorld::Ptr()) + return; + + // note: AiWander currently does not open doors + if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) + { + if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) + { + MWBase::Environment::get().getWorld()->activate(door, actor); + return; + } + + const std::string keyId = door.getCellRef().getKey(); + if (keyId.empty()) + return; + + MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor); + MWWorld::Ptr keyPtr = invStore.search(keyId); + + if (!keyPtr.isEmpty()) + MWBase::Environment::get().getWorld()->activate(door, actor); + } +} + const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell) { const ESM::CellId& id = cell->getCell()->getCellId(); diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 7e8f905ad..2b685accc 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -123,6 +123,7 @@ namespace MWMechanics virtual bool doesPathNeedRecalc(const ESM::Pathgrid::Point& newDest, const MWWorld::CellStore* currentCell); void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos); + void openDoors(const MWWorld::Ptr& actor); const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell); diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3c6f14bfd..0635a5520 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -26,13 +26,13 @@ namespace MWMechanics bool proximityToDoor(const MWWorld::Ptr& actor, float minDist) { - if(getNearbyDoor(actor, minDist)!=MWWorld::Ptr()) - return true; - else + if(getNearbyDoor(actor, minDist).isEmpty()) return false; + else + return true; } - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) + const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) { MWWorld::CellStore *cell = actor.getCell(); @@ -50,6 +50,16 @@ namespace MWMechanics const MWWorld::LiveCellRef& ref = *it; osg::Vec3f doorPos(ref.mData.getPosition().asVec3()); + + // FIXME: cast + const MWWorld::Ptr doorPtr = MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); + + int doorState = doorPtr.getClass().getDoorState(doorPtr); + float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2]; + + if (doorState != 0 || doorRot != 0) + continue; // the door is already opened/opening + doorPos.z() = 0; float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length())); @@ -62,8 +72,7 @@ namespace MWMechanics if ((pos - doorPos).length2() > minDist*minDist) continue; - // FIXME cast - return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching + return doorPtr; // found, stop searching } return MWWorld::Ptr(); // none found diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index f71207346..6a84e0ef9 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -17,7 +17,7 @@ namespace MWMechanics /// Returns door pointer within range. No guarantee is given as to which one /** \return Pointer to the door, or NULL if none exists **/ - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist); + const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist); class ObstacleCheck { diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index dd5d7a853..657d59c59 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -47,7 +47,7 @@ namespace for (typename MWWorld::CellRefList::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { - if (Misc::StringUtils::ciEqual(iter->mBase->mId, id2)) + if (Misc::StringUtils::ciEqual(iter->mBase->mId, id2) && iter->mData.getCount()) { MWWorld::Ptr ptr (&*iter, 0); ptr.setContainerStore (store); From 7ca56ccd291868c4ad11e7c1210252393d935221 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 13 Jun 2018 15:48:24 +0200 Subject: [PATCH 318/321] set search status bar to 'no results' message when search yields no results --- apps/opencs/model/doc/document.cpp | 7 ++++--- apps/opencs/model/doc/document.hpp | 4 +++- apps/opencs/view/tools/searchsubview.cpp | 13 +++++++++++++ apps/opencs/view/tools/searchsubview.hpp | 2 ++ apps/opencs/view/world/tablebottombox.cpp | 16 ++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 3 +++ 6 files changed, 41 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7a825ba39..e45d13aa9 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -320,12 +320,13 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); - connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); + connect (&mTools, SIGNAL (done (int, bool)), this, SIGNAL (operationDone (int, bool))); + connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone2 (int, bool))); connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)), this, SIGNAL (mergeDone (CSMDoc::Document*))); connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); - connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); + connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone2 (int, bool))); connect ( &mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)), @@ -437,7 +438,7 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type) std::cout << message.mMessage << std::endl; } -void CSMDoc::Document::operationDone (int type, bool failed) +void CSMDoc::Document::operationDone2 (int type, bool failed) { if (type==CSMDoc::State_Saving && !failed) mDirty = false; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index d31fd5aca..4c442428e 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -168,13 +168,15 @@ namespace CSMDoc /// document. This signal must be handled to avoid a leak. void mergeDone (CSMDoc::Document *document); + void operationDone (int type, bool failed); + private slots: void modificationStateChanged (bool clean); void reportMessage (const CSMDoc::Message& message, int type); - void operationDone (int type, bool failed); + void operationDone2 (int type, bool failed); void runStateChanged(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index b50e78227..9bada22af 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -3,6 +3,7 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/doc/state.hpp" #include "../../model/tools/search.hpp" #include "../../model/tools/reportmodel.hpp" #include "../../model/world/idtablebase.hpp" @@ -105,6 +106,9 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (document.getReport (id), SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); + + connect (&document, SIGNAL (operationDone (int, bool)), + this, SLOT (operationDone (int, bool))); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -148,3 +152,12 @@ void CSVTools::SearchSubView::tableSizeUpdate() { mBottom->tableSizeChanged (mDocument.getReport (getUniversalId())->rowCount(), 0, 0); } + +void CSVTools::SearchSubView::operationDone (int type, bool failed) +{ + if (type==CSMDoc::State_Searching && !failed && + !mDocument.getReport (getUniversalId())->rowCount()) + { + mBottom->setStatusMessage ("No Results"); + } +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index d22367722..c0f3eac84 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -62,6 +62,8 @@ namespace CSVTools void replaceAllRequest(); void tableSizeUpdate(); + + void operationDone (int type, bool failed); }; } diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index cfde5c694..f6b060a8f 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -28,6 +28,12 @@ void CSVWorld::TableBottomBox::updateStatus() { if (mShowStatusBar) { + if (!mStatusMessage.isEmpty()) + { + mStatus->setText (mStatusMessage); + return; + } + static const char *sLabels[4] = { "record", "deleted", "touched", "selected" }; static const char *sLabelsPlural[4] = { "records", "deleted", "touched", "selected" }; @@ -178,10 +184,17 @@ void CSVWorld::TableBottomBox::currentWidgetChanged(int /*index*/) updateSize(); } +void CSVWorld::TableBottomBox::setStatusMessage (const QString& message) +{ + mStatusMessage = message; + updateStatus(); +} + void CSVWorld::TableBottomBox::selectionSizeChanged (int size) { if (mStatusCount[3]!=size) { + mStatusMessage = ""; mStatusCount[3] = size; updateStatus(); } @@ -210,7 +223,10 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi } if (changed) + { + mStatusMessage = ""; updateStatus(); + } } void CSVWorld::TableBottomBox::positionChanged (int row, int column) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 5402c466e..baa68087b 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -39,6 +39,7 @@ namespace CSVWorld bool mHasPosition; int mRow; int mColumn; + QString mStatusMessage; private: @@ -73,6 +74,8 @@ namespace CSVWorld /// /// \note The BotomBox does not partake in the deletion of records. + void setStatusMessage (const QString& message); + signals: void requestFocus (const std::string& id); From 61c968d5507670f9e3fce874e8abd48f0c819a85 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Jun 2018 12:56:58 +0400 Subject: [PATCH 319/321] Ignore broken items when search for replacement (bug #4453) --- apps/openmw/mwgui/quickkeysmenu.cpp | 88 ++++++++++++++++---------- apps/openmw/mwgui/quickkeysmenu.hpp | 1 + apps/openmw/mwmechanics/actors.cpp | 18 +----- apps/openmw/mwworld/containerstore.cpp | 24 +++++++ apps/openmw/mwworld/containerstore.hpp | 3 + 5 files changed, 85 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2ce9d04e5..08192625f 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -81,6 +81,47 @@ namespace MWGui delete mMagicSelectionDialog; } + void QuickKeysMenu::onOpen() + { + WindowBase::onOpen(); + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + + // Check if quick keys are still valid + for (int i=0; i<10; ++i) + { + ItemWidget* button = mQuickKeyButtons[i]; + int type = mAssigned[i]; + + switch (type) + { + case Type_Unassigned: + case Type_HandToHand: + case Type_Magic: + break; + case Type_Item: + case Type_MagicItem: + { + MWWorld::Ptr item = *button->getUserData(); + // Make sure the item is available and is not broken + if (item.getRefData().getCount() < 1 || + (item.getClass().hasItemHealth(item) && + item.getClass().getItemHealth(item) <= 0)) + { + // Try searching for a compatible replacement + std::string id = item.getCellRef().getRefId(); + + item = store.findReplacement(id); + button->setUserData(MWWorld::Ptr(item)); + break; + } + } + } + } + + } + void QuickKeysMenu::unassign(ItemWidget* key, int index) { key->clearUserStrings(); @@ -122,12 +163,10 @@ namespace MWGui assert(index != -1); mSelectedIndex = index; - { - // open assign dialog - if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(this); - mAssignDialog->setVisible (true); - } + // open assign dialog + if (!mAssignDialog) + mAssignDialog = new QuickKeysMenuAssign(this); + mAssignDialog->setVisible (true); } void QuickKeysMenu::onOkButtonClicked (MyGUI::Widget *sender) @@ -296,21 +335,16 @@ namespace MWGui if (type == Type_Item || type == Type_MagicItem) { MWWorld::Ptr item = *button->getUserData(); - // make sure the item is available - if (item.getRefData ().getCount() < 1) + // Make sure the item is available and is not broken + if (item.getRefData().getCount() < 1 || + (item.getClass().hasItemHealth(item) && + item.getClass().getItemHealth(item) <= 0)) { // Try searching for a compatible replacement std::string id = item.getCellRef().getRefId(); - for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) - { - if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) - { - item = *it; - button->setUserData(MWWorld::Ptr(item)); - break; - } - } + item = store.findReplacement(id); + button->setUserData(MWWorld::Ptr(item)); if (item.getRefData().getCount() < 1) { @@ -498,6 +532,9 @@ namespace MWGui ESM::QuickKeys keys; keys.load(reader); + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + int i=0; for (std::vector::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it) { @@ -519,22 +556,7 @@ namespace MWGui case Type_MagicItem: { // Find the item by id - MWWorld::Ptr player = MWMechanics::getPlayer(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - MWWorld::Ptr item; - for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) - { - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) - { - if (item.isEmpty() || - // Prefer the stack with the lowest remaining uses - !item.getClass().hasItemHealth(*iter) || - iter->getClass().getItemHealth(*iter) < item.getClass().getItemHealth(item)) - { - item = *iter; - } - } - } + MWWorld::Ptr item = store.findReplacement(id); if (item.isEmpty()) unassign(button, i); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 0070aa55b..b5bc60b19 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -34,6 +34,7 @@ namespace MWGui void onAssignMagicItem (MWWorld::Ptr item); void onAssignMagic (const std::string& spellId); void onAssignMagicCancel (); + void onOpen(); void activateQuickKey(int index); void updateActivatedQuickKey(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index de394c446..f1bc6907c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -288,23 +288,9 @@ namespace MWMechanics if (prevItemId.empty()) return; - // Find the item by id - MWWorld::Ptr item; - for (MWWorld::ContainerStoreIterator iter = store.begin(); iter != store.end(); ++iter) - { - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), prevItemId)) - { - if (item.isEmpty() || - // Prefer the stack with the lowest remaining uses - !item.getClass().hasItemHealth(*iter) || - iter->getClass().getItemHealth(*iter) < item.getClass().getItemHealth(item)) - { - item = *iter; - } - } - } - + // Find previous item (or its replacement) by id. // we should equip previous item only if expired bound item was equipped. + MWWorld::Ptr item = store.findReplacement(prevItemId); if (item.isEmpty() || !wasEquipped) return; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index dd5d7a853..c92d51701 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -675,6 +675,30 @@ int MWWorld::ContainerStore::getType (const ConstPtr& ptr) "Object '" + ptr.getCellRef().getRefId() + "' of type " + ptr.getTypeName() + " can not be placed into a container"); } +MWWorld::Ptr MWWorld::ContainerStore::findReplacement(const std::string& id) +{ + MWWorld::Ptr item; + int itemHealth = 1; + for (MWWorld::ContainerStoreIterator iter = begin(); iter != end(); ++iter) + { + int iterHealth = iter->getClass().hasItemHealth(*iter) ? iter->getClass().getItemHealth(*iter) : 1; + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) + { + // Prefer the stack with the lowest remaining uses + // Try to get item with zero durability only if there are no other items found + if (item.isEmpty() || + (iterHealth > 0 && iterHealth < itemHealth) || + (itemHealth <= 0 && iterHealth > 0)) + { + item = *iter; + itemHealth = iterHealth; + } + } + } + + return item; +} + MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) { { diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index dbb82cbda..b67eb6552 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -198,6 +198,9 @@ namespace MWWorld ///< This function throws an exception, if ptr does not point to an object, that can be /// put into a container. + Ptr findReplacement(const std::string& id); + ///< Returns replacement for object with given id. Prefer used items (with low durability left). + Ptr search (const std::string& id); virtual void writeState (ESM::InventoryState& state) const; From 48d74a8781b8ba1f50fce9bc0eeb1cf09c34caa6 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Jun 2018 15:34:13 +0000 Subject: [PATCH 320/321] Disable testing for now, not yet necessary. --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 74bc74ca8..9f5442ae4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,8 +35,8 @@ build: paths: - "*.o" -# run tests using the binary built before -test: - stage: test - script: - - ls +# TODO: run tests using the binary built before +#test: +# stage: test +# script: +# - ls From e814843cdbf82d501f9fb64caa8a91d34f9adf30 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Jun 2018 22:28:34 +0400 Subject: [PATCH 321/321] Add missing changelog entries --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7871998a3..dfea001f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Bug #2222: Fatigue's effect on selling price is backwards Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped Bug #2835: Player able to slowly move when overencumbered + Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y Bug #3374: Touch spells not hitting kwama foragers Bug #3591: Angled hit distance too low Bug #3629: DB assassin attack never triggers creature spawning @@ -20,11 +21,14 @@ Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4327: Missing animations during spell/weapon stance switching Bug #4368: Settings window ok button doesn't have key focus by default + Bug #4393: NPCs walk back to where they were after using ResetActors Bug #4419: MRK NiStringExtraData is handled incorrectly Bug #4426: RotateWorld behavior is incorrect Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Bug #4451: Script fails to compile when using "Begin, [ScriptName]" syntax + Bug #4453: Quick keys behaviour is invalid for equipment Bug #4454: AI opens doors too slow Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts