From 0153b54c3fac2824ab17c081b6f6a99ebe0e575e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Oct 2017 14:08:08 +0200 Subject: [PATCH 01/67] 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 b47678e7d..8d9e4c9b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 42) +set(OPENMW_VERSION_MINOR 43) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index aa6ae47b4..a6d68dd18 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.42.0 +* Version: 0.43.0 * License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From dcd08e63294e9b474f92782627765e4c0494c674 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Oct 2017 14:28:21 +0200 Subject: [PATCH 02/67] updated changelog --- CHANGELOG.md | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b390169c6..ac2a5472e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,140 @@ +0.43.0 +------ + + Bug #815: Different settings cause inconsistent underwater visibility + Bug #1452: autosave is not executed when waiting + Bug #1555: Closing containers with spacebar doesn't work after touching an item + Bug #1692: Can't close container when item is "held" + Bug #2405: Maximum distance for guards attacking hostile creatures is incorrect + Bug #2445: Spellcasting can be interrupted + Bug #2489: Keeping map open not persisted between saves + Bug #2594: 1st person view uses wrong body texture with Better bodies + Bug #2628: enablestatreviewmenu command doen't read race, class and sign values from current game + Bug #2639: Attacking flag isn't reset upon reloading + Bug #2698: Snow and rain VFX move with the player + Bug #2704: Some creature swim animations not being used + Bug #2789: Potential risk of misunderstanding using the colored "owned" crosshair feature + Bug #3045: Settings containing '#' cannot be loaded + Bug #3097: Drop() doesn't work when an item is held (with the mouse) + Bug #3110: GetDetected doesn't work without a reference + Bug #3126: Framerate nosedives when adjusting dialogue window size + Bug #3243: Ampersand in configuration files isn't escaped automatically + Bug #3365: Wrong water reflection along banks + Bug #3441: Golden saint always dispelling soul trap / spell priority issue + Bug #3528: Disposing of corpses breaks quests + Bug #3531: No FPS limit when playing bink videos even though "framerate limit" is set in settings.cfg + Bug #3647: Multi-effect spells play audio louder than in Vanilla + Bug #3656: NPCs forget where their place in the world is + Bug #3665: Music transitions are too abrupt + Bug #3679: Spell cast effect should disappear after using rest command + Bug #3684: Merchants do not restock empty soul gems if they acquire filled ones. + Bug #3694: Wrong magicka bonus applied on character creation + Bug #3706: Guards don't try to arrest the player if attacked + Bug #3709: Editor: Camera is not positioned correctly on mode switches related to orbital mode + Bug #3720: Death counter not cleaned of non-existing IDs when loading a game + Bug #3744: "Greater/lesser or equal" operators are not parsed when their signs are swapped + Bug #3749: Yagrum Bagarn moves to different position on encountering + Bug #3766: DisableLevitation does not remove visuals of preexisting effect + Bug #3787: Script commands in result box for voiced dialogue are ignored + Bug #3793: OpenMW tries to animate animated references even when they are disabled + Bug #3794: Default sound buffer size is too small for mods + Bug #3796: Mod 'Undress for me' doesn't work: NPCs re-equip everything + Bug #3798: tgm command behaviour differs from vanilla + Bug #3804: [Mod] Animated Morrowind: some animations do not loop correctly + Bug #3805: Slight enchant miscalculation + Bug #3826: Rendering problems with an image in a letter + Bug #3833: [Mod] Windows Glow: windows textures are much darker than in original game + Bug #3835: Bodyparts with multiple NiTriShapes are not handled correctly + Bug #3839: InventoryStore::purgeEffect() removes only first effect with argument ID + Bug #3843: Wrong jumping fatigue loss calculations + Bug #3850: Boethiah's voice is distorted underwater + Bug #3851: NPCs and player say things while underwater + Bug #3864: Crash when exiting to Khartag point from Ilunibi + Bug #3878: Swapping soul gems while enchanting allows constant effect enchantments using any soul gem + Bug #3879: Dialogue option: Go to jail, persists beyond quickload + Bug #3891: Journal displays empty entries + Bug #3892: Empty space before dialogue entry display + Bug #3898: (mod) PositionCell in dialogue results closes dialogue window + Bug #3906: "Could not find Data Files location" dialog can appear multiple times + Bug #3908: [Wizard] User gets stuck if they cancel out of installing from a CD + Bug #3909: Morrowind Content Language dropdown is the only element on the right half of the Settings window + Bug #3910: Launcher window can be resized so that it cuts off the scroll + Bug #3915: NC text key on nifs doesn't work + Bug #3919: Closing inventory while cursor hovers over spell (or other magic menu item) produces left click sound + Bug #3922: Combat AI should avoid enemy hits when casts Self-ranged spells + Bug #3934: [macOS] Copy/Paste from system clipboard uses Control key instead of Command key + Bug #3935: Incorrect attack strength for AI actors + Bug #3937: Combat AI: enchanted weapons have too high rating + Bug #3942: UI sounds are distorted underwater + Bug #3943: CPU/GPU usage should stop when the game is minimised + Bug #3944: Attempting to sell stolen items back to their owner does not remove them from your inventory + Bug #3955: Player's avatar rendering issues + Bug #3956: EditEffectDialog: Cancel button does not update a Range button and an Area slider properly + Bug #3957: Weird bodypart rendering if a node has reserved name + Bug #3960: Clothes with high cost (> 32768) are not handled properly + Bug #3963: When on edge of being burdened the condition doesn't lower as you run. + Bug #3971: Editor: Incorrect colour field in cell table + Bug #3974: Journal page turning doesn't produce sounds + Bug #3978: Instant opening and closing happens when using a Controller with Menus/Containers + Bug #3981: Lagging when spells are cast, especially noticeable on new landmasses such as Tamriel Rebuilt + Bug #3982: Down sounds instead of Up ones are played when trading + Bug #3987: NPCs attack after some taunting with no "Goodbye" + Bug #3991: Journal can still be opened at main menu + Bug #3995: Dispel cancels every temporary magic effect + Bug #4002: Build broken on OpenBSD with clang + Bug #4003: Reduce Render Area of Inventory Doll to Fit Within Border + Bug #4004: Manis Virmaulese attacks without saying anything + Bug #4010: AiWander: "return to the spawn position" feature does not work properly + Bug #4016: Closing menus with spacebar will still send certain assigned actions through afterwards + Bug #4017: GetPCRunning and GetPCSneaking should check that the PC is actually moving + Bug #4024: Poor music track distribution + Bug #4025: Custom spell with copy-pasted name always sorts to top of spell list + Bug #4027: Editor: OpenMW-CS misreports its own name as "OpenCS", under Mac OS + Bug #4033: Archers don't attack if the arrows have run out and there is no other weapon + Bug #4037: Editor: New greetings do not work in-game. + Bug #4049: Reloading a saved game while falling prevents damage + Bug #4056: Draw animation should not be played when player equips a new weapon + Bug #4074: Editor: Merging of LAND/LTEX records + Bug #4076: Disposition bar is not updated when "goodbye" selected in dialogue + Bug #4079: Alchemy skill increases do not take effect until next batch + Bug #4093: GetResistFire, getResistFrost and getResistShock doesn't work as in vanilla + Bug #4094: Level-up messages for levels past 20 are hardcoded not to be used + Bug #4095: Error in framelistener when take all items from a dead corpse + Bug #4096: Messagebox with the "%0.f" format should use 0 digit precision + Bug #4104: Cycling through weapons does not skip broken ones + Bug #4105: birthsign generation menu does not show full details + Bug #4107: Editor: Left pane in Preferences window is too narrow + Bug #4112: Inventory sort order is inconsistent + Bug #4113: 'Resolution not supported in fullscreen' message is inconvenient + Bug #4131: Pickpocketing behaviour is different from vanilla + Bug #4155: NPCs don't equip a second ring in some cases + Bug #4156: Snow doesn't create water ripples + Bug #4165: NPCs autoequip new clothing with the same price + Feature #452: Rain-induced water ripples + Feature #824: Fading for doors and teleport commands + Feature #933: Editor: LTEX record table + Feature #936: Editor: LAND record table + Feature #1374: AI: Resurface to breathe + Feature #2320: ess-Importer: convert projectiles + Feature #2509: Editor: highlighting occurrences of a word in a script + Feature #2748: Editor: Should use one resource manager per document + Feature #2834: Have openMW's UI remember what menu items were 'pinned' across boots. + Feature #2923: Option to show the damage of the arrows through tooltip. + Feature #3099: Disabling inventory while dragging an item forces you to drop it + Feature #3274: Editor: Script Editor - Shortcuts and context menu options for commenting code out and uncommenting code respectively + Feature #3275: Editor: User Settings- Add an option to reset settings to their default status (per category / all) + Feature #3400: Add keyboard shortcuts for menus + Feature #3492: Show success rate while enchanting + Feature #3530: Editor: Reload data files + Feature #3682: Editor: Default key binding reset + Feature #3921: Combat AI: aggro priorities + Feature #3941: Allow starting at an unnamed exterior cell with --start + Feature #3952: Add Visual Studio 2017 support + Feature #3953: Combat AI: use "WhenUsed" enchantments + Feature #4082: Leave the stack of ingredients or potions grabbed after using an ingredient/potion + Task #2258: Windows installer: launch OpenMW tickbox + Task #4152: The Windows CI script is moving files around that CMake should be dealing with + 0.42.0 ------ From 2e6cf53fddd29a9db02f926a384ddd0069aa12d8 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 24 Oct 2017 22:57:35 +0200 Subject: [PATCH 03/67] Update CPack configuration for NSIS packages Now grabs generated files from the configuration directory where they're generated --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d9e4c9b2..8d0e126c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -443,15 +443,18 @@ if(WIN32) FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug) INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg" CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg" CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" - "${OpenMW_BINARY_DIR}/settings-default.cfg" - "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/settings-default.cfg" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/settings-default.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) if(BUILD_MYGUI_PLUGIN) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug) @@ -463,7 +466,9 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF() - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/resources" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/resources" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) + FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*") FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug) From 3e51c9e6b3356bebdead4230933965179c1e294b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 24 Oct 2017 23:23:55 +0200 Subject: [PATCH 04/67] Missed the OpenCS config file --- apps/opencs/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 777bb2d52..b9279bf91 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -252,7 +252,8 @@ endif() if (WIN32) target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw-cs.cfg" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw-cs.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) endif() if (MSVC) From 04af200ae8a6ebf19542f18753abcfc21763d0fe Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 28 Oct 2017 13:37:41 +0200 Subject: [PATCH 05/67] Downgrade MyGUI to 3.2.2 for Windows builds --- CI/before_script.msvc.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 39cb37bed..9f6051863 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -320,9 +320,9 @@ if [ -z $SKIP_DOWNLOAD ]; then "ffmpeg-3.2.4-dev-win${BITS}.zip" # MyGUI - download "MyGUI 3.2.3-git" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" + download "MyGUI 3.2.2" \ + "http://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 download "OpenAL-Soft 1.17.2" \ @@ -474,20 +474,20 @@ cd $DEPS echo # MyGUI -printf "MyGUI 3.2.3-git... " +printf "MyGUI 3.2.2... " { cd $DEPS_INSTALL if [ -d MyGUI ] && \ grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ - grep "MYGUI_VERSION_PATCH 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null + grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf MyGUI - eval 7z x -y "${DEPS}/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}" MyGUI + eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP + mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI fi export MYGUI_HOME="$(real_pwd)/MyGUI" From 41dc82abadfe785b57c08c2e2a3e68edd67a308f Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Sat, 28 Oct 2017 17:05:30 +0100 Subject: [PATCH 06/67] Update Links to Documentation in settings.cfg files (#1523) * Update settings-default.cfg * Update settings.cpp --- components/settings/settings.cpp | 2 +- files/settings-default.cfg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index e93642ee2..2e7b5a8ae 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 << "# https://wiki.openmw.org/index.php?title=Settings" << std::endl; + ostream << "# http://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/files/settings-default.cfg b/files/settings-default.cfg index aec667a9c..253883402 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -6,9 +6,9 @@ # ranges of recommended values. For detailed explanations of the # significance of each setting, interaction with other settings, hard # limits on value ranges and more information in general, please read -# the detailed documentation at the OpenMW Wiki page: +# the detailed documentation at: # -# https://wiki.openmw.org/index.php?title=Settings +# http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html # [Camera] From 492b99b008e677cee28181f88e756f3fb7481b24 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 7 Nov 2017 00:41:27 -0500 Subject: [PATCH 07/67] Transparent object markers --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/view/render/object.cpp | 38 +++++++++++++++++++++++++----- apps/opencs/view/render/object.hpp | 7 ++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 1f84c5a87..2a40c4e18 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -191,6 +191,7 @@ void CSMPrefs::State::declare() setTooltip ("Acceleration factor during drag operations while holding down shift"). setRange (0.001, 100.0); declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1); + declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1); declareCategory ("Tooltips"); declareBool ("scene", "Show Tooltips in 3D scenes", true); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 522057097..d725f5dc9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -285,15 +286,15 @@ osg::ref_ptr CSVRender::Object::makeMoveOrScaleMarker (int axis) for (int i=0; i<8; ++i) colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, - axis==2 ? 1.0f : 0.2f, 1.0f)); + axis==2 ? 1.0f : 0.2f, mMarkerTransparency)); for (int i=8; i<8+4+1; ++i) colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f, - axis==2 ? 1.0f : 0.0f, 1.0f)); + axis==2 ? 1.0f : 0.0f, mMarkerTransparency)); geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); - geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + setupCommonMarkerState(geometry); osg::ref_ptr geode (new osg::Geode); geode->addDrawable (geometry); @@ -350,7 +351,11 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis); } - colors->at(0) = osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, axis==2 ? 1.0f : 0.2f, 1.0f); + colors->at(0) = osg::Vec4f ( + axis==0 ? 1.0f : 0.2f, + axis==1 ? 1.0f : 0.2f, + axis==2 ? 1.0f : 0.2f, + mMarkerTransparency); for (size_t i = 0; i < SegmentCount; ++i) { @@ -374,7 +379,7 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) geometry->setColorArray(colors, osg::Array::BIND_OVERALL); geometry->addPrimitiveSet(primitives); - geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + setupCommonMarkerState(geometry); osg::ref_ptr geode = new osg::Geode(); geode->addDrawable (geometry); @@ -382,6 +387,21 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) return geode; } +void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) +{ + const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1; + + osg::ref_ptr state = geometry->getOrCreateStateSet(); + state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + state->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::ref_ptr depth(new osg::Depth); + depth->setWriteMask(false); + state->setAttributeAndModes(depth, osg::StateAttribute::ON); + + state->setRenderBinDetails(RenderBin, "RenderBin"); +} + osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis) { switch (axis) @@ -399,7 +419,7 @@ osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) : mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero), - mScaleOverride (1), mOverrideFlags (0), mSubMode (-1) + mScaleOverride (1), mOverrideFlags (0), mSubMode (-1), mMarkerTransparency(0.5f) { mRootNode = new osg::PositionAttitudeTransform; @@ -629,6 +649,12 @@ void CSVRender::Object::setScale (float scale) adjustTransform(); } +void CSVRender::Object::setMarkerTransparency(float value) +{ + mMarkerTransparency = value; + updateMarker(); +} + void CSVRender::Object::apply (CSMWorld::CommandMacro& commands) { const CSMWorld::RefCollection& collection = mData.getReferences(); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e14697e62..3e54093d3 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -96,6 +97,7 @@ namespace CSVRender int mOverrideFlags; osg::ref_ptr mMarker[3]; int mSubMode; + float mMarkerTransparency; /// Not implemented Object (const Object&); @@ -121,6 +123,9 @@ namespace CSVRender osg::ref_ptr makeMoveOrScaleMarker (int axis); osg::ref_ptr makeRotateMarker (int axis); + /// Sets up a stateset with properties common to all marker types. + void setupCommonMarkerState(osg::ref_ptr geometry); + osg::Vec3f getMarkerPosition (float x, float y, float z, int axis); public: @@ -179,6 +184,8 @@ namespace CSVRender /// Set override scale void setScale (float scale); + void setMarkerTransparency(float value); + /// Apply override changes via command and end edit mode void apply (CSMWorld::CommandMacro& commands); From 41ecbdbe6c47b54c34854d59bbe8f0fc5c936444 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 00:03:02 +0100 Subject: [PATCH 08/67] Add missing WaitDialog::clear() (Fixes #4196) --- apps/openmw/mwgui/waitdialog.cpp | 6 ++++++ apps/openmw/mwgui/waitdialog.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a7ad687cb..61febf315 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -96,6 +96,12 @@ namespace MWGui return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } + void WaitDialog::clear() + { + mSleeping = false; + mTimeAdvancer.stop(); + } + void WaitDialog::onOpen() { if (mTimeAdvancer.isRunning()) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index eb6a55640..2aecb002f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -33,6 +33,8 @@ namespace MWGui virtual bool exit(); + virtual void clear(); + void onFrame(float dt); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } From 197ea9564663006100606b74f9c87a499a7a6ba4 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 9 Nov 2017 13:04:46 -0500 Subject: [PATCH 09/67] Prevent arrows for move/scale markers from intersecting. --- apps/opencs/view/render/object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index d725f5dc9..0ed7830f3 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -221,7 +221,7 @@ osg::ref_ptr CSVRender::Object::makeMoveOrScaleMarker (int axis) for (int i=0; i<2; ++i) { - float length = i ? shaftLength : 0; + float length = i ? shaftLength : MarkerShaftWidth; vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis)); vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis)); From de214db8d46c97349fa81d01bd3489ac04d5ae51 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 9 Nov 2017 13:45:32 -0500 Subject: [PATCH 10/67] Use configured transparency. --- apps/opencs/view/render/object.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 0ed7830f3..a3ecbadeb 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -22,6 +22,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/commandmacro.hpp" #include "../../model/world/cellcoordinates.hpp" +#include "../../model/prefs/state.hpp" #include #include @@ -473,6 +474,7 @@ void CSVRender::Object::setSelected(bool selected) else mRootNode->addChild(mBaseNode); + mMarkerTransparency = CSMPrefs::get()["3D Scene Input"]["object-marker-alpha"].toDouble(); updateMarker(); } From 556117f6e6b6e51d89cc0681abcb45bbaed3497b Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 10 Nov 2017 01:56:06 -0500 Subject: [PATCH 11/67] Update marker transparency when changed. --- apps/opencs/view/render/worldspacewidget.cpp | 14 ++++++++++++++ apps/opencs/view/render/worldspacewidget.hpp | 1 + 2 files changed, 15 insertions(+) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 325fa5f6d..a80a61a79 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -51,6 +51,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg , mToolTipPos (-1, -1) , mShowToolTips(false) , mToolTipDelay(0) + , mInConstructor(true) { setAcceptDrops(true); @@ -114,6 +115,8 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this); connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag())); + + mInConstructor = false; } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -128,6 +131,17 @@ void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setti mDragWheelFactor = setting->toDouble(); else if (*setting=="3D Scene Input/drag-shift-factor") mDragShiftFactor = setting->toDouble(); + else if (*setting=="3D Scene Input/object-marker-alpha" && !mInConstructor) + { + float alpha = setting->toDouble(); + // getSelection is virtual, thus this can not be called from the constructor + auto selection = getSelection(Mask_Reference); + for (osg::ref_ptr tag : selection) + { + if (auto objTag = dynamic_cast(tag.get())) + objTag->mObject->setMarkerTransparency(alpha); + } + } else if (*setting=="Tooltips/scene-delay") mToolTipDelay = setting->toInt(); else if (*setting=="Tooltips/scene") diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 08b97e1be..9160ca47e 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -65,6 +65,7 @@ namespace CSVRender QPoint mToolTipPos; bool mShowToolTips; int mToolTipDelay; + bool mInConstructor; public: From 1cd539bad2724df2815ad6df0ed37e3fa29c1ee2 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 10 Nov 2017 02:06:06 -0500 Subject: [PATCH 12/67] Fix render order for markers --- apps/opencs/view/render/object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index a3ecbadeb..c5da094e6 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -390,7 +390,7 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) { - const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1; + const int RenderBin = osg::StateSet::TRANSPARENT_BIN; osg::ref_ptr state = geometry->getOrCreateStateSet(); state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); From 9943bd4d745080ef20caf6fb9c12e0f282203b21 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 11 Nov 2017 12:31:18 +0400 Subject: [PATCH 13/67] AiWander fast forwarding improvements (bug #3638) --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 + apps/openmw/mwmechanics/actors.cpp | 11 +++ apps/openmw/mwmechanics/actors.hpp | 12 ++-- apps/openmw/mwmechanics/aiwander.cpp | 70 +++++++++++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 + apps/openmw/mwmechanics/pathgrid.cpp | 10 +++ apps/openmw/mwmechanics/pathgrid.hpp | 3 + apps/openmw/mwworld/cellstore.cpp | 5 ++ apps/openmw/mwworld/cellstore.hpp | 1 + 11 files changed, 115 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 398439ad8..8ae2ae367 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -191,6 +191,9 @@ namespace MWBase virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects) = 0; virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) = 0; + /// Check if there are actors in selected range + virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius) = 0; + ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a144911c5..a47693a78 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1621,6 +1621,17 @@ namespace MWMechanics } } + bool Actors::isAnyObjectInRange(const osg::Vec3f& position, float radius) + { + for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) + { + if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius) + return true; + } + + return false; + } + std::list Actors::getActorsSidingWith(const MWWorld::Ptr& actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index e433434a5..7ed89d0e4 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -115,15 +115,17 @@ namespace MWMechanics bool isRunning(const MWWorld::Ptr& ptr); bool isSneaking(const MWWorld::Ptr& ptr); - void forceStateUpdate(const MWWorld::Ptr &ptr); + void forceStateUpdate(const MWWorld::Ptr &ptr); - bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); - void skipAnimation(const MWWorld::Ptr& ptr); - bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); - void persistAnimationStates(); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); + void skipAnimation(const MWWorld::Ptr& ptr); + bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); + void persistAnimationStates(); void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); + bool isAnyObjectInRange(const osg::Vec3f& position, float radius); + void cleanupSummonedCreature (CreatureStats& casterStats, int creatureActorId); ///Returns the list of actors which are siding with the given actor in fights diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 255874d88..343e03f6c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -799,20 +799,80 @@ namespace MWMechanics int index = Misc::Rng::rollDice(storage.mAllowedNodes.size()); ESM::Pathgrid::Point dest = storage.mAllowedNodes[index]; - state.moveIn(new AiWanderStorage()); + ESM::Pathgrid::Point worldDest = dest; + ToWorldCoordinates(worldDest, actor.getCell()->getCell()); + + bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60); + + // add offset only if the selected pathgrid is occupied by another actor + if (isPathGridOccupied) + { + ESM::Pathgrid::PointList points; + getNeighbouringNodes(dest, actor.getCell(), points); + + // there are no neighbouring nodes, nowhere to move + if (points.empty()) + return; + + int initialSize = points.size(); + bool isOccupied = false; + // AI will try to move the NPC towards every neighboring node until suitable place will be found + for (int i = 0; i < initialSize; i++) + { + int randomIndex = Misc::Rng::rollDice(points.size()); + ESM::Pathgrid::Point connDest = points[randomIndex]; + + // add an offset towards random neighboring node + osg::Vec3f dir = PathFinder::MakeOsgVec3(connDest) - PathFinder::MakeOsgVec3(dest); + float length = dir.length(); + dir.normalize(); + + for (int j = 1; j <= 3; j++) + { + // move for 5-15% towards random neighboring node + dest = PathFinder::MakePathgridPoint(PathFinder::MakeOsgVec3(dest) + dir * (j * 5 * length / 100.f)); + worldDest = dest; + ToWorldCoordinates(worldDest, actor.getCell()->getCell()); + + isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60); + + if (!isOccupied) + break; + } + + if (!isOccupied) + break; + + // Will try an another neighboring node + points.erase(points.begin()+randomIndex); + } + + // there is no free space, nowhere to move + if (isOccupied) + return; + } + + // 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.mX += OffsetToPreventOvercrowding(); - dest.mY += OffsetToPreventOvercrowding(); ToWorldCoordinates(dest, actor.getCell()->getCell()); + state.moveIn(new AiWanderStorage()); + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } - int AiWander::OffsetToPreventOvercrowding() + void AiWander::getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) { - return static_cast(20 * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*currentCell->getCell()); + + int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest)); + + currentCell->getNeighbouringPoints(index, points); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 01d889e2f..6266a7708 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -104,6 +104,8 @@ namespace MWMechanics bool mHasDestination; osg::Vec3f mDestination; + void getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points); + void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage); void trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dfbcf0ea2..0ab6f0f42 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1529,6 +1529,11 @@ namespace MWMechanics mActors.getObjectsInRange(position, radius, objects); } + bool MechanicsManager::isAnyActorInRange(const osg::Vec3f &position, float radius) + { + return mActors.isAnyObjectInRange(position, radius); + } + std::list MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor) { return mActors.getActorsSidingWith(actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ee4cf28af..df7c35d97 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -158,6 +158,9 @@ namespace MWMechanics virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects); virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); + /// Check if there are actors in selected range + virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius); + virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor); virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index c557beadd..85264095c 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -214,6 +214,16 @@ namespace MWMechanics return (mGraph[start].componentId == mGraph[end].componentId); } + void PathgridGraph::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const + { + for(int i = 0; i < static_cast (mGraph[index].edges.size()); i++) + { + int neighbourIndex = mGraph[index].edges[i].index; + if (neighbourIndex != index) + nodes.push_back(mPathgrid->mPoints[neighbourIndex]); + } + } + /* * NOTE: Based on buildPath2(), please check git history if interested * Should consider using a 3rd party library version (e.g. boost) diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index d90cb47cd..84b84652c 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -28,6 +28,9 @@ namespace MWMechanics // from start point) both start and end are pathgrid point indexes bool isPointConnected(const int start, const int end) const; + // get neighbouring nodes for index node and put them to "nodes" vector + void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const; + // the input parameters are pathgrid point indexes // the output list is in local (internal cells) or world (external // cells) coordinates diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index b4f260a25..f6e70dc94 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -942,6 +942,11 @@ namespace MWWorld return mPathgridGraph.isPointConnected(start, end); } + void CellStore::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const + { + return mPathgridGraph.getNeighbouringPoints(index, nodes); + } + std::list CellStore::aStarSearch(const int start, const int end) const { return mPathgridGraph.aStarSearch(start, end); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 4452ad889..2f6277aec 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -377,6 +377,7 @@ namespace MWWorld ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. bool isPointConnected(const int start, const int end) const; + void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const; std::list aStarSearch(const int start, const int end) const; From b7eda61f7a437bfd503be6227cec922be8c4e769 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:47:14 +0100 Subject: [PATCH 14/67] Fix overlapping widgets in trade window layout (Fixes #4205) --- files/mygui/openmw_trade_window.layout | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index d1f31c475..ebfe9b30f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -53,18 +53,17 @@ - - - - - + + + + - + - + From 3b9e1e8c1b8611f1a5d239734da3d8bb39a5265b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:48:11 +0100 Subject: [PATCH 15/67] Make movement keys not function in text input mode --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a5bb93b6c..5aa795c10 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -176,6 +176,8 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + if (SDL_IsTextInputActive()) + return; MyGUI::KeyCode key; switch (action) { From dc016059c381ecd4b277858f704b835b7240624d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:54:04 +0000 Subject: [PATCH 16/67] Disable Activate key when textinput is active (Bug #4151) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5aa795c10..9ef5033f0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1113,7 +1113,10 @@ namespace MWInput void InputManager::activate() { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + { + if (!SDL_IsTextInputActive()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + } else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From 92aaff3b788cd565d98cb40f25b125e495e6ca09 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Sun, 5 Nov 2017 21:40:35 +0100 Subject: [PATCH 17/67] Fixed escaping @ in boost program options filter --- components/files/escape.cpp | 3 ++- components/files/escape.hpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index f28870c70..3c3d04d51 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -27,7 +27,8 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char)escape_hash_filter::sEscape, 1)); + auto format = std::string(1, (char)escape_hash_filter::sEscape); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 2017c2ed2..64410f3ab 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -78,6 +78,12 @@ namespace Files mFinishLine = true; } } + else if (character == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + record = false; + } else if (mPrevious == sEscape) { mNext.push(sEscape); From 09aac227825d88470bf3cf3562d32bc2e61bbe08 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 22:16:59 +0100 Subject: [PATCH 18/67] Added StringUtil::replaceAll() --- components/misc/stringops.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..12c222036 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -2,6 +2,7 @@ #define MISC_STRINGOPS_H #include +#include #include #include @@ -138,6 +139,35 @@ public: return notFound; } + + /** @brief Replaces all occurrences of a string in another string. + * + * @param str The string to operate on. + * @param what The string to replace. + * @param with The replacement string. + * @param what_len The length of the string to replace. + * @param with_len The length of the replacement string. + * + * @return A reference to the string passed in @p str. + */ + static std::string &replaceAll(std::string &str, const char *what, const char *with, + std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + { + if (what_len == std::string::npos) + what_len = strlen(what); + + if (with_len == std::string::npos) + with_len = strlen(with); + + std::size_t found; + std::size_t offset = 0; + while((found = str.find(what, offset, what_len)) != std::string::npos) + { + str.replace(found, what_len, with, with_len); + offset = found + with_len; + } + return str; + } }; } From 52b3507a2b63a45b96b802106b8ee89b2740de41 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:10:58 +0100 Subject: [PATCH 19/67] Removed escape_hash_filter::mPrevious, removed usage of boost::replace_all --- components/files/escape.cpp | 15 ++++++++++----- components/files/escape.hpp | 11 ----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index 3c3d04d51..93ae9b885 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -1,6 +1,6 @@ #include "escape.hpp" -#include +#include namespace Files { @@ -8,7 +8,7 @@ namespace Files const int escape_hash_filter::sEscapeIdentifier = 'a'; const int escape_hash_filter::sHashIdentifier = 'h'; - escape_hash_filter::escape_hash_filter() : mNext(), mPrevious(), mSeenNonWhitespace(false), mFinishLine(false) + escape_hash_filter::escape_hash_filter() : mSeenNonWhitespace(false), mFinishLine(false) { } @@ -26,9 +26,14 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { - std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - auto format = std::string(1, (char)escape_hash_filter::sEscape); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); + std::string temp = str; + + static const char hash[] = { escape_hash_filter::sEscape, escape_hash_filter::sHashIdentifier }; + Misc::StringUtils::replaceAll(temp, hash, "#", 2, 1); + + static const char escape[] = { escape_hash_filter::sEscape, escape_hash_filter::sEscapeIdentifier }; + Misc::StringUtils::replaceAll(temp, escape, "@", 2, 1); + return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 64410f3ab..d01bd8d98 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -30,7 +30,6 @@ namespace Files private: std::queue mNext; - int mPrevious; bool mSeenNonWhitespace; bool mFinishLine; @@ -42,11 +41,9 @@ namespace Files if (mNext.empty()) { int character = boost::iostreams::get(src); - bool record = true; if (character == boost::iostreams::WOULD_BLOCK) { mNext.push(character); - record = false; } else if (character == EOF) { @@ -79,12 +76,6 @@ namespace Files } } else if (character == sEscape) - { - mNext.push(sEscape); - mNext.push(sEscapeIdentifier); - record = false; - } - else if (mPrevious == sEscape) { mNext.push(sEscape); mNext.push(sEscapeIdentifier); @@ -95,8 +86,6 @@ namespace Files } if (!mSeenNonWhitespace && !isspace(character)) mSeenNonWhitespace = true; - if (record) - mPrevious = character; } int retval = mNext.front(); mNext.pop(); From 93e9df15c999ddb42fb2f9650cced5beed162310 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:20:10 +0100 Subject: [PATCH 20/67] Fixed parameter naming --- components/misc/stringops.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 12c222036..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -145,26 +145,26 @@ public: * @param str The string to operate on. * @param what The string to replace. * @param with The replacement string. - * @param what_len The length of the string to replace. - * @param with_len The length of the replacement string. + * @param whatLen The length of the string to replace. + * @param withLen The length of the replacement string. * * @return A reference to the string passed in @p str. */ static std::string &replaceAll(std::string &str, const char *what, const char *with, - std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) { - if (what_len == std::string::npos) - what_len = strlen(what); + if (whatLen == std::string::npos) + whatLen = strlen(what); - if (with_len == std::string::npos) - with_len = strlen(with); + if (withLen == std::string::npos) + withLen = strlen(with); std::size_t found; std::size_t offset = 0; - while((found = str.find(what, offset, what_len)) != std::string::npos) + while((found = str.find(what, offset, whatLen)) != std::string::npos) { - str.replace(found, what_len, with, with_len); - offset = found + with_len; + str.replace(found, whatLen, with, withLen); + offset = found + withLen; } return str; } From 35d68f038d4dc7d3255e1b3feebdeba90a7249a4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:29:50 +0100 Subject: [PATCH 21/67] Update dialogue topics list after result script is run Regression from 0.42. --- apps/openmw/mwgui/dialogue.cpp | 14 +++++++++++++- apps/openmw/mwgui/dialogue.hpp | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a7ae85ea..14bbe81ef 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -45,6 +45,11 @@ namespace MWGui mWindow->addResponse(title, text, mNeedMargin); } + void updateTopics() + { + mWindow->updateTopics(); + } + private: DialogueWindow* mWindow; bool mNeedMargin; @@ -91,6 +96,7 @@ namespace MWGui type = MWBase::MechanicsManager::PT_Bribe1000; MWBase::Environment::get().getDialogueManager()->persuade(type, mCallback.get()); + mCallback->updateTopics(); setVisible(false); } @@ -395,6 +401,8 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + updateTopics(); } } @@ -432,7 +440,9 @@ namespace MWGui setTitle(mPtr.getClass().getName(mPtr)); - updateTopicsPane(); + updateTopics(); + updateTopicsPane(); // force update for new services + updateDisposition(); restock(); } @@ -620,11 +630,13 @@ namespace MWGui void DialogueWindow::onTopicActivated(const std::string &topicId) { MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get()); + updateTopics(); } void DialogueWindow::onChoiceActivated(int id) { MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); + updateTopics(); } void DialogueWindow::onGoodbyeActivated() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 277032513..2538602c6 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -131,8 +131,9 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - protected: void updateTopics(); + + protected: void updateTopicsPane(); bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); From ea2bbce68a6c70d3cfb3de187ba73bb99e6c9187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 18 Nov 2017 19:27:09 +0100 Subject: [PATCH 22/67] Fix memory leak in WindowManager --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccdd6916c..4992716aa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -530,6 +530,7 @@ namespace MWGui delete mDragAndDrop; delete mSoulgemDialog; delete mCursorManager; + delete mToolTips; cleanupGarbage(); From f896c9acb63b9d6fb1e2274baf21e5beab0057b7 Mon Sep 17 00:00:00 2001 From: jbo-85 Date: Sun, 19 Nov 2017 11:56:24 +0100 Subject: [PATCH 23/67] Fix search paths in FindSDL2.cmake to find SDL2 built from source --- cmake/FindSDL2.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 25105f1e2..4f2be8c42 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -70,10 +70,10 @@ endif() libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h HINTS $ENV{SDL2DIR} - PATH_SUFFIXES include SDL2 + PATH_SUFFIXES include SDL2 include/SDL2 FIND_LIBRARY SDL2 HINTS $ENV{SDL2DIR} - PATH_SUFFIXES ${_sdl_lib_suffix} + PATH_SUFFIXES lib ${_sdl_lib_suffix} ) libfind_version_n_header(SDL2 NAMES SDL_version.h DEFINES SDL_MAJOR_VERSION SDL_MINOR_VERSION SDL_PATCHLEVEL) @@ -85,7 +85,7 @@ IF(NOT SDL2_BUILDING_LIBRARY AND NOT APPLE) libfind_pkg_detect(SDL2MAIN sdl2 FIND_LIBRARY SDL2main HINTS $ENV{SDL2DIR} - PATH_SUFFIXES ${_sdl_lib_suffix} + PATH_SUFFIXES lib ${_sdl_lib_suffix} ) set(SDL2MAIN_FIND_QUIETLY TRUE) libfind_process(SDL2MAIN) From 60d0c83cca7664a5d300db0004d5b45eda1dcbc0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 17:39:28 +0400 Subject: [PATCH 24/67] Handle 128px Tx_menubook_topics textures --- apps/openmw/mwgui/journalwindow.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 30a440b58..3fbe44f95 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -203,9 +203,20 @@ namespace int cancelLeft = getWidget(CancelBTN)->getPosition().left; int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); + // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. + // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. + if (getWidget(TopicsBTN)->getSize().width == 64) + { + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget(QuestsBTN)->getPosition().left; + getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + mQuestMode = false; mAllQuests = false; mOptionsMode = false; From 4dcaf040e670809af60a8c915b0ff113e8dd4641 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 4 Aug 2017 20:21:13 +0400 Subject: [PATCH 25/67] A Russian journal index --- apps/openmw/mwgui/journalbooks.cpp | 14 ++++++++------ apps/openmw/mwgui/journalviewmodel.cpp | 24 +++++++++++++++++++++--- apps/openmw/mwgui/journalviewmodel.hpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 5634eb080..19a2a9afe 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -224,20 +224,22 @@ book JournalBooks::createTopicIndexBook () BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); - for (int i = 0; i < 26; ++i) + for (int i = 0; i < 32; ++i) { - char ch = 'A' + i; - char buffer [32]; - sprintf (buffer, "( %c )", ch); + sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, ch); + textColours.journalTopicPressed, i+1); + + // Words can not be started with these characters + if (i == 26 || i == 28) + continue; - if (i == 13) + if (i == 15) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index b5d08eec6..02103280b 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -305,18 +305,36 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (int index, 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) { - if (i->first [0] != Misc::StringUtils::toLower(character)) + if (i->first.length() < 2) + continue; + + unsigned char byte1 = i->first[0]; + unsigned char byte2 = i->first[1]; + + // Upper case + if (byte1 == 0xd0 && byte2 >= 0xb0 && byte2 < 0xc0) + byte2 -= 32; + + if (byte1 == 0xd1 && byte2 >= 0x80 && byte2 < 0x90) + { + byte1 -= 1; + byte2 += 32; + } + + // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + // so we can use 0xd08f + index + // (index is a position of letter in alphabet, begins from 1) + if (byte1 != 0xd0 || byte2 != 0x8f + index) continue; visitor (i->second.getName()); } - } struct TopicEntryImpl : BaseEntry diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 3edde3d31..88f8acd55 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -75,8 +75,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; - /// walks over the topics whose names start with the specified character providing the topics name - virtual void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const = 0; + /// walks over the topics whose names start with the character, specified by its index in the alphabet, providing the topics name + virtual void visitTopicNamesStartingWith (int index, 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/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 105f95085..b4279e03d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -431,7 +431,7 @@ namespace MWBase::Environment::get().getWindowManager()->playSound("book page"); } - void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character) + void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId index) { setVisible (LeftTopicIndex, false); setVisible (RightTopicIndex, false); @@ -444,7 +444,7 @@ namespace AddNamesToList add(list); - mModel->visitTopicNamesStartingWith((char) character, add); + mModel->visitTopicNamesStartingWith(index, add); list->adjustSize(); From a391990f2a52695b3c56afedaea5ffb80581f1e4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 21:30:46 +0400 Subject: [PATCH 26/67] Provide multibyte toLower() and single chars comparator --- apps/openmw/mwgui/journalviewmodel.cpp | 46 ++++++++++++++++---------- components/misc/stringops.hpp | 30 +++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 02103280b..33935f040 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -311,29 +311,39 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first.length() < 2) - continue; - unsigned char byte1 = i->first[0]; - unsigned char byte2 = i->first[1]; + // First, check for two-byte UTF-8 symbols, e.g. Cyrillic ones + // TODO: check which language journal index is using + if ((byte1 == 0xd0 || byte1 == 0xd1) && i->first.length() >= 2) + { + unsigned char byte2 = i->first[1]; - // Upper case - if (byte1 == 0xd0 && byte2 >= 0xb0 && byte2 < 0xc0) - byte2 -= 32; + std::pair symbol = Misc::StringUtils::toLower(byte1, byte2); - if (byte1 == 0xd1 && byte2 >= 0x80 && byte2 < 0x90) - { - byte1 -= 1; - byte2 += 32; - } + // CYRILLIC LETTER A - CYRILLIC LETTER PE + // index from 1 to 16 + if (symbol.first == 0xd0 && symbol.second >= (0xaf + index) && symbol.second < (0xbf + index) && symbol.second == (0xaf + index)) + { + visitor (i->second.getName()); + continue; + } - // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 - // so we can use 0xd08f + index - // (index is a position of letter in alphabet, begins from 1) - if (byte1 != 0xd0 || byte2 != 0x8f + index) - continue; + // CYRILLIC LETTERL R - CYRILLIC LETTER YA + // index from 17 to 32 + if (symbol.first == 0xd1 && symbol.second >= (0x6f + index) && symbol.second < (0x7f + index) && symbol.second == (0x6f + index)) + { + visitor (i->second.getName()); + continue; + } + } + else + { + // Otherwise check for regular Latin symbols, 0x61 = 'a' + if (i->first [0] != 0x60 + index) + continue; - visitor (i->second.getName()); + visitor (i->second.getName()); + } } } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..97865a44c 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -55,6 +55,36 @@ public: }; } + static std::pair toLower(unsigned char byte1, unsigned char byte2) + { + std::pair symbol = std::make_pair(byte1, byte2); + // CYRILLIC CAPITAL IO + if (symbol.first == 0xd0 && symbol.second == 0x01) + { + symbol.first++; + symbol.second = 0x91; + } + // CYRILLIC CAPITAL A - CYRILLIC CAPITAL PE + else if (symbol.first == 0xd0 && symbol.second >= 0x90 && symbol.second < 0xa0) + { + symbol.second += 0x20; + } + // CYRILLIC CAPITAL R - CYRILLIC CAPITAL YA + else if (symbol.first == 0xd0 && symbol.second >= 0xa0 && symbol.second < 0xb0) + { + symbol.first++; + symbol.second -= 0x20; + } + // Other symbols + else + { + symbol.first = toLower(symbol.first); + symbol.second = toLower(symbol.second); + } + + return symbol; + } + 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 ce5bdd636183691ea7187698cb370cbf154bf522 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 22:25:53 +0400 Subject: [PATCH 27/67] Split the JournalBooks::createTopicIndexBook() --- apps/openmw/mwgui/journalbooks.cpp | 44 ++++++++++++++++++++++++++++-- apps/openmw/mwgui/journalbooks.hpp | 2 ++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 19a2a9afe..b4f9147b5 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -217,19 +217,59 @@ book JournalBooks::createQuestBook (const std::string& questName) } book JournalBooks::createTopicIndexBook () +{ + // TODO: determine actual index alphabet + bool isRussian = true; + + BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); + + return typesetter->complete (); +} + +BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); typesetter->setSectionAlignment (BookTypesetter::AlignCenter); - BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + for (int i = 0; i < 26; ++i) + { + char ch = 'A' + i; + char buffer [32]; + + sprintf (buffer, "( %c )", ch); + + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) + const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); + BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, + textColours.journalTopicOver, + textColours.journalTopicPressed, i+1); + if (i == 13) + typesetter->sectionBreak (); + + typesetter->write (style, to_utf8_span (buffer)); + typesetter->lineBreak (); + } + + return typesetter; +} + +BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () +{ + BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); + + typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 32; ++i) { char buffer [32]; sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, @@ -246,7 +286,7 @@ book JournalBooks::createTopicIndexBook () typesetter->lineBreak (); } - return typesetter->complete (); + return typesetter; } BookTypesetter::Ptr JournalBooks::createTypesetter () diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 8f87825f0..769f05823 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -24,6 +24,8 @@ namespace MWGui private: BookTypesetter::Ptr createTypesetter (); + BookTypesetter::Ptr createLatinJournalIndex (); + BookTypesetter::Ptr createCyrillicJournalIndex (); }; } From 9fda3b6db479b61a5e52c4cdce7208bdabac72a7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:11:28 +0100 Subject: [PATCH 28/67] Fix NumericEditBox behavior broken by switch to std::stoi For some reason stoi doesn't throw an error for '1foo' while 'foo1' does. Now the edit box flat out rejects any non-digit key events. --- components/widgets/numericeditbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index 6e884a091..ee2c30a7b 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -87,7 +87,7 @@ namespace Gui setValue(std::max(mValue-1, mMinValue)); eventValueChanged(mValue); } - else + else if (character == 0 || (character >= '0' && character <= '9')) Base::onKeyButtonPressed(key, character); } From a3f821cdcd60cf7ad333c3b0af0042424e7c27e1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:28:51 +0100 Subject: [PATCH 29/67] Disable keyboard for trade +/- buttons For one, because their RepeatClick handler breaks the keyboard function, and because its redundant anyway (just press Up/Down arrow with the edit box focused to do the same thing) --- files/mygui/openmw_trade_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index ebfe9b30f..4e2fc6e6d 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -43,9 +43,11 @@ + + From cc3c27f2418cd50ad7930d701c793d0d2bfda679 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:55:15 +0100 Subject: [PATCH 30/67] Clean up layout files to use Spacer class --- files/mygui/openmw_alchemy_window.layout | 4 +--- files/mygui/openmw_chargen_birth.layout | 4 +--- files/mygui/openmw_chargen_class.layout | 4 +--- files/mygui/openmw_chargen_create_class.layout | 4 +--- files/mygui/openmw_chargen_race.layout | 4 +--- files/mygui/openmw_chargen_review.layout | 4 +--- files/mygui/openmw_edit_effect.layout | 4 +--- files/mygui/openmw_edit_note.layout | 4 +--- files/mygui/openmw_enchanting_dialog.layout | 8 ++------ files/mygui/openmw_levelup_dialog.layout | 4 +--- files/mygui/openmw_recharge_dialog.layout | 4 +--- files/mygui/openmw_repair.layout | 4 +--- files/mygui/openmw_spellcreation_dialog.layout | 4 +--- files/mygui/openmw_tooltips.layout | 8 ++------ files/mygui/openmw_wait_dialog.layout | 4 +--- 15 files changed, 17 insertions(+), 51 deletions(-) diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index 8a1bf1347..a8e5431fb 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -76,9 +76,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index d93249c03..a137d83d1 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -17,9 +17,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index d875fae22..98c8e4fde 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -74,9 +74,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index e2920c742..c04cfe064 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -75,9 +75,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 04bd9cc53..31f0436d5 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -76,9 +76,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index 1099fcd3b..927296fad 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -112,9 +112,7 @@ - - - + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 376e87efa..c2429d24b 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -94,9 +94,7 @@ - - - + diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index 7039c719e..edf53bde7 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -16,9 +16,7 @@ - - - + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 6a08e6fd0..ed3cfb03e 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -36,9 +36,7 @@ - - - + @@ -141,9 +139,7 @@ - - - + diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 66855373a..7849d507f 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -156,9 +156,7 @@ - - - + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index 200d345e3..626039065 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -27,9 +27,7 @@ - - - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index abc429594..bf58b6c81 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -34,9 +34,7 @@ - - - + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index e14674ad6..e7c27655d 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -68,9 +68,7 @@ - - - + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index c038066f1..bdc224ecd 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -103,9 +103,7 @@ - - - + @@ -122,9 +120,7 @@ - - - + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 4bc60ceb4..b02db3764 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -26,9 +26,7 @@ - - - + From a83a43e37613667b956752be5f1fff049ca959ce Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 09:32:35 +0400 Subject: [PATCH 31/67] Determine when need to use the Cyrillic journal index --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/journalbooks.cpp | 6 ++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 416a7ad87..ffcbe0502 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -9,6 +9,8 @@ #include "../mwgui/mode.hpp" +#include + namespace Loading { class Listener; @@ -365,6 +367,7 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + virtual ToUTF8::FromType getEncoding() = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index b4f9147b5..73796c381 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -5,6 +5,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include + #include "textcolours.hpp" @@ -218,8 +220,8 @@ book JournalBooks::createQuestBook (const std::string& questName) book JournalBooks::createTopicIndexBook () { - // TODO: determine actual index alphabet - bool isRussian = true; + ToUTF8::FromType encoding = MWBase::Environment::get().getWindowManager()->getEncoding(); + bool isRussian = (encoding == ToUTF8::WINDOWS_1251); BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..920b8c1ac 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -205,6 +205,7 @@ namespace MWGui , mRestAllowed(true) , mFallbackMap(fallbackMap) , mShowOwned(0) + , mEncoding(encoding) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -2174,4 +2175,8 @@ namespace MWGui return mTextColours; } + ToUTF8::FromType WindowManager::getEncoding() + { + return mEncoding; + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f74ba21a3..a1ec7cdb4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -393,6 +393,7 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); virtual const MWGui::TextColours& getTextColours(); + virtual ToUTF8::FromType getEncoding(); private: const MWWorld::ESMStore* mStore; @@ -515,6 +516,8 @@ namespace MWGui int mShowOwned; + ToUTF8::FromType mEncoding; + std::string mVersionDescription; MWGui::TextColours mTextColours; From ea36956ff11b7d81f06d219da9e6370275a50bba Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 10:00:53 +0400 Subject: [PATCH 32/67] Reworked trade window --- files/mygui/openmw_trade_window.layout | 45 ++++++++++++++------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 4e2fc6e6d..71dc04c55 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -3,7 +3,7 @@ - + @@ -34,34 +34,37 @@ - - - - - - - - - - - - - - + + + + + + + + + + + - - - + + + + + + + + + + + - - - + From ba91cd658b019dbf1ee93c4185333687c3e086a7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 12:31:23 +0400 Subject: [PATCH 33/67] Convert topic name to Unicode --- apps/openmw/mwgui/journalbooks.cpp | 19 +++++++++--- apps/openmw/mwgui/journalviewmodel.cpp | 41 ++++++-------------------- apps/openmw/mwgui/journalviewmodel.hpp | 4 +-- components/misc/stringops.hpp | 39 ++++++++---------------- 4 files changed, 39 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 49c1aa972..3b1463b45 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -6,10 +6,10 @@ #include "../mwbase/windowmanager.hpp" #include +#include #include "textcolours.hpp" - namespace { struct AddContent @@ -242,11 +242,17 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () sprintf (buffer, "( %c )", ch); + char buffer2 [32]; + sprintf(buffer2, "%c", ch); + const char * c = buffer2; + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = stream.peek(); + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, i+1); + textColours.journalTopicPressed, first); if (i == 13) typesetter->sectionBreak (); @@ -271,11 +277,16 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 - // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) + char buffer2 [32]; + sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); + const char * c = buffer2; + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = stream.peek(); + const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, i+1); + textColours.journalTopicPressed, first); // Words can not be started with these characters if (i == 26 || i == 28) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 33935f040..3f8992e31 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -305,45 +307,20 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (uint32_t 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) { - unsigned char byte1 = i->first[0]; - // First, check for two-byte UTF-8 symbols, e.g. Cyrillic ones - // TODO: check which language journal index is using - if ((byte1 == 0xd0 || byte1 == 0xd1) && i->first.length() >= 2) - { - unsigned char byte2 = i->first[1]; - - std::pair symbol = Misc::StringUtils::toLower(byte1, byte2); - - // CYRILLIC LETTER A - CYRILLIC LETTER PE - // index from 1 to 16 - if (symbol.first == 0xd0 && symbol.second >= (0xaf + index) && symbol.second < (0xbf + index) && symbol.second == (0xaf + index)) - { - visitor (i->second.getName()); - continue; - } + const char * c = i->first.c_str(); + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = Misc::StringUtils::toUpper(stream.peek()); - // CYRILLIC LETTERL R - CYRILLIC LETTER YA - // index from 17 to 32 - if (symbol.first == 0xd1 && symbol.second >= (0x6f + index) && symbol.second < (0x7f + index) && symbol.second == (0x6f + index)) - { - visitor (i->second.getName()); - continue; - } - } - else - { - // Otherwise check for regular Latin symbols, 0x61 = 'a' - if (i->first [0] != 0x60 + index) - continue; + if (first != character) + continue; - visitor (i->second.getName()); - } + visitor (i->second.getName()); } } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 88f8acd55..01dcb49de 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -75,8 +75,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; - /// walks over the topics whose names start with the character, specified by its index in the alphabet, providing the topics name - virtual void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > 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; /// 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/stringops.hpp b/components/misc/stringops.hpp index 0d9c2489f..5ce5360d1 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -56,34 +56,21 @@ public: }; } - static std::pair toLower(unsigned char byte1, unsigned char byte2) + static uint32_t toUpper(uint32_t ch) { - std::pair symbol = std::make_pair(byte1, byte2); - // CYRILLIC CAPITAL IO - if (symbol.first == 0xd0 && symbol.second == 0x01) - { - symbol.first++; - symbol.second = 0x91; - } - // CYRILLIC CAPITAL A - CYRILLIC CAPITAL PE - else if (symbol.first == 0xd0 && symbol.second >= 0x90 && symbol.second < 0xa0) - { - symbol.second += 0x20; - } - // CYRILLIC CAPITAL R - CYRILLIC CAPITAL YA - else if (symbol.first == 0xd0 && symbol.second >= 0xa0 && symbol.second < 0xb0) - { - symbol.first++; - symbol.second -= 0x20; - } - // Other symbols - else - { - symbol.first = toLower(symbol.first); - symbol.second = toLower(symbol.second); - } + // Russian alphabete + if (ch >= 0x0430 && ch < 0x0450) + ch -= 0x20; + + // Cyrillic YO character + if (ch == 0x0451) + ch -= 0x50; + + // Latin alphabete + if (ch >= 0x61 && ch < 0x80) + ch -= 0x20; - return symbol; + return ch; } static bool ciLess(const std::string &x, const std::string &y) { From 5f41f7c48df215f160a9418dd39595c954370cf8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 12:59:47 +0400 Subject: [PATCH 34/67] Clean code up a bit --- apps/openmw/mwgui/journalbooks.cpp | 10 +++------- apps/openmw/mwgui/journalviewmodel.cpp | 3 +-- components/misc/stringops.hpp | 4 ++-- components/misc/utf8stream.hpp | 5 +++++ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 3b1463b45..68b1d8403 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -239,16 +239,13 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { char ch = 'A' + i; char buffer [32]; - sprintf (buffer, "( %c )", ch); char buffer2 [32]; sprintf(buffer2, "%c", ch); - const char * c = buffer2; - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + Utf8Stream stream (buffer2); uint32_t first = stream.peek(); - // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, @@ -274,13 +271,12 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () for (int i = 0; i < 32; ++i) { char buffer [32]; - sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 char buffer2 [32]; sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); - const char * c = buffer2; - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + + Utf8Stream stream (buffer2); uint32_t first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3f8992e31..d7b233ff3 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -313,8 +313,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - const char * c = i->first.c_str(); - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + Utf8Stream stream (i->first.c_str()); uint32_t first = Misc::StringUtils::toUpper(stream.peek()); if (first != character) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 5ce5360d1..cec2a34a4 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -58,7 +58,7 @@ public: static uint32_t toUpper(uint32_t ch) { - // Russian alphabete + // Russian alphabet if (ch >= 0x0430 && ch < 0x0450) ch -= 0x20; @@ -66,7 +66,7 @@ public: if (ch == 0x0451) ch -= 0x50; - // Latin alphabete + // Latin alphabet if (ch >= 0x61 && ch < 0x80) ch -= 0x20; diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp index 760015902..368374a64 100644 --- a/components/misc/utf8stream.hpp +++ b/components/misc/utf8stream.hpp @@ -18,6 +18,11 @@ public: { } + Utf8Stream (const char * str) : + cur ((unsigned char*) str), nxt ((unsigned char*) str), end ((unsigned char*) str + strlen(str)), val(Utf8Stream::sBadChar()) + { + } + Utf8Stream (std::pair range) : cur (range.first), nxt (range.first), end (range.second), val(Utf8Stream::sBadChar()) { From 67acb83b62861e865c0fd04ff19f8922ed74c8e7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 13:27:33 +0400 Subject: [PATCH 35/67] Add missing include --- components/misc/stringops.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index cec2a34a4..1edb5ea61 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,6 +1,7 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H +#include #include #include #include From 2136003e1c32ff4f49be9f28f4d313d871430ba2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 21 Nov 2017 22:43:56 +0000 Subject: [PATCH 36/67] Reapply commit a3f821cdc which got lost in a merge --- files/mygui/openmw_trade_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 71dc04c55..0af9d59fe 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -37,6 +37,7 @@ + @@ -50,6 +51,7 @@ + From 3571f7f41379833848467c50c0ef1879c105a68c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Nov 2017 08:32:38 +0400 Subject: [PATCH 37/67] Remove getEncoding() from WindowManager --- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwgui/journalbooks.cpp | 7 +++---- apps/openmw/mwgui/journalbooks.hpp | 6 +++++- apps/openmw/mwgui/journalwindow.cpp | 8 ++++---- apps/openmw/mwgui/journalwindow.hpp | 4 +++- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +------ apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4a346a14f..6c866fbc2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,7 +351,6 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; - virtual ToUTF8::FromType getEncoding() = 0; virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 68b1d8403..07dacd0c2 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -156,8 +156,8 @@ MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text) typedef TypesetBook::Ptr book; -JournalBooks::JournalBooks (JournalViewModel::Ptr model) : - mModel (model) +JournalBooks::JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding) : + mModel (model), mEncoding(encoding) { } @@ -220,8 +220,7 @@ book JournalBooks::createQuestBook (const std::string& questName) book JournalBooks::createTopicIndexBook () { - ToUTF8::FromType encoding = MWBase::Environment::get().getWindowManager()->getEncoding(); - bool isRussian = (encoding == ToUTF8::WINDOWS_1251); + bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 769f05823..aa36eecdf 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -4,6 +4,8 @@ #include "bookpage.hpp" #include "journalviewmodel.hpp" +#include + namespace MWGui { MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text); @@ -13,7 +15,7 @@ namespace MWGui typedef TypesetBook::Ptr Book; JournalViewModel::Ptr mModel; - JournalBooks (JournalViewModel::Ptr model); + JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding); Book createEmptyJournalBook (); Book createJournalBook (); @@ -22,6 +24,8 @@ namespace MWGui Book createQuestBook (const std::string& questName); Book createTopicIndexBook (); + ToUTF8::FromType mEncoding; + private: BookTypesetter::Ptr createTypesetter (); BookTypesetter::Ptr createLatinJournalIndex (); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3c3205d91..a26f8d4ec 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -100,8 +100,8 @@ namespace return getWidget (name); } - JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) - : JournalBooks (Model), JournalWindow() + JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding) + : JournalBooks (Model, encoding), JournalWindow() { center(); @@ -643,9 +643,9 @@ namespace } // glue the implementation to the interface -MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList) +MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding) { - return new JournalWindowImpl (Model, questList); + return new JournalWindowImpl (Model, questList, encoding); } MWGui::JournalWindow::JournalWindow() diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index c9bf0ef0a..62080f72e 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" +#include + #include namespace MWBase { class WindowManager; } @@ -16,7 +18,7 @@ namespace MWGui JournalWindow(); /// construct a new instance of the one JournalWindow implementation - static JournalWindow * create (std::shared_ptr Model, bool questList); + static JournalWindow * create (std::shared_ptr Model, bool questList, ToUTF8::FromType encoding); /// destroy this instance of the JournalWindow implementation virtual ~JournalWindow () {}; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c302313f2..2084786b3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -347,7 +347,7 @@ namespace MWGui mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); - JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); + JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList, mEncoding); mWindows.push_back(journal); mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal].mCloseSound = "book close"; @@ -2034,11 +2034,6 @@ namespace MWGui return mTextColours; } - ToUTF8::FromType WindowManager::getEncoding() - { - return mEncoding; - } - bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { if (!mKeyboardNavigation->injectKeyPress(key, text)) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a264128b3..1d250f6d4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -378,7 +378,6 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); virtual const MWGui::TextColours& getTextColours(); - virtual ToUTF8::FromType getEncoding(); virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); From 86a17b1e3ed68cab4114bb14ea8307774f646f12 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Nov 2017 09:06:54 +0400 Subject: [PATCH 38/67] Get rid of the redundant Utf8Stream when during journal index creation --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/journalbooks.cpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 6c866fbc2..f2b4a526d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,6 +351,7 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 07dacd0c2..f3ee8162e 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -233,28 +233,26 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + char ch = 'A'; + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 26; ++i) { - char ch = 'A' + i; char buffer [32]; sprintf (buffer, "( %c )", ch); - char buffer2 [32]; - sprintf(buffer2, "%c", ch); - Utf8Stream stream (buffer2); - uint32_t first = stream.peek(); - const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, first); + textColours.journalTopicPressed, (uint32_t) ch); if (i == 13) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); + + ch++; } return typesetter; @@ -267,15 +265,15 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + + unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + for (int i = 0; i < 32; ++i) { char buffer [32]; - sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + sprintf(buffer, "( %c%c )", ch[0], ch[1]); - char buffer2 [32]; - sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); - - Utf8Stream stream (buffer2); + Utf8Stream stream ((char*) ch); uint32_t first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); @@ -292,6 +290,8 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); + + ch[1]++; } return typesetter; From de42aa9d03842bc1c84acd76985a36261afd339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 00:32:22 +0100 Subject: [PATCH 39/67] Make thrown projectiles rotate --- apps/openmw/mwworld/projectilemanager.cpp | 17 ++++++++++++++++- apps/openmw/mwworld/projectilemanager.hpp | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ede8c34c4..1d53c1909 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -316,6 +316,8 @@ namespace MWWorld state.mIdArrow = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; state.mAttackStrength = attackStrength; + state.mThrown = projectile.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; + state.mTime = 0.0; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -453,12 +455,25 @@ namespace MWWorld // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; + it->mTime += duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Quat orient; - orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + + orient.set( + osg::Matrixd::rotate(it->mThrown ? -1 * it->mTime : 0.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * + osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * + osg::Matrixd::inverse( + osg::Matrixd::lookAt( + osg::Vec3f(0,0,0), + it->mVelocity, + osg::Vec3f(0,0,1)) + ) + ); + it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 0dfbf6080..1e0de4dbe 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -112,6 +112,8 @@ namespace MWWorld osg::Vec3f mVelocity; float mAttackStrength; + float mTime; + bool mThrown; }; std::vector mMagicBolts; From 4d384889af728c2ba76b3ef1aeb589bbbe29f999 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 10:14:45 +0400 Subject: [PATCH 40/67] Fix the Topics button position if the Tribunal is not installed --- apps/openmw/mwgui/journalwindow.cpp | 52 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3fbe44f95..3dc583ac2 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -161,6 +161,15 @@ namespace Gui::ImageButton* showActiveButton = getWidget(ShowActiveBTN); Gui::ImageButton* showAllButton = getWidget(ShowAllBTN); Gui::ImageButton* questsButton = getWidget(QuestsBTN); + + Gui::ImageButton* nextButton = getWidget(NextPageBTN); + if (nextButton->getSize().width == 64) + { + // english button has a 7 pixel wide strip of garbage on its right edge + nextButton->setSize(64-7, nextButton->getSize().height); + nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height)); + } + if (!questList) { // If tribunal is not installed (-> no options button), we still want the Topics button available, @@ -176,6 +185,8 @@ namespace showActiveButton->setVisible(false); showAllButton->setVisible(false); questsButton->setVisible(false); + + adjustButton(TopicsBTN); } else { @@ -188,33 +199,24 @@ namespace adjustButton(ShowActiveBTN); adjustButton(OptionsBTN); adjustButton(QuestsBTN); - } - - Gui::ImageButton* nextButton = getWidget(NextPageBTN); - if (nextButton->getSize().width == 64) - { - // english button has a 7 pixel wide strip of garbage on its right edge - nextButton->setSize(64-7, nextButton->getSize().height); - nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height)); - } - - adjustButton(TopicsBTN); - int topicsWidth = getWidget(TopicsBTN)->getSize().width; - int cancelLeft = getWidget(CancelBTN)->getPosition().left; - int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; + adjustButton(TopicsBTN); + int topicsWidth = getWidget(TopicsBTN)->getSize().width; + int cancelLeft = getWidget(CancelBTN)->getPosition().left; + int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); + getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); - // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. - // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. - if (getWidget(TopicsBTN)->getSize().width == 64) - { - getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); - } - else - { - int questLeft = getWidget(QuestsBTN)->getPosition().left; - getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. + // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. + if (topicsWidth == 64) + { + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget(QuestsBTN)->getPosition().left; + getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } } mQuestMode = false; From 4f190bf7f494435aefe6d678f711bf6c4bfc27b0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 14:58:20 +0400 Subject: [PATCH 41/67] Do not show carriage return characters (bug #3696) --- apps/openmw/mwgui/bookpage.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 137594076..5a9237cea 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -16,6 +16,7 @@ class BookPageImpl; static bool ucsSpace (int codePoint); static bool ucsLineBreak (int codePoint); +static bool ucsCarriageReturn (int codePoint); static bool ucsBreakingSpace (int codePoint); struct BookTypesetter::Style { virtual ~Style () {} }; @@ -280,7 +281,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter style.mActiveColour = fontColour; style.mNormalColour = fontColour; style.mInteractiveId = 0; - + return &style; } @@ -342,7 +343,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter writeImpl (static_cast (style), begin_, end_); } - + void lineBreak (float margin) { assert (margin == 0); //TODO: figure out proper behavior here... @@ -352,7 +353,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter mRun = NULL; mLine = NULL; } - + void sectionBreak (int margin) { add_partial_text(); @@ -1188,6 +1189,9 @@ public: { Utf8Stream::UnicodeChar code_point = stream.consume (); + if (ucsCarriageReturn (code_point)) + continue; + if (!ucsSpace (code_point)) glyphStream.emitGlyph (code_point); else @@ -1331,6 +1335,11 @@ static bool ucsLineBreak (int codePoint) return codePoint == '\n'; } +static bool ucsCarriageReturn (int codePoint) +{ + return codePoint == '\r'; +} + static bool ucsSpace (int codePoint) { switch (codePoint) From 2b9a0a77328d69b215cf4ad0fb51f28944407b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 12:11:26 +0100 Subject: [PATCH 42/67] Save new projectile state --- apps/openmw/mwworld/projectilemanager.cpp | 5 +++++ components/esm/projectilestate.cpp | 8 ++++++++ components/esm/projectilestate.hpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1d53c1909..1c080aec1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -567,6 +567,9 @@ namespace MWWorld state.mVelocity = it->mVelocity; state.mAttackStrength = it->mAttackStrength; + state.mThrown = it->mThrown; + state.mTime = it->mTime; + state.save(writer); writer.endRecord(ESM::REC_PROJ); @@ -604,6 +607,8 @@ namespace MWWorld state.mVelocity = esm.mVelocity; state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; + state.mThrown = esm.mThrown; + state.mTime = esm.mTime; std::string model; try diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 8ade9d5b2..1c8a10bcb 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,6 +52,8 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); + esm.writeHNT ("THR_", mThrown); + esm.writeHNT ("TIM_", mTime); } void ProjectileState::load(ESMReader &esm) @@ -63,6 +65,12 @@ namespace ESM mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); + + mThrown = false; + esm.getHNOT (mThrown, "THR_"); + + mTime = 0.f; + esm.getHNOT (mTime, "TIM_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 67ec89bb6..625d34b6a 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,6 +42,8 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; + float mTime; + bool mThrown; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 3dbcda6686deb5fd31d0a1992eb36884b4b369ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 15:14:15 +0100 Subject: [PATCH 43/67] Make use of mEffectAnimationTime for projectile rotation --- apps/openmw/mwworld/projectilemanager.cpp | 6 +----- apps/openmw/mwworld/projectilemanager.hpp | 1 - components/esm/projectilestate.cpp | 4 ---- components/esm/projectilestate.hpp | 1 - 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1c080aec1..d38931700 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -317,7 +317,6 @@ namespace MWWorld state.mCasterHandle = actor; state.mAttackStrength = attackStrength; state.mThrown = projectile.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; - state.mTime = 0.0; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -455,7 +454,6 @@ namespace MWWorld // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; - it->mTime += duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; @@ -463,7 +461,7 @@ namespace MWWorld osg::Quat orient; orient.set( - osg::Matrixd::rotate(it->mThrown ? -1 * it->mTime : 0.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(it->mThrown ? -1 * it->mEffectAnimationTime->getTime() * 10.0 : 0.0,osg::Vec3f(0,0,1)) * osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * osg::Matrixd::inverse( @@ -568,7 +566,6 @@ namespace MWWorld state.mAttackStrength = it->mAttackStrength; state.mThrown = it->mThrown; - state.mTime = it->mTime; state.save(writer); @@ -608,7 +605,6 @@ namespace MWWorld state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; state.mThrown = esm.mThrown; - state.mTime = esm.mTime; std::string model; try diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 1e0de4dbe..ba2fe7a74 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -112,7 +112,6 @@ namespace MWWorld osg::Vec3f mVelocity; float mAttackStrength; - float mTime; bool mThrown; }; diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 1c8a10bcb..7b6c419f2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -53,7 +53,6 @@ namespace ESM esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); esm.writeHNT ("THR_", mThrown); - esm.writeHNT ("TIM_", mTime); } void ProjectileState::load(ESMReader &esm) @@ -68,9 +67,6 @@ namespace ESM mThrown = false; esm.getHNOT (mThrown, "THR_"); - - mTime = 0.f; - esm.getHNOT (mTime, "TIM_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 625d34b6a..c89bb7683 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,7 +42,6 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; - float mTime; bool mThrown; void load (ESMReader &esm); From a8bf4cdd98fea8bbb05925cc737c8c9e3eb3a63b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:29:40 +0400 Subject: [PATCH 44/67] Remove redundant include --- apps/openmw/mwbase/windowmanager.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f2b4a526d..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -11,8 +11,6 @@ #include "../mwgui/mode.hpp" -#include - namespace Loading { class Listener; From 94c0e3ed10dd58b122ddecb4192b19365e8befe8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:37:45 +0400 Subject: [PATCH 45/67] Move toUpper() from StringUtils to the JournalViewModel --- apps/openmw/mwgui/journalviewmodel.cpp | 19 ++++++++++++++++++- components/misc/stringops.hpp | 18 ------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index d7b233ff3..6ff68c9c5 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -314,7 +314,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { Utf8Stream stream (i->first.c_str()); - uint32_t first = Misc::StringUtils::toUpper(stream.peek()); + uint32_t first = toUpper(stream.peek()); if (first != character) continue; @@ -323,6 +323,23 @@ struct JournalViewModelImpl : JournalViewModel } } + 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/components/misc/stringops.hpp b/components/misc/stringops.hpp index 1edb5ea61..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,7 +1,6 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H -#include #include #include #include @@ -57,23 +56,6 @@ public: }; } - static uint32_t toUpper(uint32_t ch) - { - // Russian alphabet - if (ch >= 0x0430 && ch < 0x0450) - ch -= 0x20; - - // Cyrillic YO character - if (ch == 0x0451) - ch -= 0x50; - - // Latin alphabet - if (ch >= 0x61 && ch < 0x80) - ch -= 0x20; - - return ch; - } - 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 38bda3bd710a7cabb8168d1c9785c561d1ad4aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 18:00:10 +0100 Subject: [PATCH 46/67] Do not save thrown state for projectiles --- apps/openmw/mwworld/projectilemanager.cpp | 4 +--- components/esm/projectilestate.cpp | 4 ---- components/esm/projectilestate.hpp | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d38931700..707e8b193 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -565,8 +565,6 @@ namespace MWWorld state.mVelocity = it->mVelocity; state.mAttackStrength = it->mAttackStrength; - state.mThrown = it->mThrown; - state.save(writer); writer.endRecord(ESM::REC_PROJ); @@ -604,7 +602,6 @@ namespace MWWorld state.mVelocity = esm.mVelocity; state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; - state.mThrown = esm.mThrown; std::string model; try @@ -612,6 +609,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); MWWorld::Ptr ptr = ref.getPtr(); model = ptr.getClass().getModel(ptr); + state.mThrown = ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; } catch(...) { diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 7b6c419f2..8ade9d5b2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,7 +52,6 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); - esm.writeHNT ("THR_", mThrown); } void ProjectileState::load(ESMReader &esm) @@ -64,9 +63,6 @@ namespace ESM mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); - - mThrown = false; - esm.getHNOT (mThrown, "THR_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index c89bb7683..67ec89bb6 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,7 +42,6 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; - bool mThrown; void load (ESMReader &esm); void save (ESMWriter &esm) const; From d0a299caabc3feef0d8009189d0ec25fa51b89f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 20:02:12 +0100 Subject: [PATCH 47/67] Rotate thrown projectiles around the bb center --- apps/openmw/mwworld/projectilemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 707e8b193..73b8d4d49 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -202,6 +203,12 @@ namespace MWWorld osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); + osg::ref_ptr boundVisitor = new osg::ComputeBoundsVisitor(); + projectile->accept(*boundVisitor.get()); + osg::BoundingBox bb = boundVisitor->getBoundingBox(); + + state.mNode->setPivotPoint(bb.center()); + if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) { From 4373fea21e008375b974447f48c84844ac690bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 20:27:22 +0100 Subject: [PATCH 48/67] Correct projectile rotation --- apps/openmw/mwworld/projectilemanager.cpp | 28 ++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 73b8d4d49..a4a22ea4a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -386,7 +386,6 @@ namespace MWWorld static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get() .find("fTargetSpellMaxSpeed")->getFloat(); float speed = fTargetSpellMaxSpeed * it->mSpeed; - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); direction.normalize(); osg::Vec3f pos(it->mNode->getPosition()); @@ -466,18 +465,21 @@ namespace MWWorld osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Quat orient; - - orient.set( - osg::Matrixd::rotate(it->mThrown ? -1 * it->mEffectAnimationTime->getTime() * 10.0 : 0.0,osg::Vec3f(0,0,1)) * - osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * - osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * - osg::Matrixd::inverse( - osg::Matrixd::lookAt( - osg::Vec3f(0,0,0), - it->mVelocity, - osg::Vec3f(0,0,1)) - ) - ); + + if (it->mThrown) + orient.set( + osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * + osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * + osg::Matrixd::inverse( + osg::Matrixd::lookAt( + osg::Vec3f(0,0,0), + it->mVelocity, + osg::Vec3f(0,0,1)) + ) + ); + else + orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); From a7c953b3180e962af2c22458b2407800039faa80 Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Fri, 24 Nov 2017 15:06:07 +0100 Subject: [PATCH 49/67] Display 0 chance for spell if player does not have enought magic energy --- 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 6953d682b..c4112513a 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -60,7 +60,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor))); + std::string chance = std::to_string((stats.getMagicka().getCurrent() >= spell->mData.mCost) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0); newSpell.mCostColumn = cost + "/" + chance; } else From 32096ae0cc19f2b6c8eabd31a2732c49a337d567 Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Sat, 25 Nov 2017 01:46:04 +0100 Subject: [PATCH 50/67] Fix displayed spell success chance in God Mode --- apps/openmw/mwgui/spellmodel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index c4112513a..9d71d9247 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -8,6 +8,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -60,7 +61,11 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string((stats.getMagicka().getCurrent() >= spell->mData.mCost) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0); + std::string chance = std::to_string( + (stats.getMagicka().getCurrent() >= spell->mData.mCost || + (mActor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) + ) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0 + ); newSpell.mCostColumn = cost + "/" + chance; } else From 55db3c2712a112d9b978bffacf903cb803edc0a6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 25 Nov 2017 11:35:29 +0400 Subject: [PATCH 51/67] Set default values for class and birthsign select menus (bug #4226) --- apps/openmw/mwgui/birth.cpp | 10 +++++++++- apps/openmw/mwgui/class.cpp | 13 ++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 92f29e3ef..c1867541b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -8,7 +8,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" + #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" #include "widgets.hpp" @@ -70,8 +72,14 @@ namespace MWGui updateBirths(); updateSpells(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList); - } + // Show the current birthsign by default + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + if (!signId.empty()) + setBirthId(signId); + } void BirthDialog::setBirthId(const std::string &birthId) { diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 33daa0ad1..4d2a15c82 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -7,6 +7,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" + +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/esmstore.hpp" #include "tooltips.hpp" @@ -131,8 +134,16 @@ namespace MWGui updateClasses(); updateStats(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList); - } + // Show the current class by default + MWWorld::Ptr player = MWMechanics::getPlayer(); + + const std::string &classId = + player.get()->mBase->mClass; + + if (!classId.empty()) + setClassId(classId); + } void PickClassDialog::setClassId(const std::string &classId) { From c8f79ea8382797ef47b8eb3989a1afaeb58f884a Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 25 Nov 2017 20:46:14 -0500 Subject: [PATCH 52/67] Adjust rotation markers --- apps/opencs/view/render/object.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c5da094e6..2e9f03719 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -307,11 +307,11 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) { const float Pi = 3.14159265f; - const float InnerRadius = mBaseNode->getBound().radius(); + const float InnerRadius = std::max(MarkerShaftBaseLength, mBaseNode->getBound().radius()); const float OuterRadius = InnerRadius + MarkerShaftWidth; const float SegmentDistance = 100.f; - const size_t SegmentCount = std::min(64, std::max(8, (int)(OuterRadius * 2 * Pi / SegmentDistance))); + const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * Pi / SegmentDistance))); const size_t VerticesPerSegment = 4; const size_t IndicesPerSegment = 24; From dea7d0beff41d06356befbb34eb3ec4d6d23e602 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 24 Nov 2017 18:25:57 +0400 Subject: [PATCH 53/67] Do not interrupt swim and sneak idle animations during attack (bug #4122) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- apps/openmw/mwmechanics/character.cpp | 19 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9ef5033f0..eba0d8191 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -232,7 +232,10 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->setAttackingOrSpell(currentValue != 0); + { + MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState(); + mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing); + } else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6cea0e9b4..d9e2cc292 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1278,7 +1278,16 @@ bool CharacterController::updateWeaponState() bool animPlaying; if(mAttackingOrSpell) { - mIdleState = CharState_None; + MWWorld::Ptr player = getPlayer(); + + // We should reset player's idle animation in the first-person mode. + if (mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson()) + mIdleState = CharState_None; + + // In other cases we should not break swim and sneak animations + if (mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) + mIdleState = CharState_None; + if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); @@ -1288,7 +1297,7 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; - if (mPtr == getPlayer()) + if (mPtr == player) { MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } @@ -1298,7 +1307,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr == getPlayer()) + if (mPtr == player) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1310,7 +1319,7 @@ bool CharacterController::updateWeaponState() MWMechanics::CastSpell cast(mPtr, NULL); cast.playSpellCastingEffects(spellid); - const ESM::Spell *spell = store.get().find(spellid); + const ESM::Spell *spell = store.get().find(spellid); const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back(); const ESM::MagicEffect *effect; @@ -1639,7 +1648,7 @@ void CharacterController::update(float duration) float speed = 0.f; updateMagicEffects(); - + if (isKnockedOut()) mTimeUntilWake -= duration; From ce324623587bc261a8b6c6e81e63766fd80a0be2 Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Sat, 25 Nov 2017 17:27:04 +0100 Subject: [PATCH 54/67] Move code to apps/openmw/mwmechanics/spellcasting.cpp, move reduce mana code to CastSpell::cast(const ESM::Spell*) --- apps/openmw/mwgui/spellmodel.cpp | 7 +------ apps/openmw/mwmechanics/spellcasting.cpp | 18 ++++++++++++------ apps/openmw/mwworld/worldimp.cpp | 7 ------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 9d71d9247..6953d682b 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -8,7 +8,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" -#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -61,11 +60,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string( - (stats.getMagicka().getCurrent() >= spell->mData.mCost || - (mActor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) - ) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0 - ); + std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor))); newSpell.mCostColumn = cost + "/" + chance; } else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a09436d14..19afc11ec 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -126,7 +126,10 @@ namespace MWMechanics float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; castChance *= stats.getFatigueTerm(); - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) + if (godmode) + return 100; + + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) return 0; if (spell->mData.mType == ESM::Spell::ST_Power) @@ -135,13 +138,11 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (spell->mData.mFlags & ESM::Spell::F_Always) - return 100; + if (stats.getMagicka().getCurrent() < spell->mData.mCost) + return 0; - if (godmode) - { + if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; - } if (!cap) return std::max(0.f, castChance); @@ -888,6 +889,11 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } + + // Reduce mana + MWMechanics::DynamicStat magicka = stats.getMagicka(); + magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); + stats.setMagicka(magicka); } if (fail) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9c7fba9fa..83971eadf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2718,13 +2718,6 @@ namespace MWWorld message = "#{sPowerAlreadyUsed}"; fail = true; } - - // Reduce mana - if (!fail && !godmode) - { - magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); - stats.setMagicka(magicka); - } } if (isPlayer && fail) From eb23367175b28cb07fe5f9449d54b05aed4f5533 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 26 Nov 2017 17:39:57 -0500 Subject: [PATCH 55/67] Fix rendering depth/order issues --- apps/opencs/view/render/object.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 2e9f03719..df7283b1a 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -336,6 +336,9 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) osg::ref_ptr primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, IndexCount); + // prevent some depth collision issues from overlaps + osg::Vec3f offset = getMarkerPosition(0, MarkerShaftWidth/4, 0, axis); + for (size_t i = 0; i < SegmentCount; ++i) { size_t index = i * VerticesPerSegment; @@ -346,10 +349,10 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) float outerX = OuterRadius * std::cos(i * Angle); float outerY = OuterRadius * std::sin(i * Angle); - vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis); - vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis); - vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis); - vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis); + vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis) + offset; + vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis) + offset; + vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis) + offset; + vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis) + offset; } colors->at(0) = osg::Vec4f ( @@ -390,17 +393,11 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) { - const int RenderBin = osg::StateSet::TRANSPARENT_BIN; - osg::ref_ptr state = geometry->getOrCreateStateSet(); state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); state->setMode(GL_BLEND, osg::StateAttribute::ON); - osg::ref_ptr depth(new osg::Depth); - depth->setWriteMask(false); - state->setAttributeAndModes(depth, osg::StateAttribute::ON); - - state->setRenderBinDetails(RenderBin, "RenderBin"); + state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis) From c50b18b3bbb9ac335cf6cb0f248d84edd4154551 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 27 Nov 2017 18:30:31 +0100 Subject: [PATCH 56/67] Move PathgridGraph out of CellStore By definition this is not 'Mutable state of a cell' and does not belong in CellStore. This change should improve startup times (graph is now loaded on demand) and edits to 'pathgrid.hpp' no longer cause the entirety of OpenMW to be rebuilt. --- apps/openmw/mwmechanics/aicombat.cpp | 3 ++- apps/openmw/mwmechanics/aipackage.cpp | 17 +++++++++++++++- apps/openmw/mwmechanics/aipackage.hpp | 3 +++ apps/openmw/mwmechanics/aiwander.cpp | 13 ++++++------ apps/openmw/mwmechanics/pathfinding.cpp | 27 +++++++++++++------------ apps/openmw/mwmechanics/pathfinding.hpp | 6 ++++-- apps/openmw/mwmechanics/pathgrid.cpp | 8 +++++++- apps/openmw/mwmechanics/pathgrid.hpp | 4 +++- apps/openmw/mwworld/cellstore.cpp | 19 ----------------- apps/openmw/mwworld/cellstore.hpp | 10 +-------- 10 files changed, 57 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index ee1013fe4..83ebc67d9 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -13,6 +13,7 @@ #include "../mwrender/animation.hpp" +#include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" @@ -372,7 +373,7 @@ namespace MWMechanics int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos); for (int i = 0; i < static_cast(pathgrid->mPoints.size()); i++) { - if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i)) + if (i != closestPointIndex && getPathGridGraph(storage.mCell).isPointConnected(closestPointIndex, i)) { points.push_back(pathgrid->mPoints[static_cast(i)]); } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f837ad2ee..198c8fc4b 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "pathgrid.hpp" #include "creaturestats.hpp" #include "movement.hpp" #include "steering.hpp" @@ -107,7 +108,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity @@ -220,6 +221,20 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur } } +const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell) +{ + const ESM::CellId& id = cell->getCell()->getCellId(); + // static cache is OK for now, pathgrids can never change during runtime + typedef std::map > CacheMap; + static CacheMap cache; + CacheMap::iterator found = cache.find(id); + if (found == cache.end()) + { + cache.insert(std::make_pair(id, std::unique_ptr(new MWMechanics::PathgridGraph(cell)))); + } + return *cache[id].get(); +} + bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS) { const MWWorld::Class& actorClass = actor.getClass(); diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index acbd87908..a9c69ad7f 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -27,6 +27,7 @@ namespace MWMechanics const float AI_REACTION_TIME = 0.25f; class CharacterController; + class PathgridGraph; /// \brief Base class for AI packages class AiPackage @@ -119,6 +120,8 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos); + const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 343e03f6c..7bdb3a11d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -17,6 +17,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" @@ -217,7 +218,7 @@ namespace MWMechanics ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination)); ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); if (mPathFinder.isPathConstructed()) storage.setState(Wander_Walking); @@ -349,7 +350,7 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); if (mPathFinder.isPathConstructed()) { @@ -383,7 +384,7 @@ namespace MWMechanics // Check if land creature will walk onto water or if water creature will swim onto land if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || (isWaterCreature && !destinationThroughGround(currentPositionVec3f, mDestination))) { - mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell()); + mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), getPathGridGraph(actor.getCell())); mPathFinder.addPointToPath(destinationPosition); if (mPathFinder.isPathConstructed()) @@ -666,7 +667,7 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); // don't take shortcuts for wandering - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); if (mPathFinder.isPathConstructed()) { @@ -872,7 +873,7 @@ namespace MWMechanics int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest)); - currentCell->getNeighbouringPoints(index, points); + getPathGridGraph(currentCell).getNeighbouringPoints(index, points); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage) @@ -913,7 +914,7 @@ namespace MWMechanics { osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); if((npcPos - nodePos).length2() <= mDistance * mDistance && - cellStore->isPointConnected(closestPointIndex, counter)) + getPathGridGraph(cellStore).isPointConnected(closestPointIndex, counter)) { storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]); pointIndex = counter; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 5c0456096..1dccb6c9a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -5,16 +5,16 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "pathgrid.hpp" #include "coordinateconverter.hpp" namespace { // Chooses a reachable end pathgrid point. start is assumed reachable. std::pair getClosestReachablePoint(const ESM::Pathgrid* grid, - const MWWorld::CellStore *cell, + const MWMechanics::PathgridGraph *graph, const osg::Vec3f& pos, int start) { assert(grid && !grid->mPoints.empty()); @@ -31,7 +31,7 @@ namespace if (potentialDistBetween < closestDistanceReachable) { // found a closer one - if (cell->isPointConnected(start, counter)) + if (graph->isPointConnected(start, counter)) { closestDistanceReachable = potentialDistBetween; closestReachableIndex = counter; @@ -45,7 +45,7 @@ namespace } // post-condition: start and endpoint must be connected - assert(cell->isPointConnected(start, closestReachableIndex)); + assert(graph->isPointConnected(start, closestReachableIndex)); // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start @@ -120,8 +120,8 @@ namespace MWMechanics } PathFinder::PathFinder() - : mPathgrid(NULL), - mCell(NULL) + : mPathgrid(NULL) + , mCell(NULL) { } @@ -169,14 +169,15 @@ namespace MWMechanics */ void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell) + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph) { mPath.clear(); + // TODO: consider removing mCell / mPathgrid in favor of mPathgridGraph if(mCell != cell || !mPathgrid) { mCell = cell; - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell->getCell()); + mPathgrid = pathgridGraph.getPathgrid(); } // Refer to AiWander reseach topic on openmw forums for some background. @@ -200,7 +201,7 @@ namespace MWMechanics int startNode = GetClosestPoint(mPathgrid, startPointInLocalCoords); osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); - std::pair endNode = getClosestReachablePoint(mPathgrid, cell, + std::pair endNode = getClosestReachablePoint(mPathgrid, &pathgridGraph, endPointInLocalCoords, startNode); @@ -228,7 +229,7 @@ namespace MWMechanics } else { - mPath = mCell->aStarSearch(startNode, endNode.first); + mPath = pathgridGraph.aStarSearch(startNode, endNode.first); // convert supplied path to world coordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) @@ -301,18 +302,18 @@ namespace MWMechanics // see header for the rationale void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell) + const MWWorld::CellStore* cell, const MWMechanics::PathgridGraph& pathgridGraph) { if (mPath.size() < 2) { // if path has one point, then it's the destination. // don't need to worry about bad path for this case - buildPath(startPoint, endPoint, cell); + buildPath(startPoint, endPoint, cell, pathgridGraph); } else { const ESM::Pathgrid::Point oldStart(*getPath().begin()); - buildPath(startPoint, endPoint, cell); + buildPath(startPoint, endPoint, cell, pathgridGraph); if (mPath.size() >= 2) { // if 2nd waypoint of new path == 1st waypoint of old, diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 945a7f927..ebc22f10d 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -14,6 +14,8 @@ namespace MWWorld namespace MWMechanics { + class PathgridGraph; + float distance(const ESM::Pathgrid::Point& point, float x, float y, float); float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b); float getZAngleToDir(const osg::Vec3f& dir); @@ -54,7 +56,7 @@ namespace MWMechanics void clearPath(); void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell); + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. @@ -89,7 +91,7 @@ namespace MWMechanics Which results in NPC "running in a circle" back to the just passed waypoint. */ void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell); + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); void addPointToPath(const ESM::Pathgrid::Point &point) { diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 85264095c..c0122a861 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -49,7 +49,7 @@ namespace namespace MWMechanics { - PathgridGraph::PathgridGraph() + PathgridGraph::PathgridGraph(const MWWorld::CellStore *cell) : mCell(NULL) , mPathgrid(NULL) , mIsExterior(0) @@ -58,6 +58,7 @@ namespace MWMechanics , mSCCId(0) , mSCCIndex(0) { + load(cell); } /* @@ -130,6 +131,11 @@ namespace MWMechanics return true; } + const ESM::Pathgrid *PathgridGraph::getPathgrid() const + { + return mPathgrid; + } + // v is the pathgrid point index (some call them vertices) void PathgridGraph::recursiveStrongConnect(int v) { diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 84b84652c..0c71c4561 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -20,10 +20,12 @@ namespace MWMechanics class PathgridGraph { public: - PathgridGraph(); + PathgridGraph(const MWWorld::CellStore* cell); bool load(const MWWorld::CellStore *cell); + const ESM::Pathgrid* getPathgrid() const; + // returns true if end point is strongly connected (i.e. reachable // from start point) both start and end are pathgrid point indexes bool isPointConnected(const int start, const int end) const; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f6e70dc94..f33c7bb67 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -445,10 +445,6 @@ namespace MWWorld loadRefs (); mState = State_Loaded; - - // TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else. - // In a simple test, loading the graph for all cells in MW + expansions took 200 ms - mPathgridGraph.load(this); } } @@ -937,21 +933,6 @@ namespace MWWorld return !(left==right); } - bool CellStore::isPointConnected(const int start, const int end) const - { - return mPathgridGraph.isPointConnected(start, end); - } - - void CellStore::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const - { - return mPathgridGraph.getNeighbouringPoints(index, nodes); - } - - std::list CellStore::aStarSearch(const int start, const int end) const - { - return mPathgridGraph.aStarSearch(start, end); - } - void CellStore::setFog(ESM::FogState *fog) { mFogState.reset(fog); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2f6277aec..dd54bdd6a 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -32,13 +32,12 @@ #include #include -#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld - #include "timestamp.hpp" #include "ptr.hpp" namespace ESM { + struct Cell; struct CellState; struct FogState; struct CellId; @@ -376,11 +375,6 @@ namespace MWWorld void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. - bool isPointConnected(const int start, const int end) const; - void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const; - - std::list aStarSearch(const int start, const int end) const; - private: /// Run through references and store IDs @@ -392,8 +386,6 @@ namespace MWWorld ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. - - MWMechanics::PathgridGraph mPathgridGraph; }; template<> From f7f8dfaf2aaf541983e193c0e2f8dfff75256aa7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 18:03:13 +0400 Subject: [PATCH 57/67] AiWander: do not allow flying/swimming creatures to use pathgrid --- apps/openmw/mwmechanics/aipackage.cpp | 28 +++++++++++++-------------- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 16 +++++++++++++-- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 198c8fc4b..398e84448 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -101,8 +101,17 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr { bool wasShortcutting = mIsShortcutting; bool destInLOS = false; - if (getTypeId() != TypeIdWander) // prohibit shortcuts for AiWander - mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first + + const MWWorld::Class& actorClass = actor.getClass(); + MWBase::World* world = MWBase::Environment::get().getWorld(); + + // check if actor can move along z-axis + bool actorCanMoveByZ = (actorClass.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || world->isFlying(actor); + + // Prohibit shortcuts for AiWander, if the actor can not move in 3 dimensions. + if (actorCanMoveByZ || getTypeId() != TypeIdWander) + mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS, actorCanMoveByZ); // try to shortcut first if (!mIsShortcutting) { @@ -235,20 +244,9 @@ const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const return *cache[id].get(); } -bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS) +bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear) { - const MWWorld::Class& actorClass = actor.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - - // check if actor can move along z-axis - bool actorCanMoveByZ = (actorClass.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) - || world->isFlying(actor); - - // don't use pathgrid when actor can move in 3 dimensions - bool isPathClear = actorCanMoveByZ; - - if (!isPathClear - && (!mShortcutProhibited || (PathFinder::MakeOsgVec3(mShortcutFailPos) - PathFinder::MakeOsgVec3(startPoint)).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) + if (!mShortcutProhibited || (PathFinder::MakeOsgVec3(mShortcutFailPos) - PathFinder::MakeOsgVec3(startPoint)).length() >= PATHFIND_SHORTCUT_RETRY_DIST) { // check if target is clearly visible isPathClear = !MWBase::Environment::get().getWorld()->castRay( diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index a9c69ad7f..06b4adf61 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -111,7 +111,7 @@ namespace MWMechanics /// If a shortcut is possible then path will be cleared and filled with the destination point. /// \param destInLOS If not NULL function will return ray cast check result /// \return If can shortcut the path - bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS); + bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear); /// Check if the way to the destination is clear, taking into account actor speed bool checkWayIsClearForActor(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7bdb3a11d..8199170dc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -265,9 +265,20 @@ namespace MWMechanics getAllowedNodes(actor, currentCell->getCell(), storage); } + bool actorCanMoveByZ = (actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || MWBase::Environment::get().getWorld()->isFlying(actor); + + if(actorCanMoveByZ && mDistance > 0) { + // Typically want to idle for a short time before the next wander + if (Misc::Rng::rollDice(100) >= 92 && storage.mState != Wander_Walking) { + wanderNearStart(actor, storage, mDistance); + } + + storage.mCanWanderAlongPathGrid = false; + } // If the package has a wander distance but no pathgrid is available, // randomly idle or wander near spawn point - if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) { + else if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) { // Typically want to idle for a short time before the next wander if (Misc::Rng::rollDice(100) >= 96) { wanderNearStart(actor, storage, mDistance); @@ -373,7 +384,7 @@ namespace MWMechanics do { // Determine a random location within radius of original position const float pi = 3.14159265359f; - const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance; + const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi; const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection); const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection); @@ -661,6 +672,7 @@ namespace MWMechanics { unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size()); ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]); + ToWorldCoordinates(dest, storage.mCell->getCell()); // actor position is already in world coordinates From b9d9660efdca3f51c043eec2284b7ebf4ca84ee4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 20:49:48 +0400 Subject: [PATCH 58/67] Update music state in the menu mode (bug #3664) --- apps/openmw/mwmechanics/actors.cpp | 61 ++++++++++++++++++++---------- apps/openmw/mwmechanics/actors.hpp | 3 ++ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ea34881fa..20955f22a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1148,6 +1148,46 @@ namespace MWMechanics } } + void Actors::updateCombatMusic () + { + MWWorld::Ptr player = getPlayer(); + int hostilesCount = 0; // need to know this to play Battle music + + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + { + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) + { + bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() + <= sqrAiProcessingDistance; + + if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) + { + if (iter->first != player) + { + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; + } + } + } + } + + // check if we still have any player enemies to switch music + static int currentMusic = 0; + + if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && + MWBase::Environment::get().getSoundManager()->isMusicPlaying())) + { + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); + currentMusic = 1; + } + else if (currentMusic != 2 && hostilesCount > 0) + { + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); + currentMusic = 2; + } + + } + void Actors::update (float duration, bool paused) { if(!paused) @@ -1165,8 +1205,6 @@ namespace MWMechanics MWWorld::Ptr player = getPlayer(); - int hostilesCount = 0; // need to know this to play Battle music - /// \todo move update logic to Actor class where appropriate std::map > cachedAllies; // will be filled as engageCombat iterates @@ -1257,8 +1295,6 @@ namespace MWMechanics CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), iter->second->getAiState(), duration); - - if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; } } @@ -1331,21 +1367,6 @@ namespace MWMechanics killDeadActors(); - // check if we still have any player enemies to switch music - static int currentMusic = 0; - - if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && - MWBase::Environment::get().getSoundManager()->isMusicPlaying())) - { - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - currentMusic = 1; - } - else if (currentMusic != 2 && hostilesCount > 0) - { - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); - currentMusic = 2; - } - static float sneakTimer = 0.f; // times update of sneak icon // if player is in sneak state see if anyone detects him @@ -1412,6 +1433,8 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); } } + + updateCombatMusic(); } void Actors::killDeadActors() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 7ed89d0e4..13641abf4 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -81,6 +81,9 @@ namespace MWMechanics void dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore); ///< Deregister all actors (except for \a ignore) in the given cell. + void updateCombatMusic(); + ///< Update combat music state + void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement From dab72b45db77e9fbbb6f51d64ac61f38c9f734bb Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Tue, 28 Nov 2017 23:14:57 +0100 Subject: [PATCH 59/67] Move mana reducing code back --- apps/openmw/mwmechanics/spellcasting.cpp | 5 ----- apps/openmw/mwworld/worldimp.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 19afc11ec..5cab750db 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -889,11 +889,6 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } - - // Reduce mana - MWMechanics::DynamicStat magicka = stats.getMagicka(); - magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); - stats.setMagicka(magicka); } if (fail) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 83971eadf..9c7fba9fa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2718,6 +2718,13 @@ namespace MWWorld message = "#{sPowerAlreadyUsed}"; fail = true; } + + // Reduce mana + if (!fail && !godmode) + { + magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); + stats.setMagicka(magicka); + } } if (isPlayer && fail) From 9fe5a4d236d5f3e5d3f3214be6beb2e400b9e43e Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Tue, 28 Nov 2017 17:04:37 +0100 Subject: [PATCH 60/67] Revert condition changes --- apps/openmw/mwmechanics/spellcasting.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5cab750db..63fe3fa3c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -126,10 +126,7 @@ namespace MWMechanics float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; castChance *= stats.getFatigueTerm(); - if (godmode) - return 100; - - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) return 0; if (spell->mData.mType == ESM::Spell::ST_Power) @@ -138,12 +135,17 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (stats.getMagicka().getCurrent() < spell->mData.mCost) + if (stats.getMagicka().getCurrent() < spell->mData.mCost && !godmode) return 0; if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; + if (godmode) + { + return 100; + } + if (!cap) return std::max(0.f, castChance); else From 2abb1a2ec27c35cbef25ae031a50e46dd5c0caea Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Tue, 28 Nov 2017 23:10:07 +0100 Subject: [PATCH 61/67] Added checkMagicka parameter --- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 8 ++++---- apps/openmw/mwmechanics/spellcasting.hpp | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 6953d682b..f83b72096 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -60,7 +60,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor))); + std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor, NULL, true, true))); newSpell.mCostColumn = cost + "/" + chance; } else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 63fe3fa3c..8fbf67535 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -115,7 +115,7 @@ namespace MWMechanics return castChance; } - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka) { bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); @@ -135,7 +135,7 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (stats.getMagicka().getCurrent() < spell->mData.mCost && !godmode) + if (checkMagicka && stats.getMagicka().getCurrent() < spell->mData.mCost && !godmode) return 0; if (spell->mData.mFlags & ESM::Spell::F_Always) @@ -152,11 +152,11 @@ namespace MWMechanics return std::max(0.f, std::min(100.f, castChance)); } - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka) { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - return getSpellSuccessChance(spell, actor, effectiveSchool, cap); + return getSpellSuccessChance(spell, actor, effectiveSchool, cap, checkMagicka); } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2e368afcf..1f5ef45bd 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -31,11 +31,12 @@ namespace MWMechanics * @param actor calculate spell success chance for this actor (depends on actor's skills) * @param effectiveSchool the spell's effective school (relevant for skill progress) will be written here * @param cap cap the result to 100%? + * @param checkMagicka check magicka? * @note actor can be an NPC or a creature * @return success chance from 0 to 100 (in percent), if cap=false then chance above 100 may be returned. */ - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true); - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true); + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true, bool checkMagicka=false); + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true, bool checkMagicka=false); int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor); int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); From bb7ca055d03345d9ed961ece215e8eee5fc67103 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 29 Nov 2017 22:13:42 +0000 Subject: [PATCH 62/67] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index c4190343d..155d017f3 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -153,6 +153,7 @@ Programmers Sylvain Thesnieres (Garvek) t6 terrorfisch + thegriglat Thomas Luppi (Digmaster) Will Herrmann (Thunderforge) Tom Mason (wheybags) From 50deed126b0d63a65423b1648c454e5d94b3e40f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 2 Dec 2017 21:48:57 +0100 Subject: [PATCH 63/67] Update SDL to 2.0.7 --- CI/before_script.msvc.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 9f6051863..ee48c1f68 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -350,9 +350,9 @@ if [ -z $SKIP_DOWNLOAD ]; then fi # SDL2 - download "SDL 2.0.4" \ - "https://www.libsdl.org/release/SDL2-devel-2.0.4-VC.zip" \ - "SDL2-2.0.4.zip" + download "SDL 2.0.7" \ + "https://www.libsdl.org/release/SDL2-devel-2.0.7-VC.zip" \ + "SDL2-2.0.7.zip" fi cd .. #/.. @@ -632,18 +632,18 @@ cd $DEPS echo # SDL2 -printf "SDL 2.0.4... " +printf "SDL 2.0.7... " { - if [ -d SDL2-2.0.4 ]; then + if [ -d SDL2-2.0.7 ]; then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then - rm -rf SDL2-2.0.4 - eval 7z x -y SDL2-2.0.4.zip $STRIP + rm -rf SDL2-2.0.7 + eval 7z x -y SDL2-2.0.7.zip $STRIP fi - export SDL2DIR="$(real_pwd)/SDL2-2.0.4" + export SDL2DIR="$(real_pwd)/SDL2-2.0.7" - add_runtime_dlls "$(pwd)/SDL2-2.0.4/lib/x${ARCHSUFFIX}/SDL2.dll" + add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll" echo Done. } From 8decd356079a13dcd0f4b18dec2ca6acffaf907a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 3 Dec 2017 21:49:13 +0400 Subject: [PATCH 64/67] Fixes crash on quickload from the container menu (bug #4239) --- apps/openmw/mwgui/container.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 444eaff85..9222f1d02 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -154,7 +154,8 @@ namespace MWGui { WindowBase::onClose(); - mModel->onClose(); + if (mModel) + mModel->onClose(); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) From 441420225f47fb7af3555c45fcf19f614b6c8d8f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 4 Dec 2017 17:00:02 +0000 Subject: [PATCH 65/67] Contributing.md: referencing issues in commit messages --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b5a7423d2..6c82d1dfd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,7 @@ Furthermore, we advise to: * Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. * If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). * Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway. +* Reference the bug / feature ticket(s) in your commit message (e.g. 'Bug #123') to make it easier to keep track of what we changed for what reason. Our bugtracker will show those commits next to the ticket. If your commit message includes 'Fixes #123', that bug/feature will automatically be set to 'Closed' when your commit is merged. Guidelines for original engine "fixes" ================================= From b6ae7f3cc8106fb9b1c1b7791ad243e36fd06ddd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 4 Dec 2017 22:01:57 +0400 Subject: [PATCH 66/67] Do not add greetings to the journal index (bug #4342) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1f6de04e5..de9ca83ca 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -146,7 +146,6 @@ namespace MWDialogue // TODO play sound } - MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); callback->addResponse("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); @@ -387,7 +386,7 @@ namespace MWDialogue { Filter filter (mActor, mChoice, mTalkedTo); - if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) + if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) { if (const ESM::DialInfo *info = filter.search (*dialogue, true)) { @@ -401,15 +400,18 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); callback->addResponse("", Interpreter::fixDefinesDialog(text, interpreterContext)); - // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, - // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); - iter!=dialogue->mInfo.end(); ++iter) + if (dialogue->mType == ESM::Dialogue::Topic) { - if (iter->mId == info->mId) + // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, + // in which case it should not be added to the journal + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); + iter!=dialogue->mInfo.end(); ++iter) { - MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); - break; + if (iter->mId == info->mId) + { + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); + break; + } } } From 29b2308b2c64510e787a526793abe65065624bb6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 4 Dec 2017 22:10:22 +0400 Subject: [PATCH 67/67] Do not display cyrillic soft/hard signs in the journal index --- apps/openmw/mwgui/journalbooks.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index f3ee8162e..e8aa23158 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -281,6 +281,8 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () textColours.journalTopicOver, textColours.journalTopicPressed, first); + ch[1]++; + // Words can not be started with these characters if (i == 26 || i == 28) continue; @@ -290,8 +292,6 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); - - ch[1]++; } return typesetter;