mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-01 16:06:41 +00:00
Update to upstream/master. Resolve merge conflicts
This commit is contained in:
commit
03c2e11961
150 changed files with 3970 additions and 2477 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -41,7 +41,6 @@ resources
|
||||||
|
|
||||||
## generated objects
|
## generated objects
|
||||||
apps/openmw/config.hpp
|
apps/openmw/config.hpp
|
||||||
components/version/version.hpp
|
|
||||||
docs/mainpage.hpp
|
docs/mainpage.hpp
|
||||||
moc_*.cxx
|
moc_*.cxx
|
||||||
*.cxx_parameters
|
*.cxx_parameters
|
||||||
|
|
|
@ -18,8 +18,8 @@ addons:
|
||||||
name: "OpenMW/openmw"
|
name: "OpenMW/openmw"
|
||||||
description: "<Your project description here>"
|
description: "<Your project description here>"
|
||||||
notification_email: scrawl@baseoftrash.de
|
notification_email: scrawl@baseoftrash.de
|
||||||
build_command_prepend: "cmake ."
|
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE"
|
||||||
build_command: "make -j3"
|
build_command: "make"
|
||||||
branch_pattern: coverity_scan
|
branch_pattern: coverity_scan
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
|
|
@ -52,6 +52,7 @@ Programmers
|
||||||
jeaye
|
jeaye
|
||||||
Jeffrey Haines (Jyby)
|
Jeffrey Haines (Jyby)
|
||||||
Jengerer
|
Jengerer
|
||||||
|
Jiří Kuneš (kunesj)
|
||||||
Joel Graff (graffy)
|
Joel Graff (graffy)
|
||||||
John Blomberg (fstp)
|
John Blomberg (fstp)
|
||||||
Jordan Ayers
|
Jordan Ayers
|
||||||
|
@ -59,6 +60,7 @@ Programmers
|
||||||
Julien Voisin (jvoisin/ap0)
|
Julien Voisin (jvoisin/ap0)
|
||||||
Karl-Felix Glatzer (k1ll)
|
Karl-Felix Glatzer (k1ll)
|
||||||
Kevin Poitra (PuppyKevin)
|
Kevin Poitra (PuppyKevin)
|
||||||
|
Koncord
|
||||||
Lars Söderberg (Lazaroth)
|
Lars Söderberg (Lazaroth)
|
||||||
lazydev
|
lazydev
|
||||||
Leon Saunders (emoose)
|
Leon Saunders (emoose)
|
||||||
|
@ -86,6 +88,7 @@ Programmers
|
||||||
Nolan Poe (nopoe)
|
Nolan Poe (nopoe)
|
||||||
Paul McElroy (Greendogo)
|
Paul McElroy (Greendogo)
|
||||||
Pieter van der Kloet (pvdk)
|
Pieter van der Kloet (pvdk)
|
||||||
|
pkubik
|
||||||
Radu-Marius Popovici (rpopovici)
|
Radu-Marius Popovici (rpopovici)
|
||||||
rdimesio
|
rdimesio
|
||||||
riothamus
|
riothamus
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
0.36.1
|
||||||
|
------
|
||||||
|
|
||||||
|
Bug #2590: Start scripts not added correctly
|
||||||
|
|
||||||
0.36.0
|
0.36.0
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,10 @@ fi
|
||||||
|
|
||||||
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||||
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||||
|
echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa
|
||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
sudo apt-get install -qq libgtest-dev google-mock
|
sudo apt-get install -qq libgtest-dev google-mock
|
||||||
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev
|
sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev
|
||||||
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
|
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
|
||||||
sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
||||||
sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04
|
sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04
|
||||||
|
|
|
@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 36)
|
set(OPENMW_VERSION_MINOR 36)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 1)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
set(OPENMW_VERSION_TAGHASH "")
|
set(OPENMW_VERSION_TAGHASH "")
|
||||||
|
@ -56,6 +56,8 @@ configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_
|
||||||
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
|
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
|
||||||
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||||
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
||||||
|
option(OSG_STATIC "Link static build of OpenSceneGraph into the binaries" FALSE)
|
||||||
|
option(QT_STATIC "Link static build of QT into the binaries" FALSE)
|
||||||
|
|
||||||
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
||||||
|
|
||||||
|
@ -199,9 +201,67 @@ IF(BOOST_STATIC)
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX)
|
find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX)
|
||||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
if(OSG_STATIC)
|
||||||
|
macro(use_static_osg_plugin_library PLUGIN_NAME)
|
||||||
|
set(PLUGIN_NAME_DBG ${PLUGIN_NAME}d ${PLUGIN_NAME}D ${PLUGIN_NAME}_d ${PLUGIN_NAME}_D ${PLUGIN_NAME}_debug ${PLUGIN_NAME})
|
||||||
|
|
||||||
|
# For now, users wishing to do a static build will need to pass the path to where the plugins reside
|
||||||
|
# More clever logic would need to deduce the path, probably installed under <OpenSceneGraph>/lib/osgPlugins-<X.X.X>
|
||||||
|
find_library(${PLUGIN_NAME}_LIBRARY_REL NAMES ${PLUGIN_NAME} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH})
|
||||||
|
find_library(${PLUGIN_NAME}_LIBRARY_DBG NAMES ${PLUGIN_NAME_DBG} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH})
|
||||||
|
make_library_set(${PLUGIN_NAME}_LIBRARY)
|
||||||
|
|
||||||
|
if("${${PLUGIN_NAME}_LIBRARY}" STREQUAL "")
|
||||||
|
message(FATAL_ERROR "Unable to find static OpenSceneGraph plugin: ${PLUGIN_NAME}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${PLUGIN_NAME}_LIBRARY})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(use_static_osg_plugin_dep DEPENDENCY)
|
||||||
|
find_package(${DEPENDENCY} REQUIRED)
|
||||||
|
|
||||||
|
set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${DEPENDENCY}_LIBRARIES})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
add_definitions(-DOSG_LIBRARY_STATIC)
|
||||||
|
|
||||||
|
set(PLUGIN_LIST
|
||||||
|
osgdb_png # depends on libpng, zlib
|
||||||
|
osgdb_tga
|
||||||
|
osgdb_dds
|
||||||
|
osgdb_jpeg # depends on libjpeg
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(PLUGIN ${PLUGIN_LIST})
|
||||||
|
use_static_osg_plugin_library(${PLUGIN})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# OSG static plugins need to linked against their respective dependencies
|
||||||
|
set(PLUGIN_DEPS_LIST
|
||||||
|
PNG # needed by osgdb_png
|
||||||
|
ZLIB # needed by osgdb_png
|
||||||
|
JPEG # needed by osgdb_jpeg
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(DEPENDENCY ${PLUGIN_DEPS_LIST})
|
||||||
|
use_static_osg_plugin_dep(${DEPENDENCY})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QT_STATIC)
|
||||||
|
if(WIN32)
|
||||||
|
if(DESIRED_QT_VERSION MATCHES 4)
|
||||||
|
# QtCore needs WSAAsyncSelect from Ws2_32.lib
|
||||||
|
set(QT_QTCORE_LIBRARY ${QT_QTCORE_LIBRARY} Ws2_32.lib)
|
||||||
|
message("QT_QTCORE_LIBRARY: ${QT_QTCORE_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(MyGUI REQUIRED)
|
find_package(MyGUI REQUIRED)
|
||||||
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
|
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
|
||||||
message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info")
|
message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info")
|
||||||
|
@ -366,6 +426,7 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
# Install global configuration files
|
# Install global configuration files
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
|
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
|
@ -381,6 +442,7 @@ if(WIN32)
|
||||||
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
|
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
|
||||||
INSTALL(FILES ${dll_files} DESTINATION ".")
|
INSTALL(FILES ${dll_files} DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
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}/README.md" DESTINATION "." RENAME "README.txt")
|
||||||
INSTALL(FILES
|
INSTALL(FILES
|
||||||
|
|
14
README.md
14
README.md
|
@ -3,10 +3,11 @@ OpenMW
|
||||||
|
|
||||||
[](https://travis-ci.org/OpenMW/openmw) [](https://scan.coverity.com/projects/3740)
|
[](https://travis-ci.org/OpenMW/openmw) [](https://scan.coverity.com/projects/3740)
|
||||||
|
|
||||||
OpenMW is an attempt at recreating the engine for the popular role-playing game
|
OpenMW is a recreation of the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
|
||||||
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
|
|
||||||
|
|
||||||
* Version: 0.36.0
|
OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set.
|
||||||
|
|
||||||
|
* Version: 0.36.1
|
||||||
* License: GPL (see docs/license/GPL3.txt for more information)
|
* License: GPL (see docs/license/GPL3.txt for more information)
|
||||||
* Website: http://www.openmw.org
|
* Website: http://www.openmw.org
|
||||||
* IRC: #openmw on irc.freenode.net
|
* IRC: #openmw on irc.freenode.net
|
||||||
|
@ -14,6 +15,13 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f
|
||||||
Font Licenses:
|
Font Licenses:
|
||||||
* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information)
|
* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information)
|
||||||
|
|
||||||
|
Current Status
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/versions/21) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces.
|
||||||
|
|
||||||
|
Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page.
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "convertplayer.hpp"
|
#include "convertplayer.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,9 @@ namespace ESSImport
|
||||||
|
|
||||||
if (i >= file2.mRecords.size())
|
if (i >= file2.mRecords.size())
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl;
|
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +176,9 @@ namespace ESSImport
|
||||||
|
|
||||||
if (rec.mName != rec2.mName)
|
if (rec.mName != rec2.mName)
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl;
|
std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
return; // TODO: try to recover
|
return; // TODO: try to recover
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +189,9 @@ namespace ESSImport
|
||||||
|
|
||||||
if (j >= rec2.mSubrecords.size())
|
if (j >= rec2.mSubrecords.size())
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
|
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,8 +199,10 @@ namespace ESSImport
|
||||||
|
|
||||||
if (sub.mName != sub2.mName)
|
if (sub.mName != sub2.mName)
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset
|
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset
|
||||||
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
break; // TODO: try to recover
|
break; // TODO: try to recover
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +211,8 @@ namespace ESSImport
|
||||||
if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end())
|
if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
|
|
||||||
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset
|
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset
|
||||||
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||||
|
|
||||||
|
@ -235,6 +245,7 @@ namespace ESSImport
|
||||||
std::cout << "\033[0m";
|
std::cout << "\033[0m";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,7 +330,11 @@ namespace ESSImport
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (unknownRecords.insert(n.val).second)
|
if (unknownRecords.insert(n.val).second)
|
||||||
|
{
|
||||||
|
std::ios::fmtflags f(std::cerr.flags());
|
||||||
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
||||||
|
std::cerr.flags(f);
|
||||||
|
}
|
||||||
|
|
||||||
esm.skipRecord();
|
esm.skipRecord();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,10 @@ namespace ESSImport
|
||||||
std::map<std::string, ESM::NPC> mNpcs;
|
std::map<std::string, ESM::NPC> mNpcs;
|
||||||
|
|
||||||
Context()
|
Context()
|
||||||
|
: mDay(0)
|
||||||
|
, mMonth(0)
|
||||||
|
, mYear(0)
|
||||||
|
, mHour(0.f)
|
||||||
{
|
{
|
||||||
mPlayer.mAutoMove = 0;
|
mPlayer.mAutoMove = 0;
|
||||||
ESM::CellId playerCellId;
|
ESM::CellId playerCellId;
|
||||||
|
|
|
@ -57,26 +57,6 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
// Remove what's this? button
|
// Remove what's this? button
|
||||||
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
// Add version information to bottom of the window
|
|
||||||
QString revision(OPENMW_VERSION_COMMITHASH);
|
|
||||||
QString tag(OPENMW_VERSION_TAGHASH);
|
|
||||||
|
|
||||||
versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
||||||
if (!revision.isEmpty() && !tag.isEmpty())
|
|
||||||
{
|
|
||||||
if (revision == tag) {
|
|
||||||
versionLabel->setText(tr("OpenMW %1 release").arg(OPENMW_VERSION));
|
|
||||||
} else {
|
|
||||||
versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the compile date and time
|
|
||||||
versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
|
||||||
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
|
||||||
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
|
||||||
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
|
||||||
}
|
|
||||||
|
|
||||||
createIcons();
|
createIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,11 +166,38 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||||
return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure;
|
return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Launcher::MainDialog::setVersionLabel()
|
||||||
|
{
|
||||||
|
// Add version information to bottom of the window
|
||||||
|
Version::Version v = Version::getOpenmwVersion(mGameSettings.value("resources").toUtf8().constData());
|
||||||
|
|
||||||
|
QString revision(QString::fromUtf8(v.mCommitHash.c_str()));
|
||||||
|
QString tag(QString::fromUtf8(v.mTagHash.c_str()));
|
||||||
|
|
||||||
|
versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
if (!revision.isEmpty() && !tag.isEmpty())
|
||||||
|
{
|
||||||
|
if (revision == tag) {
|
||||||
|
versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str())));
|
||||||
|
} else {
|
||||||
|
versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the compile date and time
|
||||||
|
versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
||||||
|
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
||||||
|
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
||||||
|
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Launcher::MainDialog::setup()
|
bool Launcher::MainDialog::setup()
|
||||||
{
|
{
|
||||||
if (!setupGameSettings())
|
if (!setupGameSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
setVersionLabel();
|
||||||
|
|
||||||
mLauncherSettings.setContentList(mGameSettings);
|
mLauncherSettings.setContentList(mGameSettings);
|
||||||
|
|
||||||
if (!setupGraphicsSettings())
|
if (!setupGraphicsSettings())
|
||||||
|
@ -309,11 +316,11 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
mGameSettings.readUserFile(stream);
|
mGameSettings.readUserFile(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now the rest
|
// Now the rest - priority: user > local > global
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
paths.append(userPath + QString("openmw.cfg"));
|
|
||||||
paths.append(QString("openmw.cfg"));
|
|
||||||
paths.append(globalPath + QString("openmw.cfg"));
|
paths.append(globalPath + QString("openmw.cfg"));
|
||||||
|
paths.append(QString("openmw.cfg"));
|
||||||
|
paths.append(userPath + QString("openmw.cfg"));
|
||||||
|
|
||||||
foreach (const QString &path, paths) {
|
foreach (const QString &path, paths) {
|
||||||
qDebug() << "Loading config file:" << qPrintable(path);
|
qDebug() << "Loading config file:" << qPrintable(path);
|
||||||
|
|
|
@ -72,6 +72,8 @@ namespace Launcher
|
||||||
bool setupGameSettings();
|
bool setupGameSettings();
|
||||||
bool setupGraphicsSettings();
|
bool setupGraphicsSettings();
|
||||||
|
|
||||||
|
void setVersionLabel();
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ opencs_units (view/world
|
||||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||||
cellcreator referenceablecreator referencecreator scenesubview
|
cellcreator referenceablecreator referencecreator scenesubview
|
||||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||||
dialoguespinbox recordbuttonbar tableeditidaction extendedcommandconfigurator
|
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
|
|
|
@ -798,9 +798,9 @@ void CSMDoc::Document::addGmsts()
|
||||||
"sBookSkillMessage",
|
"sBookSkillMessage",
|
||||||
"sBounty",
|
"sBounty",
|
||||||
"sBreath",
|
"sBreath",
|
||||||
"sBribe",
|
"sBribe 10 Gold",
|
||||||
"sBribe",
|
"sBribe 100 Gold",
|
||||||
"sBribe",
|
"sBribe 1000 Gold",
|
||||||
"sBribeFail",
|
"sBribeFail",
|
||||||
"sBribeSuccess",
|
"sBribeSuccess",
|
||||||
"sBuy",
|
"sBuy",
|
||||||
|
|
|
@ -8,6 +8,20 @@ CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& me
|
||||||
: mId (id), mMessage (message), mHint (hint), mSeverity (severity)
|
: mId (id), mMessage (message), mHint (hint), mSeverity (severity)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
std::string CSMDoc::Message::toString (Severity severity)
|
||||||
|
{
|
||||||
|
switch (severity)
|
||||||
|
{
|
||||||
|
case CSMDoc::Message::Severity_Info: return "Information";
|
||||||
|
case CSMDoc::Message::Severity_Warning: return "Warning";
|
||||||
|
case CSMDoc::Message::Severity_Error: return "Error";
|
||||||
|
case CSMDoc::Message::Severity_SeriousError: return "Serious Error";
|
||||||
|
case CSMDoc::Message::Severity_Default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CSMDoc::Messages::Messages (Message::Severity default_)
|
CSMDoc::Messages::Messages (Message::Severity default_)
|
||||||
: mDefault (default_)
|
: mDefault (default_)
|
||||||
|
@ -18,7 +32,7 @@ void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string&
|
||||||
{
|
{
|
||||||
if (severity==Message::Severity_Default)
|
if (severity==Message::Severity_Default)
|
||||||
severity = mDefault;
|
severity = mDefault;
|
||||||
|
|
||||||
mMessages.push_back (Message (id, message, hint, severity));
|
mMessages.push_back (Message (id, message, hint, severity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,18 +21,20 @@ namespace CSMDoc
|
||||||
// reporting it correctly
|
// reporting it correctly
|
||||||
Severity_Default = 4
|
Severity_Default = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
CSMWorld::UniversalId mId;
|
CSMWorld::UniversalId mId;
|
||||||
std::string mMessage;
|
std::string mMessage;
|
||||||
std::string mHint;
|
std::string mHint;
|
||||||
Severity mSeverity;
|
Severity mSeverity;
|
||||||
|
|
||||||
Message();
|
Message();
|
||||||
|
|
||||||
Message (const CSMWorld::UniversalId& id, const std::string& message,
|
Message (const CSMWorld::UniversalId& id, const std::string& message,
|
||||||
const std::string& hint, Severity severity);
|
const std::string& hint, Severity severity);
|
||||||
|
|
||||||
|
static std::string toString (Severity severity);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Messages
|
class Messages
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -162,7 +162,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
ritd->setDeclaredValues (values);
|
ritd->setDeclaredValues (values);
|
||||||
}
|
}
|
||||||
|
|
||||||
declareSection ("table-input", "Table Input");
|
declareSection ("table-input", "ID Tables");
|
||||||
{
|
{
|
||||||
QString inPlaceEdit ("Edit in Place");
|
QString inPlaceEdit ("Edit in Place");
|
||||||
QString editRecord ("Edit Record");
|
QString editRecord ("Edit Record");
|
||||||
|
@ -226,7 +226,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
"records are deleted/reverted immediately.");
|
"records are deleted/reverted immediately.");
|
||||||
}
|
}
|
||||||
|
|
||||||
declareSection ("report-input", "Report Input");
|
declareSection ("dialogues", "ID Dialogues");
|
||||||
|
{
|
||||||
|
Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar");
|
||||||
|
toolbar->setDefaultValue ("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
declareSection ("report-input", "Reports");
|
||||||
{
|
{
|
||||||
QString none ("None");
|
QString none ("None");
|
||||||
QString edit ("Edit");
|
QString edit ("Edit");
|
||||||
|
@ -266,7 +272,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
shiftCtrlDoubleClick->setDefaultValue (none);
|
shiftCtrlDoubleClick->setDefaultValue (none);
|
||||||
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:<p>" + toolTip);
|
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:<p>" + toolTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
declareSection ("search", "Search & Replace");
|
declareSection ("search", "Search & Replace");
|
||||||
{
|
{
|
||||||
Setting *before = createSetting (Type_SpinBox, "char-before",
|
Setting *before = createSetting (Type_SpinBox, "char-before",
|
||||||
|
@ -308,7 +314,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
|
|
||||||
QStringList modes;
|
QStringList modes;
|
||||||
modes << "Ignore" << modeNormal << "Strict";
|
modes << "Ignore" << modeNormal << "Strict";
|
||||||
|
|
||||||
Setting *warnings = createSetting (Type_ComboBox, "warnings",
|
Setting *warnings = createSetting (Type_ComboBox, "warnings",
|
||||||
"Warning Mode");
|
"Warning Mode");
|
||||||
warnings->setDeclaredValues (modes);
|
warnings->setDeclaredValues (modes);
|
||||||
|
@ -318,7 +324,16 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
"<li>Normal: Report warning as a warning</li>"
|
"<li>Normal: Report warning as a warning</li>"
|
||||||
"<li>Strict: Promote warning to an error</li>"
|
"<li>Strict: Promote warning to an error</li>"
|
||||||
"</ul>");
|
"</ul>");
|
||||||
|
|
||||||
|
Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar");
|
||||||
|
toolbar->setDefaultValue ("true");
|
||||||
|
|
||||||
|
Setting *delay = createSetting (Type_SpinBox, "compile-delay",
|
||||||
|
"Delay between updating of source errors");
|
||||||
|
delay->setDefaultValue (100);
|
||||||
|
delay->setRange (0, 10000);
|
||||||
|
delay->setToolTip ("Delay in milliseconds");
|
||||||
|
|
||||||
Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int");
|
Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int");
|
||||||
formatInt->setDefaultValues (QStringList() << "Dark magenta");
|
formatInt->setDefaultValues (QStringList() << "Dark magenta");
|
||||||
formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip);
|
formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip);
|
||||||
|
@ -355,7 +370,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
cycle->setToolTip ("When using next/previous functions at the last/first item of a "
|
cycle->setToolTip ("When using next/previous functions at the last/first item of a "
|
||||||
"list go to the first/last item");
|
"list go to the first/last item");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* There are three types of values:
|
* There are three types of values:
|
||||||
|
|
|
@ -13,7 +13,7 @@ CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn)
|
||||||
|
|
||||||
if (severityColumn)
|
if (severityColumn)
|
||||||
mColumnSeverity = index++;
|
mColumnSeverity = index++;
|
||||||
|
|
||||||
if (fieldColumn)
|
if (fieldColumn)
|
||||||
mColumnField = index++;
|
mColumnField = index++;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
|
||||||
case Column_Type:
|
case Column_Type:
|
||||||
|
|
||||||
return static_cast<int> (mRows.at (index.row()).mId.getType());
|
return static_cast<int> (mRows.at (index.row()).mId.getType());
|
||||||
|
|
||||||
case Column_Id:
|
case Column_Id:
|
||||||
{
|
{
|
||||||
CSMWorld::UniversalId id = mRows.at (index.row()).mId;
|
CSMWorld::UniversalId id = mRows.at (index.row()).mId;
|
||||||
|
@ -56,7 +56,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
|
||||||
|
|
||||||
return QString ("-");
|
return QString ("-");
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column_Hint:
|
case Column_Hint:
|
||||||
|
|
||||||
return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str());
|
return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str());
|
||||||
|
@ -85,16 +85,10 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
|
||||||
|
|
||||||
if (index.column()==mColumnSeverity)
|
if (index.column()==mColumnSeverity)
|
||||||
{
|
{
|
||||||
switch (mRows.at (index.row()).mSeverity)
|
return QString::fromUtf8 (
|
||||||
{
|
CSMDoc::Message::toString (mRows.at (index.row()).mSeverity).c_str());
|
||||||
case CSMDoc::Message::Severity_Info: return "Information";
|
|
||||||
case CSMDoc::Message::Severity_Warning: return "Warning";
|
|
||||||
case CSMDoc::Message::Severity_Error: return "Error";
|
|
||||||
case CSMDoc::Message::Severity_SeriousError: return "Serious Error";
|
|
||||||
case CSMDoc::Message::Severity_Default: break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +138,7 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
|
||||||
void CSMTools::ReportModel::add (const CSMDoc::Message& message)
|
void CSMTools::ReportModel::add (const CSMDoc::Message& message)
|
||||||
{
|
{
|
||||||
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
|
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
|
||||||
|
|
||||||
mRows.push_back (message);
|
mRows.push_back (message);
|
||||||
|
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
|
|
@ -62,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
|
||||||
|
|
||||||
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager)
|
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager)
|
||||||
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
|
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
|
||||||
mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS())
|
mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS()))
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
|
@ -537,14 +537,14 @@ CSMWorld::Data::~Data()
|
||||||
delete mReader;
|
delete mReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource::ResourceSystem* CSMWorld::Data::getResourceSystem()
|
boost::shared_ptr<Resource::ResourceSystem> CSMWorld::Data::getResourceSystem()
|
||||||
{
|
{
|
||||||
return &mResourceSystem;
|
return mResourceSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const
|
boost::shared_ptr<const Resource::ResourceSystem> CSMWorld::Data::getResourceSystem() const
|
||||||
{
|
{
|
||||||
return &mResourceSystem;
|
return mResourceSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
|
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace CSMWorld
|
||||||
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
|
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
|
||||||
int mReaderIndex;
|
int mReaderIndex;
|
||||||
|
|
||||||
Resource::ResourceSystem mResourceSystem;
|
boost::shared_ptr<Resource::ResourceSystem> mResourceSystem;
|
||||||
|
|
||||||
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
|
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
|
||||||
|
|
||||||
|
@ -138,9 +138,9 @@ namespace CSMWorld
|
||||||
|
|
||||||
const VFS::Manager* getVFS() const;
|
const VFS::Manager* getVFS() const;
|
||||||
|
|
||||||
Resource::ResourceSystem* getResourceSystem();
|
boost::shared_ptr<Resource::ResourceSystem> getResourceSystem();
|
||||||
|
|
||||||
const Resource::ResourceSystem* getResourceSystem() const;
|
boost::shared_ptr<const Resource::ResourceSystem> getResourceSystem() const;
|
||||||
|
|
||||||
const IdCollection<ESM::Global>& getGlobals() const;
|
const IdCollection<ESM::Global>& getGlobals() const;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,24 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i
|
||||||
return mapFromSource (dynamic_cast<IdTableBase&> (*sourceModel()).getModelIndex (id, column));
|
return mapFromSource (dynamic_cast<IdTableBase&> (*sourceModel()).getModelIndex (id, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model)
|
||||||
|
{
|
||||||
|
QSortFilterProxyModel::setSourceModel(model);
|
||||||
|
|
||||||
|
connect(sourceModel(),
|
||||||
|
SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
|
||||||
|
this,
|
||||||
|
SLOT(sourceRowsChanged(const QModelIndex &, int, int)));
|
||||||
|
connect(sourceModel(),
|
||||||
|
SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||||
|
this,
|
||||||
|
SLOT(sourceRowsChanged(const QModelIndex &, int, int)));
|
||||||
|
connect(sourceModel(),
|
||||||
|
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
|
||||||
|
this,
|
||||||
|
SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter)
|
void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
@ -60,6 +78,20 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::
|
||||||
|
|
||||||
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
{
|
{
|
||||||
|
Columns::ColumnId id = static_cast<Columns::ColumnId>(left.data(ColumnBase::Role_ColumnId).toInt());
|
||||||
|
EnumColumnCache::const_iterator valuesIt = mEnumColumnCache.find(id);
|
||||||
|
if (valuesIt == mEnumColumnCache.end())
|
||||||
|
{
|
||||||
|
if (Columns::hasEnums(id))
|
||||||
|
{
|
||||||
|
valuesIt = mEnumColumnCache.insert(std::make_pair(id, Columns::getEnums(id))).first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valuesIt != mEnumColumnCache.end())
|
||||||
|
{
|
||||||
|
return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()];
|
||||||
|
}
|
||||||
return QSortFilterProxyModel::lessThan(left, right);
|
return QSortFilterProxyModel::lessThan(left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,3 +100,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter()
|
||||||
updateColumnMap();
|
updateColumnMap();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
|
||||||
|
{
|
||||||
|
refreshFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::IdTableProxyModel::sourceDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/)
|
||||||
|
{
|
||||||
|
refreshFilter();
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "../filter/node.hpp"
|
#include "../filter/node.hpp"
|
||||||
|
|
||||||
|
#include "columns.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
class IdTableProxyModel : public QSortFilterProxyModel
|
class IdTableProxyModel : public QSortFilterProxyModel
|
||||||
|
@ -20,6 +22,11 @@ namespace CSMWorld
|
||||||
boost::shared_ptr<CSMFilter::Node> mFilter;
|
boost::shared_ptr<CSMFilter::Node> mFilter;
|
||||||
std::map<int, int> mColumnMap; // column ID, column index in this model (or -1)
|
std::map<int, int> mColumnMap; // column ID, column index in this model (or -1)
|
||||||
|
|
||||||
|
// Cache of enum values for enum columns (e.g. Modified, Record Type).
|
||||||
|
// Used to speed up comparisons during the sort by such columns.
|
||||||
|
typedef std::map<Columns::ColumnId, std::vector<std::string> > EnumColumnCache;
|
||||||
|
mutable EnumColumnCache mEnumColumnCache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void updateColumnMap();
|
void updateColumnMap();
|
||||||
|
@ -30,6 +37,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
|
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
|
||||||
|
|
||||||
|
virtual void setSourceModel(QAbstractItemModel *model);
|
||||||
|
|
||||||
void setFilter (const boost::shared_ptr<CSMFilter::Node>& filter);
|
void setFilter (const boost::shared_ptr<CSMFilter::Node>& filter);
|
||||||
|
|
||||||
void refreshFilter();
|
void refreshFilter();
|
||||||
|
@ -39,6 +48,12 @@ namespace CSMWorld
|
||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||||
|
|
||||||
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
|
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void sourceRowsChanged(const QModelIndex &parent, int start, int end);
|
||||||
|
|
||||||
|
void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,10 +171,10 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par
|
||||||
encodedId = this->foldIndexAddress(parent);
|
encodedId = this->foldIndexAddress(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row<0 || row>=idCollection()->getSize())
|
if (row < 0 || row >= rowCount(parent))
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
if (column<0 || column>=idCollection()->getColumns())
|
if (column < 0 || column >= columnCount(parent))
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
return createIndex(row, column, encodedId); // store internal id
|
return createIndex(row, column, encodedId); // store internal id
|
||||||
|
|
|
@ -161,8 +161,19 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
|
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
|
||||||
{
|
{
|
||||||
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getColumnsCount(
|
const ColumnBase &nestedColumn = Collection<ESXRecordT, IdAccessorT>::getColumn(column);
|
||||||
Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
int numRecords = Collection<ESXRecordT, IdAccessorT>::getSize();
|
||||||
|
if (row >= 0 && row < numRecords)
|
||||||
|
{
|
||||||
|
const Record<ESXRecordT>& record = Collection<ESXRecordT, IdAccessorT>::getRecord(row);
|
||||||
|
return getAdapter(nestedColumn).getColumnsCount(record);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the row is invalid (or there no records), retrieve the column count using a blank record
|
||||||
|
const Record<ESXRecordT> record;
|
||||||
|
return getAdapter(nestedColumn).getColumnsCount(record);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
|
|
@ -75,10 +75,10 @@ QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QM
|
||||||
{
|
{
|
||||||
assert (!parent.isValid());
|
assert (!parent.isValid());
|
||||||
|
|
||||||
int rows = mMainModel->rowCount(parent);
|
int numRows = rowCount(parent);
|
||||||
int columns = mMainModel->columnCount(parent);
|
int numColumns = columnCount(parent);
|
||||||
|
|
||||||
if (row < 0 || row >= rows || column < 0 || column >= columns)
|
if (row < 0 || row >= numRows || column < 0 || column >= numColumns)
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
return createIndex(row, column);
|
return createIndex(row, column);
|
||||||
|
|
|
@ -71,7 +71,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
||||||
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
||||||
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
|
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
|
||||||
{
|
{
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
||||||
mTerrain->loadCell(esmLand->mX,
|
mTerrain->loadCell(esmLand->mX,
|
||||||
esmLand->mY);
|
esmLand->mY);
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const
|
||||||
|
|
||||||
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
||||||
const std::string& id, bool referenceable, bool forceBaseToZero)
|
const std::string& id, bool referenceable, bool forceBaseToZero)
|
||||||
: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero)
|
: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero)
|
||||||
{
|
{
|
||||||
mBaseNode = new osg::PositionAttitudeTransform;
|
mBaseNode = new osg::PositionAttitudeTransform;
|
||||||
parentNode->addChild(mBaseNode);
|
parentNode->addChild(mBaseNode);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
|
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
|
||||||
const std::string& id, bool referenceable, QWidget *parent)
|
const std::string& id, bool referenceable, QWidget *parent)
|
||||||
: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable)
|
: SceneWidget (data.getResourceSystem(), parent), mData (data), mObject(data, mRootNode, id, referenceable)
|
||||||
{
|
{
|
||||||
mView->setCameraManipulator(new osgGA::TrackballManipulator);
|
mView->setCameraManipulator(new osgGA::TrackballManipulator);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <osg/LightModel>
|
#include <osg/LightModel>
|
||||||
|
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
#include "../widget/scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
#include "../../model/settings/usersettings.hpp"
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
@ -132,9 +133,9 @@ void CompositeViewer::update()
|
||||||
|
|
||||||
// ---------------------------------------------------
|
// ---------------------------------------------------
|
||||||
|
|
||||||
SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f)
|
SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSystem, QWidget *parent, Qt::WindowFlags f)
|
||||||
: RenderWidget(parent, f)
|
: RenderWidget(parent, f)
|
||||||
, mSceneManager(sceneManager)
|
, mResourceSystem(resourceSystem)
|
||||||
, mLighting(NULL)
|
, mLighting(NULL)
|
||||||
, mHasDefaultAmbient(false)
|
, mHasDefaultAmbient(false)
|
||||||
{
|
{
|
||||||
|
@ -147,7 +148,7 @@ SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent,
|
||||||
SceneWidget::~SceneWidget()
|
SceneWidget::~SceneWidget()
|
||||||
{
|
{
|
||||||
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
|
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
|
||||||
mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneWidget::setLighting(Lighting *lighting)
|
void SceneWidget::setLighting(Lighting *lighting)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include "lightingday.hpp"
|
#include "lightingday.hpp"
|
||||||
#include "lightingnight.hpp"
|
#include "lightingnight.hpp"
|
||||||
#include "lightingbright.hpp"
|
#include "lightingbright.hpp"
|
||||||
|
@ -13,7 +15,7 @@
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
class SceneManager;
|
class ResourceSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
|
@ -57,7 +59,7 @@ namespace CSVRender
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0);
|
SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSystem, QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
virtual ~SceneWidget();
|
virtual ~SceneWidget();
|
||||||
|
|
||||||
CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent);
|
CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent);
|
||||||
|
@ -73,7 +75,7 @@ namespace CSVRender
|
||||||
|
|
||||||
void setAmbient(const osg::Vec4f& ambient);
|
void setAmbient(const osg::Vec4f& ambient);
|
||||||
|
|
||||||
Resource::SceneManager* mSceneManager;
|
boost::shared_ptr<Resource::ResourceSystem> mResourceSystem;
|
||||||
|
|
||||||
Lighting* mLighting;
|
Lighting* mLighting;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include "editmode.hpp"
|
#include "editmode.hpp"
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
||||||
: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mSceneElements(0), mRun(0), mDocument(document),
|
: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document),
|
||||||
mInteractionMask (0)
|
mInteractionMask (0)
|
||||||
{
|
{
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
|
@ -16,7 +16,7 @@ void CSVTools::SearchSubView::replace (bool selection)
|
||||||
{
|
{
|
||||||
if (mLocked)
|
if (mLocked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<int> indices = mTable->getReplaceIndices (selection);
|
std::vector<int> indices = mTable->getReplaceIndices (selection);
|
||||||
|
|
||||||
std::string replace = mSearchBox.getReplaceText();
|
std::string replace = mSearchBox.getReplaceText();
|
||||||
|
@ -29,7 +29,7 @@ void CSVTools::SearchSubView::replace (bool selection)
|
||||||
|
|
||||||
CSMTools::Search search (mSearch);
|
CSMTools::Search search (mSearch);
|
||||||
CSMWorld::IdTableBase *currentTable = 0;
|
CSMWorld::IdTableBase *currentTable = 0;
|
||||||
|
|
||||||
// We are running through the indices in reverse order to avoid messing up multiple results
|
// We are running through the indices in reverse order to avoid messing up multiple results
|
||||||
// in a single string.
|
// in a single string.
|
||||||
for (std::vector<int>::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter)
|
for (std::vector<int>::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter)
|
||||||
|
@ -46,7 +46,7 @@ void CSVTools::SearchSubView::replace (bool selection)
|
||||||
search.configure (table);
|
search.configure (table);
|
||||||
currentTable = table;
|
currentTable = table;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string hint = model.getHint (*iter);
|
std::string hint = model.getHint (*iter);
|
||||||
|
|
||||||
if (search.verify (mDocument, table, id, hint))
|
if (search.verify (mDocument, table, id, hint))
|
||||||
|
@ -63,7 +63,7 @@ void CSVTools::SearchSubView::replace (bool selection)
|
||||||
void CSVTools::SearchSubView::showEvent (QShowEvent *event)
|
void CSVTools::SearchSubView::showEvent (QShowEvent *event)
|
||||||
{
|
{
|
||||||
CSVDoc::SubView::showEvent (event);
|
CSVDoc::SubView::showEvent (event);
|
||||||
mSearchBox.focus();
|
mSearchBox.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||||
|
@ -71,25 +71,23 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc:
|
||||||
{
|
{
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
|
||||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
|
||||||
|
|
||||||
layout->addWidget (&mSearchBox);
|
layout->addWidget (&mSearchBox);
|
||||||
|
|
||||||
layout->addWidget (mTable = new ReportTable (document, id, true), 2);
|
layout->addWidget (mTable = new ReportTable (document, id, true), 2);
|
||||||
|
|
||||||
QWidget *widget = new QWidget;
|
QWidget *widget = new QWidget;
|
||||||
|
|
||||||
widget->setLayout (layout);
|
widget->setLayout (layout);
|
||||||
|
|
||||||
setWidget (widget);
|
setWidget (widget);
|
||||||
|
|
||||||
stateChanged (document.getState(), &document);
|
stateChanged (document.getState(), &document);
|
||||||
|
|
||||||
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
|
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
|
||||||
SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)));
|
SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)));
|
||||||
|
|
||||||
connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest()));
|
connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest()));
|
||||||
|
|
||||||
connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
|
connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
|
||||||
this, SLOT (stateChanged (int, CSMDoc::Document *)));
|
this, SLOT (stateChanged (int, CSMDoc::Document *)));
|
||||||
|
|
||||||
|
@ -124,7 +122,7 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search)
|
||||||
|
|
||||||
mSearch = search;
|
mSearch = search;
|
||||||
mSearch.setPadding (paddingBefore, paddingAfter);
|
mSearch.setPadding (paddingBefore, paddingAfter);
|
||||||
|
|
||||||
mTable->clear();
|
mTable->clear();
|
||||||
mDocument.runSearch (getUniversalId(), mSearch);
|
mDocument.runSearch (getUniversalId(), mSearch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "../../model/world/idtree.hpp"
|
#include "../../model/world/idtree.hpp"
|
||||||
#include "../../model/world/commands.hpp"
|
#include "../../model/world/commands.hpp"
|
||||||
#include "../../model/doc/document.hpp"
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
|
||||||
#include "../widget/coloreditor.hpp"
|
#include "../widget/coloreditor.hpp"
|
||||||
#include "../widget/droplineedit.hpp"
|
#include "../widget/droplineedit.hpp"
|
||||||
|
@ -66,7 +67,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo
|
||||||
|
|
||||||
CSMWorld::Columns::ColumnId columnId = static_cast<CSMWorld::Columns::ColumnId> (
|
CSMWorld::Columns::ColumnId columnId = static_cast<CSMWorld::Columns::ColumnId> (
|
||||||
mTable->getColumnId (index.column()));
|
mTable->getColumnId (index.column()));
|
||||||
|
|
||||||
if (QVariant::String == v.type())
|
if (QVariant::String == v.type())
|
||||||
{
|
{
|
||||||
label->setText(v.toString());
|
label->setText(v.toString());
|
||||||
|
@ -75,7 +76,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo
|
||||||
{
|
{
|
||||||
int data = v.toInt();
|
int data = v.toInt();
|
||||||
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (columnId));
|
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (columnId));
|
||||||
|
|
||||||
label->setText(QString::fromUtf8(enumNames.at(data).c_str()));
|
label->setText(QString::fromUtf8(enumNames.at(data).c_str()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -324,11 +325,11 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di
|
||||||
Q_ASSERT(mWidget != NULL);
|
Q_ASSERT(mWidget != NULL);
|
||||||
Q_ASSERT(CSMWorld::ColumnBase::isId(display));
|
Q_ASSERT(CSMWorld::ColumnBase::isId(display));
|
||||||
Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None);
|
Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None);
|
||||||
|
|
||||||
mWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
mWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(mWidget,
|
connect(mWidget,
|
||||||
SIGNAL(customContextMenuRequested(const QPoint &)),
|
SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||||
this,
|
this,
|
||||||
SLOT(showContextMenu(const QPoint &)));
|
SLOT(showContextMenu(const QPoint &)));
|
||||||
|
|
||||||
mEditIdAction = new QAction(this);
|
mEditIdAction = new QAction(this);
|
||||||
|
@ -352,7 +353,7 @@ void CSVWorld::IdContextMenu::excludeId(const std::string &id)
|
||||||
|
|
||||||
QString CSVWorld::IdContextMenu::getWidgetValue() const
|
QString CSVWorld::IdContextMenu::getWidgetValue() const
|
||||||
{
|
{
|
||||||
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(mWidget);
|
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(mWidget);
|
||||||
QLabel *label = qobject_cast<QLabel *>(mWidget);
|
QLabel *label = qobject_cast<QLabel *>(mWidget);
|
||||||
|
|
||||||
QString value = "";
|
QString value = "";
|
||||||
|
@ -411,7 +412,7 @@ void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
removeEditIdActionFromMenu();
|
removeEditIdActionFromMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mContextMenu->actions().isEmpty())
|
if (!mContextMenu->actions().isEmpty())
|
||||||
{
|
{
|
||||||
mContextMenu->exec(mWidget->mapToGlobal(pos));
|
mContextMenu->exec(mWidget->mapToGlobal(pos));
|
||||||
|
@ -588,9 +589,9 @@ void CSVWorld::EditWidget::remake(int row)
|
||||||
tablesLayout->addWidget(label);
|
tablesLayout->addWidget(label);
|
||||||
tablesLayout->addWidget(table);
|
tablesLayout->addWidget(table);
|
||||||
|
|
||||||
connect(table,
|
connect(table,
|
||||||
SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)),
|
SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)),
|
||||||
this,
|
this,
|
||||||
SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)));
|
SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)));
|
||||||
}
|
}
|
||||||
else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List))
|
else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List))
|
||||||
|
@ -830,45 +831,74 @@ void CSVWorld::SimpleDialogueSubView::updateCurrentId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id,
|
void CSVWorld::DialogueSubView::addButtonBar()
|
||||||
CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting)
|
|
||||||
: SimpleDialogueSubView (id, document)
|
|
||||||
{
|
{
|
||||||
// bottom box
|
if (mButtons)
|
||||||
mBottom = new TableBottomBox (creatorFactory, document, id, this);
|
return;
|
||||||
|
|
||||||
mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed);
|
mButtons = new RecordButtonBar (getUniversalId(), getTable(), mBottom,
|
||||||
|
|
||||||
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
|
|
||||||
this, SLOT (requestFocus (const std::string&)));
|
|
||||||
|
|
||||||
// button bar
|
|
||||||
mButtons = new RecordButtonBar (id, getTable(), mBottom,
|
|
||||||
&getCommandDispatcher(), this);
|
&getCommandDispatcher(), this);
|
||||||
|
|
||||||
// layout
|
getMainLayout().insertWidget (1, mButtons);
|
||||||
getMainLayout().addWidget (mButtons);
|
|
||||||
getMainLayout().addWidget (mBottom);
|
|
||||||
|
|
||||||
// connections
|
// connections
|
||||||
connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview()));
|
connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview()));
|
||||||
connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord()));
|
connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord()));
|
||||||
connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int)));
|
connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int)));
|
||||||
|
|
||||||
connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)),
|
connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)),
|
||||||
mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&)));
|
mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id,
|
||||||
|
CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting)
|
||||||
|
: SimpleDialogueSubView (id, document), mButtons (0)
|
||||||
|
{
|
||||||
|
// bottom box
|
||||||
|
mBottom = new TableBottomBox (creatorFactory, document, id, this);
|
||||||
|
|
||||||
|
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
|
||||||
|
this, SLOT (requestFocus (const std::string&)));
|
||||||
|
|
||||||
|
// button bar
|
||||||
|
if (CSMSettings::UserSettings::instance().setting ("dialogues/toolbar", QString("true")) == "true")
|
||||||
|
addButtonBar();
|
||||||
|
|
||||||
|
// layout
|
||||||
|
getMainLayout().addWidget (mBottom);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::DialogueSubView::setEditLock (bool locked)
|
void CSVWorld::DialogueSubView::setEditLock (bool locked)
|
||||||
{
|
{
|
||||||
SimpleDialogueSubView::setEditLock (locked);
|
SimpleDialogueSubView::setEditLock (locked);
|
||||||
mButtons->setEditLock (locked);
|
|
||||||
|
if (mButtons)
|
||||||
|
mButtons->setEditLock (locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value)
|
void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
{
|
{
|
||||||
SimpleDialogueSubView::updateUserSetting (name, value);
|
SimpleDialogueSubView::updateUserSetting (name, value);
|
||||||
mButtons->updateUserSetting (name, value);
|
|
||||||
|
if (name=="dialogues/toolbar")
|
||||||
|
{
|
||||||
|
if (value.at(0)==QString ("true"))
|
||||||
|
{
|
||||||
|
addButtonBar();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mButtons)
|
||||||
|
{
|
||||||
|
getMainLayout().removeWidget (mButtons);
|
||||||
|
delete mButtons;
|
||||||
|
mButtons = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mButtons)
|
||||||
|
mButtons->updateUserSetting (name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::DialogueSubView::showPreview ()
|
void CSVWorld::DialogueSubView::showPreview ()
|
||||||
|
@ -908,7 +938,7 @@ void CSVWorld::DialogueSubView::switchToRow (int row)
|
||||||
|
|
||||||
setUniversalId (CSMWorld::UniversalId (type, id));
|
setUniversalId (CSMWorld::UniversalId (type, id));
|
||||||
updateCurrentId();
|
updateCurrentId();
|
||||||
|
|
||||||
getEditWidget().remake (row);
|
getEditWidget().remake (row);
|
||||||
|
|
||||||
int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
||||||
|
@ -923,5 +953,5 @@ void CSVWorld::DialogueSubView::requestFocus (const std::string& id)
|
||||||
QModelIndex index = getTable().getModelIndex (id, 0);
|
QModelIndex index = getTable().getModelIndex (id, 0);
|
||||||
|
|
||||||
if (index.isValid())
|
if (index.isValid())
|
||||||
switchToRow (index.row());
|
switchToRow (index.row());
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,8 +195,8 @@ namespace CSVWorld
|
||||||
CSMDoc::Document& mDocument;
|
CSMDoc::Document& mDocument;
|
||||||
std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor
|
std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor
|
||||||
|
|
||||||
void createEditorContextMenu(QWidget *editor,
|
void createEditorContextMenu(QWidget *editor,
|
||||||
CSMWorld::ColumnBase::Display display,
|
CSMWorld::ColumnBase::Display display,
|
||||||
int currentRow) const;
|
int currentRow) const;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ namespace CSVWorld
|
||||||
void updateCurrentId();
|
void updateCurrentId();
|
||||||
|
|
||||||
bool isLocked() const;
|
bool isLocked() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||||
|
@ -256,10 +256,14 @@ namespace CSVWorld
|
||||||
class DialogueSubView : public SimpleDialogueSubView
|
class DialogueSubView : public SimpleDialogueSubView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
TableBottomBox* mBottom;
|
TableBottomBox* mBottom;
|
||||||
RecordButtonBar *mButtons;
|
RecordButtonBar *mButtons;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void addButtonBar();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||||
|
@ -268,14 +272,14 @@ namespace CSVWorld
|
||||||
virtual void setEditLock (bool locked);
|
virtual void setEditLock (bool locked);
|
||||||
|
|
||||||
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void showPreview();
|
void showPreview();
|
||||||
|
|
||||||
void viewRecord();
|
void viewRecord();
|
||||||
|
|
||||||
void switchToRow (int row);
|
void switchToRow (int row);
|
||||||
|
|
||||||
void requestFocus (const std::string& id);
|
void requestFocus (const std::string& id);
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,8 +13,6 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo
|
||||||
{
|
{
|
||||||
QHBoxLayout *layout = new QHBoxLayout;
|
QHBoxLayout *layout = new QHBoxLayout;
|
||||||
|
|
||||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
|
||||||
|
|
||||||
if (document.getData().getReferenceables().searchId (id.getId())==-1)
|
if (document.getData().getReferenceables().searchId (id.getId())==-1)
|
||||||
{
|
{
|
||||||
std::string referenceableId =
|
std::string referenceableId =
|
||||||
|
|
|
@ -17,18 +17,17 @@ void CSVWorld::RecordButtonBar::updateModificationButtons()
|
||||||
|
|
||||||
mCloneButton->setDisabled (createAndDeleteDisabled);
|
mCloneButton->setDisabled (createAndDeleteDisabled);
|
||||||
mAddButton->setDisabled (createAndDeleteDisabled);
|
mAddButton->setDisabled (createAndDeleteDisabled);
|
||||||
mDeleteButton->setDisabled (createAndDeleteDisabled);
|
|
||||||
|
|
||||||
bool commandDisabled = !mCommandDispatcher || mLocked;
|
bool commandDisabled = !mCommandDispatcher || mLocked;
|
||||||
|
|
||||||
mRevertButton->setDisabled (commandDisabled);
|
mRevertButton->setDisabled (commandDisabled);
|
||||||
mDeleteButton->setDisabled (commandDisabled);
|
mDeleteButton->setDisabled (commandDisabled || createAndDeleteDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::RecordButtonBar::updatePrevNextButtons()
|
void CSVWorld::RecordButtonBar::updatePrevNextButtons()
|
||||||
{
|
{
|
||||||
int rows = mTable.rowCount();
|
int rows = mTable.rowCount();
|
||||||
|
|
||||||
if (rows<=1)
|
if (rows<=1)
|
||||||
{
|
{
|
||||||
mPrevButton->setDisabled (true);
|
mPrevButton->setDisabled (true);
|
||||||
|
@ -62,12 +61,12 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
|
||||||
mPrevButton->setIcon(QIcon(":/go-previous.png"));
|
mPrevButton->setIcon(QIcon(":/go-previous.png"));
|
||||||
mPrevButton->setToolTip ("Switch to previous record");
|
mPrevButton->setToolTip ("Switch to previous record");
|
||||||
buttonsLayout->addWidget (mPrevButton, 0);
|
buttonsLayout->addWidget (mPrevButton, 0);
|
||||||
|
|
||||||
mNextButton = new QToolButton (this);
|
mNextButton = new QToolButton (this);
|
||||||
mNextButton->setIcon(QIcon(":/go-next.png"));
|
mNextButton->setIcon(QIcon(":/go-next.png"));
|
||||||
mNextButton->setToolTip ("Switch to next record");
|
mNextButton->setToolTip ("Switch to next record");
|
||||||
buttonsLayout->addWidget (mNextButton, 1);
|
buttonsLayout->addWidget (mNextButton, 1);
|
||||||
|
|
||||||
buttonsLayout->addStretch(2);
|
buttonsLayout->addStretch(2);
|
||||||
|
|
||||||
// optional buttons of the right section
|
// optional buttons of the right section
|
||||||
|
@ -94,22 +93,22 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
|
||||||
mCloneButton->setIcon(QIcon(":/edit-clone.png"));
|
mCloneButton->setIcon(QIcon(":/edit-clone.png"));
|
||||||
mCloneButton->setToolTip ("Clone record");
|
mCloneButton->setToolTip ("Clone record");
|
||||||
buttonsLayout->addWidget(mCloneButton);
|
buttonsLayout->addWidget(mCloneButton);
|
||||||
|
|
||||||
mAddButton = new QToolButton (this);
|
mAddButton = new QToolButton (this);
|
||||||
mAddButton->setIcon(QIcon(":/add.png"));
|
mAddButton->setIcon(QIcon(":/add.png"));
|
||||||
mAddButton->setToolTip ("Add new record");
|
mAddButton->setToolTip ("Add new record");
|
||||||
buttonsLayout->addWidget(mAddButton);
|
buttonsLayout->addWidget(mAddButton);
|
||||||
|
|
||||||
mDeleteButton = new QToolButton (this);
|
mDeleteButton = new QToolButton (this);
|
||||||
mDeleteButton->setIcon(QIcon(":/edit-delete.png"));
|
mDeleteButton->setIcon(QIcon(":/edit-delete.png"));
|
||||||
mDeleteButton->setToolTip ("Delete record");
|
mDeleteButton->setToolTip ("Delete record");
|
||||||
buttonsLayout->addWidget(mDeleteButton);
|
buttonsLayout->addWidget(mDeleteButton);
|
||||||
|
|
||||||
mRevertButton = new QToolButton (this);
|
mRevertButton = new QToolButton (this);
|
||||||
mRevertButton->setIcon(QIcon(":/edit-undo.png"));
|
mRevertButton->setIcon(QIcon(":/edit-undo.png"));
|
||||||
mRevertButton->setToolTip ("Revert record");
|
mRevertButton->setToolTip ("Revert record");
|
||||||
buttonsLayout->addWidget(mRevertButton);
|
buttonsLayout->addWidget(mRevertButton);
|
||||||
|
|
||||||
setLayout (buttonsLayout);
|
setLayout (buttonsLayout);
|
||||||
|
|
||||||
// connections
|
// connections
|
||||||
|
@ -132,7 +131,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
|
||||||
this, SLOT (rowNumberChanged (const QModelIndex&, int, int)));
|
this, SLOT (rowNumberChanged (const QModelIndex&, int, int)));
|
||||||
connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
|
connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (rowNumberChanged (const QModelIndex&, int, int)));
|
this, SLOT (rowNumberChanged (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
updateModificationButtons();
|
updateModificationButtons();
|
||||||
updatePrevNextButtons();
|
updatePrevNextButtons();
|
||||||
}
|
}
|
||||||
|
@ -170,7 +169,7 @@ void CSVWorld::RecordButtonBar::cloneRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::RecordButtonBar::nextId()
|
void CSVWorld::RecordButtonBar::nextId()
|
||||||
{
|
{
|
||||||
int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1;
|
int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1;
|
||||||
|
|
||||||
if (newRow >= mTable.rowCount())
|
if (newRow >= mTable.rowCount())
|
||||||
|
@ -180,8 +179,8 @@ void CSVWorld::RecordButtonBar::nextId()
|
||||||
newRow = 0;
|
newRow = 0;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit switchToRow (newRow);
|
emit switchToRow (newRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +196,7 @@ void CSVWorld::RecordButtonBar::prevId()
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit switchToRow (newRow);
|
emit switchToRow (newRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,6 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
{
|
{
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
|
||||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
|
||||||
|
|
||||||
layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0);
|
layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0);
|
||||||
|
|
||||||
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
|
|
@ -276,11 +276,11 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event)
|
||||||
if(textCursor().hasSelection())
|
if(textCursor().hasSelection())
|
||||||
{
|
{
|
||||||
QString str = textCursor().selection().toPlainText();
|
QString str = textCursor().selection().toPlainText();
|
||||||
int selectedLines = str.count("\n")+1;
|
int offset = str.count("\n");
|
||||||
if(textCursor().position() < textCursor().anchor())
|
if(textCursor().position() < textCursor().anchor())
|
||||||
endBlock += selectedLines;
|
endBlock += offset;
|
||||||
else
|
else
|
||||||
startBlock -= selectedLines;
|
startBlock -= offset;
|
||||||
}
|
}
|
||||||
painter.setBackgroundMode(Qt::OpaqueMode);
|
painter.setBackgroundMode(Qt::OpaqueMode);
|
||||||
QFont font = painter.font();
|
QFont font = painter.font();
|
||||||
|
|
143
apps/opencs/view/world/scripterrortable.cpp
Normal file
143
apps/opencs/view/world/scripterrortable.cpp
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
|
||||||
|
#include "scripterrortable.hpp"
|
||||||
|
|
||||||
|
#include <QHeaderView>
|
||||||
|
|
||||||
|
#include <components/compiler/tokenloc.hpp>
|
||||||
|
#include <components/compiler/scanner.hpp>
|
||||||
|
#include <components/compiler/fileparser.hpp>
|
||||||
|
#include <components/compiler/exception.hpp>
|
||||||
|
#include <components/compiler/extensions0.hpp>
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type)
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << message << " (" << loc.mLiteral << ")";
|
||||||
|
|
||||||
|
addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ?
|
||||||
|
CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error,
|
||||||
|
loc.mLine, loc.mColumn-loc.mLiteral.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type)
|
||||||
|
{
|
||||||
|
addMessage (message, type==Compiler::ErrorHandler::WarningMessage ?
|
||||||
|
CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::addMessage (const std::string& message,
|
||||||
|
CSMDoc::Message::Severity severity, int line, int column)
|
||||||
|
{
|
||||||
|
int row = rowCount();
|
||||||
|
|
||||||
|
setRowCount (row+1);
|
||||||
|
|
||||||
|
QTableWidgetItem *severityItem = new QTableWidgetItem (
|
||||||
|
QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()));
|
||||||
|
severityItem->setFlags (severityItem->flags() ^ Qt::ItemIsEditable);
|
||||||
|
setItem (row, 0, severityItem);
|
||||||
|
|
||||||
|
if (line!=-1)
|
||||||
|
{
|
||||||
|
QTableWidgetItem *lineItem = new QTableWidgetItem;
|
||||||
|
lineItem->setData (Qt::DisplayRole, line+1);
|
||||||
|
lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable);
|
||||||
|
setItem (row, 1, lineItem);
|
||||||
|
|
||||||
|
QTableWidgetItem *columnItem = new QTableWidgetItem;
|
||||||
|
columnItem->setData (Qt::DisplayRole, column);
|
||||||
|
columnItem->setFlags (columnItem->flags() ^ Qt::ItemIsEditable);
|
||||||
|
setItem (row, 3, columnItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str()));
|
||||||
|
messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable);
|
||||||
|
setItem (row, 2, messageItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value)
|
||||||
|
{
|
||||||
|
if (value=="Ignore")
|
||||||
|
Compiler::ErrorHandler::setWarningsMode (0);
|
||||||
|
else if (value=="Normal")
|
||||||
|
Compiler::ErrorHandler::setWarningsMode (1);
|
||||||
|
else if (value=="Strict")
|
||||||
|
Compiler::ErrorHandler::setWarningsMode (2);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent)
|
||||||
|
: QTableWidget (parent), mContext (document.getData())
|
||||||
|
{
|
||||||
|
setColumnCount (4);
|
||||||
|
|
||||||
|
QStringList headers;
|
||||||
|
headers << "Severity" << "Line" << "Description";
|
||||||
|
setHorizontalHeaderLabels (headers);
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||||
|
horizontalHeader()->setSectionResizeMode (0, QHeaderView::ResizeToContents);
|
||||||
|
horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents);
|
||||||
|
#else
|
||||||
|
horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents);
|
||||||
|
horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents);
|
||||||
|
#endif
|
||||||
|
horizontalHeader()->setStretchLastSection (true);
|
||||||
|
verticalHeader()->hide();
|
||||||
|
setColumnHidden (3, true);
|
||||||
|
|
||||||
|
setSelectionMode (QAbstractItemView::NoSelection);
|
||||||
|
|
||||||
|
Compiler::registerExtensions (mExtensions);
|
||||||
|
mContext.setExtensions (&mExtensions);
|
||||||
|
|
||||||
|
setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings"));
|
||||||
|
|
||||||
|
connect (this, SIGNAL (cellClicked (int, int)), this, SLOT (cellClicked (int, int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
|
{
|
||||||
|
if (name=="script-editor/warnings" && !value.isEmpty())
|
||||||
|
setWarningsMode (value.at (0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::update (const std::string& source)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::istringstream input (source);
|
||||||
|
|
||||||
|
Compiler::Scanner scanner (*this, input, mContext.getExtensions());
|
||||||
|
|
||||||
|
Compiler::FileParser parser (*this, mContext);
|
||||||
|
|
||||||
|
scanner.scan (parser);
|
||||||
|
}
|
||||||
|
catch (const Compiler::SourceException&)
|
||||||
|
{
|
||||||
|
// error has already been reported via error handler
|
||||||
|
}
|
||||||
|
catch (const std::exception& error)
|
||||||
|
{
|
||||||
|
addMessage (error.what(), CSMDoc::Message::Severity_SeriousError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::clear()
|
||||||
|
{
|
||||||
|
setRowCount (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptErrorTable::cellClicked (int row, int column)
|
||||||
|
{
|
||||||
|
if (item (row, 1))
|
||||||
|
{
|
||||||
|
int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt();
|
||||||
|
int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt();
|
||||||
|
emit highlightError (scriptLine-1, scriptColumn);
|
||||||
|
}
|
||||||
|
}
|
57
apps/opencs/view/world/scripterrortable.hpp
Normal file
57
apps/opencs/view/world/scripterrortable.hpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef CSV_WORLD_SCRIPTERRORTABLE_H
|
||||||
|
#define CSV_WORLD_SCRIPTERRORTABLE_H
|
||||||
|
|
||||||
|
#include <QTableWidget>
|
||||||
|
|
||||||
|
#include <components/compiler/errorhandler.hpp>
|
||||||
|
#include <components/compiler/extensions.hpp>
|
||||||
|
|
||||||
|
#include "../../model/world/scriptcontext.hpp"
|
||||||
|
#include "../../model/doc/messages.hpp"
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class ScriptErrorTable : public QTableWidget, private Compiler::ErrorHandler
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Compiler::Extensions mExtensions;
|
||||||
|
CSMWorld::ScriptContext mContext;
|
||||||
|
|
||||||
|
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
|
||||||
|
///< Report error to the user.
|
||||||
|
|
||||||
|
virtual void report (const std::string& message, Type type);
|
||||||
|
///< Report a file related error
|
||||||
|
|
||||||
|
void addMessage (const std::string& message, CSMDoc::Message::Severity severity,
|
||||||
|
int line = -1, int column = -1);
|
||||||
|
|
||||||
|
void setWarningsMode (const QString& value);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0);
|
||||||
|
|
||||||
|
void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
|
void update (const std::string& source);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void cellClicked (int row, int column);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void highlightError (int line, int column);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
#include <QStackedLayout>
|
#include <QStackedLayout>
|
||||||
#include <QLabel>
|
#include <QSplitter>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include "../../model/doc/document.hpp"
|
#include "../../model/doc/document.hpp"
|
||||||
#include "../../model/world/universalid.hpp"
|
#include "../../model/world/universalid.hpp"
|
||||||
|
@ -15,45 +16,96 @@
|
||||||
#include "../../model/settings/usersettings.hpp"
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
|
||||||
#include "scriptedit.hpp"
|
#include "scriptedit.hpp"
|
||||||
|
#include "recordbuttonbar.hpp"
|
||||||
|
#include "tablebottombox.hpp"
|
||||||
|
#include "genericcreator.hpp"
|
||||||
|
#include "scripterrortable.hpp"
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::addButtonBar()
|
||||||
|
{
|
||||||
|
if (mButtons)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mButtons = new RecordButtonBar (getUniversalId(), *mModel, mBottom, &mCommandDispatcher, this);
|
||||||
|
|
||||||
|
mLayout.insertWidget (1, mButtons);
|
||||||
|
|
||||||
|
connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int)));
|
||||||
|
|
||||||
|
connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)),
|
||||||
|
mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::recompile()
|
||||||
|
{
|
||||||
|
if (!mCompileDelay->isActive() && !isDeleted())
|
||||||
|
mCompileDelay->start (
|
||||||
|
CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVWorld::ScriptSubView::isDeleted() const
|
||||||
|
{
|
||||||
|
return mModel->data (mModel->getModelIndex (getUniversalId().getId(), mStateColumn)).toInt()
|
||||||
|
==CSMWorld::RecordBase::State_Deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::updateDeletedState()
|
||||||
|
{
|
||||||
|
if (isDeleted())
|
||||||
|
{
|
||||||
|
mErrors->clear();
|
||||||
|
mEditor->setEnabled (false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEditor->setEnabled (true);
|
||||||
|
recompile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||||
: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0)
|
: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0),
|
||||||
|
mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType()))
|
||||||
{
|
{
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
std::vector<std::string> selection (1, id.getId());
|
||||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
mCommandDispatcher.setSelection (selection);
|
||||||
|
|
||||||
mBottom = new QWidget(this);
|
mMain = new QSplitter (this);
|
||||||
QStackedLayout *bottmLayout = new QStackedLayout(mBottom);
|
mMain->setOrientation (Qt::Vertical);
|
||||||
bottmLayout->setContentsMargins (0, 0, 0, 0);
|
mLayout.addWidget (mMain, 2);
|
||||||
QStatusBar *statusBar = new QStatusBar(mBottom);
|
|
||||||
mStatus = new QLabel(mBottom);
|
|
||||||
statusBar->addWidget (mStatus);
|
|
||||||
bottmLayout->addWidget (statusBar);
|
|
||||||
mBottom->setLayout (bottmLayout);
|
|
||||||
|
|
||||||
layout->addWidget (mBottom, 0);
|
mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this);
|
||||||
layout->insertWidget (0, mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2);
|
mMain->addWidget (mEditor);
|
||||||
|
mMain->setCollapsible (0, false);
|
||||||
|
|
||||||
QWidget *widget = new QWidget;
|
mErrors = new ScriptErrorTable (document, this);
|
||||||
widget->setLayout (layout);
|
mMain->addWidget (mErrors);
|
||||||
|
|
||||||
|
QWidget *widget = new QWidget (this);;
|
||||||
|
widget->setLayout (&mLayout);
|
||||||
setWidget (widget);
|
setWidget (widget);
|
||||||
|
|
||||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (
|
mModel = &dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
|
||||||
|
|
||||||
for (int i=0; i<mModel->columnCount(); ++i)
|
mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText);
|
||||||
if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)==
|
mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
||||||
CSMWorld::ColumnBase::Display_ScriptFile)
|
|
||||||
{
|
|
||||||
mColumn = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mColumn==-1)
|
QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString();
|
||||||
throw std::logic_error ("Can't find script column");
|
|
||||||
|
|
||||||
mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString());
|
mEditor->setPlainText (source);
|
||||||
|
// bottom box and buttons
|
||||||
|
mBottom = new TableBottomBox (CreatorFactory<GenericCreator>(), document, id, this);
|
||||||
|
|
||||||
|
if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true")
|
||||||
|
addButtonBar();
|
||||||
|
|
||||||
|
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
|
||||||
|
this, SLOT (switchToId (const std::string&)));
|
||||||
|
|
||||||
|
mLayout.addWidget (mBottom);
|
||||||
|
|
||||||
|
// signals
|
||||||
connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged()));
|
connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged()));
|
||||||
|
|
||||||
connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
@ -64,35 +116,80 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc:
|
||||||
|
|
||||||
updateStatusBar();
|
updateStatusBar();
|
||||||
connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar()));
|
connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar()));
|
||||||
|
|
||||||
|
mErrors->update (source.toUtf8().constData());
|
||||||
|
|
||||||
|
connect (mErrors, SIGNAL (highlightError (int, int)),
|
||||||
|
this, SLOT (highlightError (int, int)));
|
||||||
|
|
||||||
|
mCompileDelay = new QTimer (this);
|
||||||
|
mCompileDelay->setSingleShot (true);
|
||||||
|
connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest()));
|
||||||
|
|
||||||
|
updateDeletedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value)
|
void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
{
|
{
|
||||||
if (name == "script-editor/show-linenum")
|
if (name == "script-editor/show-linenum")
|
||||||
{
|
{
|
||||||
std::string showLinenum = value.at(0).toStdString();
|
std::string showLinenum = value.at(0).toUtf8().constData();
|
||||||
mEditor->showLineNum(showLinenum == "true");
|
mEditor->showLineNum(showLinenum == "true");
|
||||||
mBottom->setVisible(showLinenum == "true");
|
mBottom->setVisible(showLinenum == "true");
|
||||||
}
|
}
|
||||||
else if (name == "script-editor/mono-font")
|
else if (name == "script-editor/mono-font")
|
||||||
{
|
{
|
||||||
mEditor->setMonoFont(value.at(0).toStdString() == "true");
|
mEditor->setMonoFont (value.at(0)==QString ("true"));
|
||||||
}
|
}
|
||||||
|
else if (name=="script-editor/toolbar")
|
||||||
|
{
|
||||||
|
if (value.at(0)==QString ("true"))
|
||||||
|
{
|
||||||
|
addButtonBar();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mButtons)
|
||||||
|
{
|
||||||
|
mLayout.removeWidget (mButtons);
|
||||||
|
delete mButtons;
|
||||||
|
mButtons = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (name=="script-editor/compile-delay")
|
||||||
|
{
|
||||||
|
mCompileDelay->setInterval (value.at (0).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mButtons)
|
||||||
|
mButtons->updateUserSetting (name, value);
|
||||||
|
|
||||||
|
mErrors->updateUserSetting (name, value);
|
||||||
|
|
||||||
|
if (name=="script-editor/warnings")
|
||||||
|
recompile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::setStatusBar (bool show)
|
||||||
|
{
|
||||||
|
mBottom->setStatusBar (show);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::updateStatusBar ()
|
void CSVWorld::ScriptSubView::updateStatusBar ()
|
||||||
{
|
{
|
||||||
std::ostringstream stream;
|
mBottom->positionChanged (mEditor->textCursor().blockNumber() + 1,
|
||||||
|
mEditor->textCursor().columnNumber() + 1);
|
||||||
stream << "(" << mEditor->textCursor().blockNumber() + 1 << ", "
|
|
||||||
<< mEditor->textCursor().columnNumber() + 1 << ")";
|
|
||||||
|
|
||||||
mStatus->setText (QString::fromUtf8 (stream.str().c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::setEditLock (bool locked)
|
void CSVWorld::ScriptSubView::setEditLock (bool locked)
|
||||||
{
|
{
|
||||||
mEditor->setReadOnly (locked);
|
mEditor->setReadOnly (locked);
|
||||||
|
|
||||||
|
if (mButtons)
|
||||||
|
mButtons->setEditLock (locked);
|
||||||
|
|
||||||
|
mCommandDispatcher.setEditLock (locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::useHint (const std::string& hint)
|
void CSVWorld::ScriptSubView::useHint (const std::string& hint)
|
||||||
|
@ -129,8 +226,12 @@ void CSVWorld::ScriptSubView::textChanged()
|
||||||
|
|
||||||
ScriptEdit::ChangeLock lock (*mEditor);
|
ScriptEdit::ChangeLock lock (*mEditor);
|
||||||
|
|
||||||
|
QString source = mEditor->toPlainText();
|
||||||
|
|
||||||
mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel,
|
mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel,
|
||||||
mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText()));
|
mModel->getModelIndex (getUniversalId().getId(), mColumn), source));
|
||||||
|
|
||||||
|
recompile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
@ -142,12 +243,21 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo
|
||||||
|
|
||||||
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||||
|
|
||||||
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() &&
|
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
|
||||||
index.column()>=topLeft.column() && index.column()<=bottomRight.column())
|
|
||||||
{
|
{
|
||||||
QTextCursor cursor = mEditor->textCursor();
|
if (mStateColumn>=topLeft.column() && mStateColumn<=bottomRight.column())
|
||||||
mEditor->setPlainText (mModel->data (index).toString());
|
updateDeletedState();
|
||||||
mEditor->setTextCursor (cursor);
|
|
||||||
|
if (mColumn>=topLeft.column() && mColumn<=bottomRight.column())
|
||||||
|
{
|
||||||
|
QString source = mModel->data (index).toString();
|
||||||
|
|
||||||
|
QTextCursor cursor = mEditor->textCursor();
|
||||||
|
mEditor->setPlainText (source);
|
||||||
|
mEditor->setTextCursor (cursor);
|
||||||
|
|
||||||
|
recompile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,3 +269,42 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i
|
||||||
emit closeRequest();
|
emit closeRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::switchToRow (int row)
|
||||||
|
{
|
||||||
|
int idColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||||
|
std::string id = mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData();
|
||||||
|
setUniversalId (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, id));
|
||||||
|
|
||||||
|
mEditor->setPlainText (mModel->data (mModel->index (row, mColumn)).toString());
|
||||||
|
|
||||||
|
std::vector<std::string> selection (1, id);
|
||||||
|
mCommandDispatcher.setSelection (selection);
|
||||||
|
|
||||||
|
updateDeletedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::switchToId (const std::string& id)
|
||||||
|
{
|
||||||
|
switchToRow (mModel->getModelIndex (id, 0).row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::highlightError (int line, int column)
|
||||||
|
{
|
||||||
|
QTextCursor cursor = mEditor->textCursor();
|
||||||
|
|
||||||
|
cursor.movePosition (QTextCursor::Start);
|
||||||
|
if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line))
|
||||||
|
cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column);
|
||||||
|
|
||||||
|
mEditor->setFocus();
|
||||||
|
mEditor->setTextCursor (cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ScriptSubView::updateRequest()
|
||||||
|
{
|
||||||
|
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||||
|
|
||||||
|
QString source = mModel->data (index).toString();
|
||||||
|
|
||||||
|
mErrors->update (source.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
#ifndef CSV_WORLD_SCRIPTSUBVIEW_H
|
#ifndef CSV_WORLD_SCRIPTSUBVIEW_H
|
||||||
#define CSV_WORLD_SCRIPTSUBVIEW_H
|
#define CSV_WORLD_SCRIPTSUBVIEW_H
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "../../model/world/commanddispatcher.hpp"
|
||||||
|
|
||||||
#include "../doc/subview.hpp"
|
#include "../doc/subview.hpp"
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
class QVBoxLayout;
|
||||||
|
class QSplitter;
|
||||||
|
class QTime;
|
||||||
|
|
||||||
namespace CSMDoc
|
namespace CSMDoc
|
||||||
{
|
{
|
||||||
|
@ -19,6 +26,9 @@ namespace CSMWorld
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
{
|
{
|
||||||
class ScriptEdit;
|
class ScriptEdit;
|
||||||
|
class RecordButtonBar;
|
||||||
|
class TableBottomBox;
|
||||||
|
class ScriptErrorTable;
|
||||||
|
|
||||||
class ScriptSubView : public CSVDoc::SubView
|
class ScriptSubView : public CSVDoc::SubView
|
||||||
{
|
{
|
||||||
|
@ -28,8 +38,24 @@ namespace CSVWorld
|
||||||
CSMDoc::Document& mDocument;
|
CSMDoc::Document& mDocument;
|
||||||
CSMWorld::IdTable *mModel;
|
CSMWorld::IdTable *mModel;
|
||||||
int mColumn;
|
int mColumn;
|
||||||
QWidget *mBottom;
|
int mStateColumn;
|
||||||
QLabel *mStatus;
|
TableBottomBox *mBottom;
|
||||||
|
RecordButtonBar *mButtons;
|
||||||
|
CSMWorld::CommandDispatcher mCommandDispatcher;
|
||||||
|
QVBoxLayout mLayout;
|
||||||
|
QSplitter *mMain;
|
||||||
|
ScriptErrorTable *mErrors;
|
||||||
|
QTimer *mCompileDelay;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void addButtonBar();
|
||||||
|
|
||||||
|
void recompile();
|
||||||
|
|
||||||
|
bool isDeleted() const;
|
||||||
|
|
||||||
|
void updateDeletedState();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -41,6 +67,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
|
virtual void setStatusBar (bool show);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void textChanged();
|
void textChanged();
|
||||||
|
@ -52,6 +80,14 @@ namespace CSVWorld
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void updateStatusBar();
|
void updateStatusBar();
|
||||||
|
|
||||||
|
void switchToRow (int row);
|
||||||
|
|
||||||
|
void switchToId (const std::string& id);
|
||||||
|
|
||||||
|
void highlightError (int line, int column);
|
||||||
|
|
||||||
|
void updateRequest();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -679,10 +679,6 @@ void CSVWorld::Table::tableSizeUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
emit tableSizeChanged (size, deleted, modified);
|
emit tableSizeChanged (size, deleted, modified);
|
||||||
|
|
||||||
// not really related to tableSizeUpdate() but placed here for convenience rather than
|
|
||||||
// creating a bunch of extra connections & slot
|
|
||||||
mProxyModel->refreshFilter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::selectionSizeUpdate()
|
void CSVWorld::Table::selectionSizeUpdate()
|
||||||
|
|
|
@ -51,6 +51,14 @@ void CSVWorld::TableBottomBox::updateStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mHasPosition)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
stream << " -- ";
|
||||||
|
|
||||||
|
stream << "(" << mRow << ", " << mColumn << ")";
|
||||||
|
}
|
||||||
|
|
||||||
mStatus->setText (QString::fromUtf8 (stream.str().c_str()));
|
mStatus->setText (QString::fromUtf8 (stream.str().c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +77,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto
|
||||||
CSMDoc::Document& document,
|
CSMDoc::Document& document,
|
||||||
const CSMWorld::UniversalId& id,
|
const CSMWorld::UniversalId& id,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None)
|
: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false)
|
||||||
{
|
{
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
mStatusCount[i] = 0;
|
mStatusCount[i] = 0;
|
||||||
|
@ -206,6 +214,20 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi
|
||||||
updateStatus();
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::TableBottomBox::positionChanged (int row, int column)
|
||||||
|
{
|
||||||
|
mRow = row;
|
||||||
|
mColumn = column;
|
||||||
|
mHasPosition = true;
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::TableBottomBox::noMorePosition()
|
||||||
|
{
|
||||||
|
mHasPosition = false;
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::TableBottomBox::createRequest()
|
void CSVWorld::TableBottomBox::createRequest()
|
||||||
{
|
{
|
||||||
mCreator->reset();
|
mCreator->reset();
|
||||||
|
@ -216,8 +238,8 @@ void CSVWorld::TableBottomBox::createRequest()
|
||||||
mCreator->focus();
|
mCreator->focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::TableBottomBox::cloneRequest(const std::string& id,
|
void CSVWorld::TableBottomBox::cloneRequest(const std::string& id,
|
||||||
const CSMWorld::UniversalId::Type type)
|
const CSMWorld::UniversalId::Type type)
|
||||||
{
|
{
|
||||||
mCreator->reset();
|
mCreator->reset();
|
||||||
mCreator->cloneMode(id, type);
|
mCreator->cloneMode(id, type);
|
||||||
|
|
|
@ -36,6 +36,9 @@ namespace CSVWorld
|
||||||
ExtendedCommandConfigurator *mExtendedConfigurator;
|
ExtendedCommandConfigurator *mExtendedConfigurator;
|
||||||
|
|
||||||
QStackedLayout *mLayout;
|
QStackedLayout *mLayout;
|
||||||
|
bool mHasPosition;
|
||||||
|
int mRow;
|
||||||
|
int mColumn;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -52,9 +55,9 @@ namespace CSVWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TableBottomBox (const CreatorFactoryBase& creatorFactory,
|
TableBottomBox (const CreatorFactoryBase& creatorFactory,
|
||||||
CSMDoc::Document& document,
|
CSMDoc::Document& document,
|
||||||
const CSMWorld::UniversalId& id,
|
const CSMWorld::UniversalId& id,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
|
||||||
virtual ~TableBottomBox();
|
virtual ~TableBottomBox();
|
||||||
|
@ -92,6 +95,10 @@ namespace CSVWorld
|
||||||
/// \param deleted Number of deleted records
|
/// \param deleted Number of deleted records
|
||||||
/// \param modified Number of added and modified records
|
/// \param modified Number of added and modified records
|
||||||
|
|
||||||
|
void positionChanged (int row, int column);
|
||||||
|
|
||||||
|
void noMorePosition();
|
||||||
|
|
||||||
void createRequest();
|
void createRequest();
|
||||||
void cloneRequest(const std::string& id,
|
void cloneRequest(const std::string& id,
|
||||||
const CSMWorld::UniversalId::Type type);
|
const CSMWorld::UniversalId::Type type);
|
||||||
|
|
|
@ -23,8 +23,6 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
{
|
{
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
|
||||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
|
||||||
|
|
||||||
layout->addWidget (mBottom =
|
layout->addWidget (mBottom =
|
||||||
new TableBottomBox (creatorFactory, document, id, this), 0);
|
new TableBottomBox (creatorFactory, document, id, this), 0);
|
||||||
|
|
||||||
|
@ -171,4 +169,3 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event)
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/translation/translation.hpp>
|
#include <components/translation/translation.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/version/version.hpp>
|
||||||
|
|
||||||
#include "mwinput/inputmanagerimp.hpp"
|
#include "mwinput/inputmanagerimp.hpp"
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ void OMW::Engine::setWindowIcon()
|
||||||
{
|
{
|
||||||
boost::filesystem::ifstream windowIconStream;
|
boost::filesystem::ifstream windowIconStream;
|
||||||
std::string windowIcon = (mResDir / "mygui" / "openmw.png").string();
|
std::string windowIcon = (mResDir / "mygui" / "openmw.png").string();
|
||||||
windowIconStream.open(windowIcon);
|
windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
|
||||||
if (windowIconStream.fail())
|
if (windowIconStream.fail())
|
||||||
std::cerr << "Failed to open " << windowIcon << std::endl;
|
std::cerr << "Failed to open " << windowIcon << std::endl;
|
||||||
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||||
|
@ -493,7 +493,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
rootNode->addChild(guiRoot);
|
rootNode->addChild(guiRoot);
|
||||||
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(),
|
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(),
|
||||||
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
|
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
|
||||||
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap);
|
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap,
|
||||||
|
Version::getOpenmwVersionDescription(mResDir.string()));
|
||||||
mEnvironment.setWindowManager (window);
|
mEnvironment.setWindowManager (window);
|
||||||
|
|
||||||
// Create sound system
|
// Create sound system
|
||||||
|
@ -645,9 +646,6 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
prepareEngine (settings);
|
prepareEngine (settings);
|
||||||
|
|
||||||
// Play some good 'ol tunes
|
|
||||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
|
||||||
|
|
||||||
if (!mSaveGameFile.empty())
|
if (!mSaveGameFile.empty())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile);
|
MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile);
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// For OutputDebugString
|
// For OutputDebugString
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
// makes __argc and __argv available on windows
|
// makes __argc and __argv available on windows
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -197,18 +199,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "OpenMW version " << OPENMW_VERSION;
|
|
||||||
std::string rev = OPENMW_VERSION_COMMITHASH;
|
|
||||||
std::string tag = OPENMW_VERSION_TAGHASH;
|
|
||||||
if (!rev.empty() && !tag.empty())
|
|
||||||
{
|
|
||||||
rev = rev.substr(0, 10);
|
|
||||||
std::cout << " (revision " << rev << ")";
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
if (variables.count ("version"))
|
if (variables.count ("version"))
|
||||||
|
{
|
||||||
|
cfgMgr.readConfiguration(variables, desc, true);
|
||||||
|
|
||||||
|
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<std::string>());
|
||||||
|
std::cout << v.describe() << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cfgMgr.readConfiguration(variables, desc);
|
cfgMgr.readConfiguration(variables, desc);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
class CellStore;
|
class CellStore;
|
||||||
|
class CellRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Loading
|
namespace Loading
|
||||||
|
@ -128,6 +129,11 @@ namespace MWBase
|
||||||
OffenseType type, int arg=0, bool victimAware=false) = 0;
|
OffenseType type, int arg=0, bool victimAware=false) = 0;
|
||||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||||
|
|
||||||
|
/// Notify that actor was killed, add a murder bounty if applicable
|
||||||
|
/// @note No-op for non-player attackers
|
||||||
|
virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||||
|
|
||||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||||
/// @param container The container the item is in; may be empty for an item in the world
|
/// @param container The container the item is in; may be empty for an item in the world
|
||||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||||
|
@ -211,6 +217,8 @@ namespace MWBase
|
||||||
|
|
||||||
/// Has the player stolen this item from the given owner?
|
/// Has the player stolen this item from the given owner?
|
||||||
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
|
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
|
||||||
|
|
||||||
|
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,20 +25,16 @@
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
bool isGold (const MWWorld::Ptr& ptr)
|
|
||||||
{
|
|
||||||
return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001")
|
|
||||||
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005")
|
|
||||||
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010")
|
|
||||||
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025")
|
|
||||||
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
|
bool Miscellaneous::isGold (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001")
|
||||||
|
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005")
|
||||||
|
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010")
|
||||||
|
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025")
|
||||||
|
|| Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100");
|
||||||
|
}
|
||||||
std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const
|
std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
return ptr.get<ESM::Miscellaneous>()->mBase->mId;
|
return ptr.get<ESM::Miscellaneous>()->mBase->mId;
|
||||||
|
|
|
@ -62,6 +62,8 @@ namespace MWClass
|
||||||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||||
|
|
||||||
virtual bool isKey (const MWWorld::Ptr &ptr) const;
|
virtual bool isKey (const MWWorld::Ptr &ptr) const;
|
||||||
|
|
||||||
|
virtual bool isGold (const MWWorld::Ptr& ptr) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -751,12 +751,7 @@ namespace MWClass
|
||||||
attacker.getClass().getNpcStats(attacker).addWerewolfKill();
|
attacker.getClass().getNpcStats(attacker).addWerewolfKill();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
|
||||||
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
|
||||||
// for bystanders it is not possible to tell who attacked first, anyway.
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
|
||||||
if (attacker == player && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 && ptr != player)
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <components/esm/loaddial.hpp>
|
#include <components/esm/loaddial.hpp>
|
||||||
#include <components/esm/loadinfo.hpp>
|
#include <components/esm/loadinfo.hpp>
|
||||||
#include <components/esm/dialoguestate.hpp>
|
#include <components/esm/dialoguestate.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include <components/compiler/exception.hpp>
|
#include <components/compiler/exception.hpp>
|
||||||
#include <components/compiler/errorhandler.hpp>
|
#include <components/compiler/errorhandler.hpp>
|
||||||
|
|
|
@ -203,6 +203,8 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
||||||
return false; // script does not have a variable of this name.
|
return false; // script does not have a variable of this name.
|
||||||
|
|
||||||
int index = localDefs.getIndex (name);
|
int index = localDefs.getIndex (name);
|
||||||
|
if (index < 0)
|
||||||
|
return false; // shouldn't happen, we checked that variable has a type above, so must exist
|
||||||
|
|
||||||
const MWScript::Locals& locals = mActor.getRefData().getLocals();
|
const MWScript::Locals& locals = mActor.getRefData().getLocals();
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#include <MyGUI_ImageBox.h>
|
#include <MyGUI_ImageBox.h>
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
|
|
||||||
#include <components/esm/records.hpp>
|
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
|
@ -132,134 +132,141 @@ namespace MWGui
|
||||||
|
|
||||||
void CharacterCreation::spawnDialog(const char id)
|
void CharacterCreation::spawnDialog(const char id)
|
||||||
{
|
{
|
||||||
switch (id)
|
try
|
||||||
{
|
{
|
||||||
case GM_Name:
|
switch (id)
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog);
|
{
|
||||||
mNameDialog = 0;
|
case GM_Name:
|
||||||
mNameDialog = new TextInputDialog();
|
MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog);
|
||||||
mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name"));
|
mNameDialog = 0;
|
||||||
mNameDialog->setTextInput(mPlayerName);
|
mNameDialog = new TextInputDialog();
|
||||||
mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen);
|
mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name"));
|
||||||
mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone);
|
mNameDialog->setTextInput(mPlayerName);
|
||||||
mNameDialog->setVisible(true);
|
mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen);
|
||||||
break;
|
mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone);
|
||||||
|
mNameDialog->setVisible(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case GM_Race:
|
case GM_Race:
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog);
|
MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog);
|
||||||
mRaceDialog = 0;
|
mRaceDialog = 0;
|
||||||
mRaceDialog = new RaceDialog(mViewer, mResourceSystem);
|
mRaceDialog = new RaceDialog(mViewer, mResourceSystem);
|
||||||
mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen);
|
mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen);
|
||||||
mRaceDialog->setRaceId(mPlayerRaceId);
|
mRaceDialog->setRaceId(mPlayerRaceId);
|
||||||
mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
|
mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
|
||||||
mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
|
mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
|
||||||
mRaceDialog->setVisible(true);
|
mRaceDialog->setVisible(true);
|
||||||
if (mCreationStage < CSE_NameChosen)
|
if (mCreationStage < CSE_NameChosen)
|
||||||
mCreationStage = CSE_NameChosen;
|
mCreationStage = CSE_NameChosen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GM_Class:
|
case GM_Class:
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog);
|
MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog);
|
||||||
mClassChoiceDialog = 0;
|
mClassChoiceDialog = 0;
|
||||||
mClassChoiceDialog = new ClassChoiceDialog();
|
mClassChoiceDialog = new ClassChoiceDialog();
|
||||||
mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
|
mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
|
||||||
mClassChoiceDialog->setVisible(true);
|
mClassChoiceDialog->setVisible(true);
|
||||||
if (mCreationStage < CSE_RaceChosen)
|
if (mCreationStage < CSE_RaceChosen)
|
||||||
mCreationStage = CSE_RaceChosen;
|
mCreationStage = CSE_RaceChosen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GM_ClassPick:
|
case GM_ClassPick:
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog);
|
MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog);
|
||||||
mPickClassDialog = 0;
|
mPickClassDialog = 0;
|
||||||
mPickClassDialog = new PickClassDialog();
|
mPickClassDialog = new PickClassDialog();
|
||||||
mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
|
mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
|
||||||
mPickClassDialog->setClassId(mPlayerClass.mName);
|
mPickClassDialog->setClassId(mPlayerClass.mName);
|
||||||
mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
|
mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
|
||||||
mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
|
mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
|
||||||
mPickClassDialog->setVisible(true);
|
mPickClassDialog->setVisible(true);
|
||||||
if (mCreationStage < CSE_RaceChosen)
|
if (mCreationStage < CSE_RaceChosen)
|
||||||
mCreationStage = CSE_RaceChosen;
|
mCreationStage = CSE_RaceChosen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GM_Birth:
|
case GM_Birth:
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog);
|
MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog);
|
||||||
mBirthSignDialog = 0;
|
mBirthSignDialog = 0;
|
||||||
mBirthSignDialog = new BirthDialog();
|
mBirthSignDialog = new BirthDialog();
|
||||||
mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen);
|
mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen);
|
||||||
mBirthSignDialog->setBirthId(mPlayerBirthSignId);
|
mBirthSignDialog->setBirthId(mPlayerBirthSignId);
|
||||||
mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
|
mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
|
||||||
mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
|
mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
|
||||||
mBirthSignDialog->setVisible(true);
|
mBirthSignDialog->setVisible(true);
|
||||||
if (mCreationStage < CSE_ClassChosen)
|
if (mCreationStage < CSE_ClassChosen)
|
||||||
mCreationStage = CSE_ClassChosen;
|
mCreationStage = CSE_ClassChosen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GM_ClassCreate:
|
case GM_ClassCreate:
|
||||||
if (!mCreateClassDialog)
|
if (!mCreateClassDialog)
|
||||||
{
|
|
||||||
mCreateClassDialog = new CreateClassDialog();
|
|
||||||
mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
|
|
||||||
mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
|
|
||||||
}
|
|
||||||
mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
|
|
||||||
mCreateClassDialog->setVisible(true);
|
|
||||||
if (mCreationStage < CSE_RaceChosen)
|
|
||||||
mCreationStage = CSE_RaceChosen;
|
|
||||||
break;
|
|
||||||
case GM_ClassGenerate:
|
|
||||||
mGenerateClassStep = 0;
|
|
||||||
mGenerateClass = "";
|
|
||||||
mGenerateClassSpecializations[0] = 0;
|
|
||||||
mGenerateClassSpecializations[1] = 0;
|
|
||||||
mGenerateClassSpecializations[2] = 0;
|
|
||||||
showClassQuestionDialog();
|
|
||||||
if (mCreationStage < CSE_RaceChosen)
|
|
||||||
mCreationStage = CSE_RaceChosen;
|
|
||||||
break;
|
|
||||||
case GM_Review:
|
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog);
|
|
||||||
mReviewDialog = 0;
|
|
||||||
mReviewDialog = new ReviewDialog();
|
|
||||||
mReviewDialog->setPlayerName(mPlayerName);
|
|
||||||
mReviewDialog->setRace(mPlayerRaceId);
|
|
||||||
mReviewDialog->setClass(mPlayerClass);
|
|
||||||
mReviewDialog->setBirthSign(mPlayerBirthSignId);
|
|
||||||
|
|
||||||
{
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
|
||||||
const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
|
||||||
|
|
||||||
mReviewDialog->setHealth ( stats.getHealth() );
|
|
||||||
mReviewDialog->setMagicka( stats.getMagicka() );
|
|
||||||
mReviewDialog->setFatigue( stats.getFatigue() );
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
|
|
||||||
for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin();
|
|
||||||
it != attributes.end(); ++it)
|
|
||||||
{
|
{
|
||||||
mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second);
|
mCreateClassDialog = new CreateClassDialog();
|
||||||
|
mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
|
||||||
|
mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
|
||||||
}
|
}
|
||||||
}
|
mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
|
||||||
|
mCreateClassDialog->setVisible(true);
|
||||||
|
if (mCreationStage < CSE_RaceChosen)
|
||||||
|
mCreationStage = CSE_RaceChosen;
|
||||||
|
break;
|
||||||
|
case GM_ClassGenerate:
|
||||||
|
mGenerateClassStep = 0;
|
||||||
|
mGenerateClass = "";
|
||||||
|
mGenerateClassSpecializations[0] = 0;
|
||||||
|
mGenerateClassSpecializations[1] = 0;
|
||||||
|
mGenerateClassSpecializations[2] = 0;
|
||||||
|
showClassQuestionDialog();
|
||||||
|
if (mCreationStage < CSE_RaceChosen)
|
||||||
|
mCreationStage = CSE_RaceChosen;
|
||||||
|
break;
|
||||||
|
case GM_Review:
|
||||||
|
MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog);
|
||||||
|
mReviewDialog = 0;
|
||||||
|
mReviewDialog = new ReviewDialog();
|
||||||
|
mReviewDialog->setPlayerName(mPlayerName);
|
||||||
|
mReviewDialog->setRace(mPlayerRaceId);
|
||||||
|
mReviewDialog->setClass(mPlayerClass);
|
||||||
|
mReviewDialog->setBirthSign(mPlayerBirthSignId);
|
||||||
|
|
||||||
{
|
|
||||||
std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
|
|
||||||
for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin();
|
|
||||||
it != skills.end(); ++it)
|
|
||||||
{
|
{
|
||||||
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second);
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
}
|
const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||||
mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills());
|
|
||||||
}
|
|
||||||
|
|
||||||
mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
|
mReviewDialog->setHealth ( stats.getHealth() );
|
||||||
mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
|
mReviewDialog->setMagicka( stats.getMagicka() );
|
||||||
mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
|
mReviewDialog->setFatigue( stats.getFatigue() );
|
||||||
mReviewDialog->setVisible(true);
|
}
|
||||||
if (mCreationStage < CSE_BirthSignChosen)
|
|
||||||
mCreationStage = CSE_BirthSignChosen;
|
{
|
||||||
break;
|
std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
|
||||||
|
for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin();
|
||||||
|
it != attributes.end(); ++it)
|
||||||
|
{
|
||||||
|
mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
|
||||||
|
for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin();
|
||||||
|
it != skills.end(); ++it)
|
||||||
|
{
|
||||||
|
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second);
|
||||||
|
}
|
||||||
|
mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills());
|
||||||
|
}
|
||||||
|
|
||||||
|
mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
|
||||||
|
mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
|
||||||
|
mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
|
||||||
|
mReviewDialog->setVisible(true);
|
||||||
|
if (mCreationStage < CSE_BirthSignChosen)
|
||||||
|
mCreationStage = CSE_BirthSignChosen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to create chargen window: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "companionitemmodel.hpp"
|
#include "companionitemmodel.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
|
@ -3,11 +3,8 @@
|
||||||
#include <MyGUI_InputManager.h>
|
#include <MyGUI_InputManager.h>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "messagebox.hpp"
|
#include "messagebox.hpp"
|
||||||
|
|
|
@ -11,13 +11,11 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
|
||||||
|
|
||||||
#include "../mwmechanics/pickpocket.hpp"
|
#include "../mwmechanics/pickpocket.hpp"
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
#include "countdialog.hpp"
|
#include "countdialog.hpp"
|
||||||
#include "tradewindow.hpp"
|
|
||||||
#include "inventorywindow.hpp"
|
#include "inventorywindow.hpp"
|
||||||
|
|
||||||
#include "itemview.hpp"
|
#include "itemview.hpp"
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/containerstore.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
#include "bookpage.hpp"
|
#include "bookpage.hpp"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <MyGUI_Button.h>
|
#include <MyGUI_Button.h>
|
||||||
#include <MyGUI_ScrollView.h>
|
#include <MyGUI_ScrollView.h>
|
||||||
|
|
||||||
#include <components/esm/records.hpp>
|
|
||||||
#include <components/widgets/list.hpp>
|
#include <components/widgets/list.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
@ -518,7 +517,19 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
mCrosshair->setVisible (visible);
|
mCrosshair->setVisible (visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HUD::setCrosshairOwned(bool owned)
|
||||||
|
{
|
||||||
|
if(owned)
|
||||||
|
{
|
||||||
|
mCrosshair->changeWidgetSkin("HUD_Crosshair_Owned");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCrosshair->changeWidgetSkin("HUD_Crosshair");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HUD::setHmsVisible(bool visible)
|
void HUD::setHmsVisible(bool visible)
|
||||||
{
|
{
|
||||||
mHealth->setVisible(visible);
|
mHealth->setVisible(visible);
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace MWGui
|
||||||
void unsetSelectedWeapon();
|
void unsetSelectedWeapon();
|
||||||
|
|
||||||
void setCrosshairVisible(bool visible);
|
void setCrosshairVisible(bool visible);
|
||||||
|
void setCrosshairOwned(bool owned);
|
||||||
|
|
||||||
void onFrame(float dt);
|
void onFrame(float dt);
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
@ -19,12 +21,12 @@
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/action.hpp"
|
#include "../mwworld/action.hpp"
|
||||||
#include "../mwscript/interpretercontext.hpp"
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
#include "../mwbase/scriptmanager.hpp"
|
|
||||||
#include "../mwrender/characterpreview.hpp"
|
#include "../mwrender/characterpreview.hpp"
|
||||||
|
|
||||||
#include "itemview.hpp"
|
#include "itemview.hpp"
|
||||||
|
@ -432,6 +434,20 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
const std::string& script = ptr.getClass().getScript(ptr);
|
const std::string& script = ptr.getClass().getScript(ptr);
|
||||||
|
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
|
// early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case
|
||||||
|
if (!ptr.getClass().getEquipmentSlots(ptr).first.empty())
|
||||||
|
{
|
||||||
|
std::pair<int, std::string> canEquip = ptr.getClass().canBeEquipped(ptr, player);
|
||||||
|
if (canEquip.first == 0)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second);
|
||||||
|
updateItemView();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the item has a script, set its OnPcEquip to 1
|
// If the item has a script, set its OnPcEquip to 1
|
||||||
if (!script.empty()
|
if (!script.empty()
|
||||||
// Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards,
|
// Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards,
|
||||||
|
@ -451,7 +467,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
boost::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr);
|
boost::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr);
|
||||||
|
|
||||||
action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
|
action->execute (player);
|
||||||
|
|
||||||
mSkippedToEquip = MWWorld::Ptr();
|
mSkippedToEquip = MWWorld::Ptr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,7 @@
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
|
||||||
#include "../mwbase/statemanager.hpp"
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
#include <MyGUI_RenderManager.h>
|
#include <MyGUI_RenderManager.h>
|
||||||
|
|
||||||
#include <components/version/version.hpp>
|
|
||||||
|
|
||||||
#include <components/widgets/imagebutton.hpp>
|
#include <components/widgets/imagebutton.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
@ -14,12 +12,8 @@
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/journal.hpp"
|
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
|
||||||
#include "../mwbase/statemanager.hpp"
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
#include "../mwstate/character.hpp"
|
|
||||||
|
|
||||||
#include "savegamedialog.hpp"
|
#include "savegamedialog.hpp"
|
||||||
#include "confirmationdialog.hpp"
|
#include "confirmationdialog.hpp"
|
||||||
#include "backgroundimage.hpp"
|
#include "backgroundimage.hpp"
|
||||||
|
@ -28,7 +22,7 @@
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs)
|
MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription)
|
||||||
: Layout("openmw_mainmenu.layout")
|
: Layout("openmw_mainmenu.layout")
|
||||||
, mWidth (w), mHeight (h)
|
, mWidth (w), mHeight (h)
|
||||||
, mVFS(vfs), mButtonBox(0)
|
, mVFS(vfs), mButtonBox(0)
|
||||||
|
@ -38,20 +32,7 @@ namespace MWGui
|
||||||
, mSaveGameDialog(NULL)
|
, mSaveGameDialog(NULL)
|
||||||
{
|
{
|
||||||
getWidget(mVersionText, "VersionText");
|
getWidget(mVersionText, "VersionText");
|
||||||
std::stringstream sstream;
|
mVersionText->setCaption(versionDescription);
|
||||||
sstream << "OpenMW Version: " << OPENMW_VERSION;
|
|
||||||
|
|
||||||
// adding info about git hash if available
|
|
||||||
std::string rev = OPENMW_VERSION_COMMITHASH;
|
|
||||||
std::string tag = OPENMW_VERSION_TAGHASH;
|
|
||||||
if (!rev.empty() && !tag.empty())
|
|
||||||
{
|
|
||||||
rev = rev.substr(0,10);
|
|
||||||
sstream << "\nRevision: " << rev;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string output = sstream.str();
|
|
||||||
mVersionText->setCaption(output);
|
|
||||||
|
|
||||||
mHasAnimatedMenu = mVFS->exists("video/menu_background.bik");
|
mHasAnimatedMenu = mVFS->exists("video/menu_background.bik");
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace MWGui
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MainMenu(int w, int h, const VFS::Manager* vfs);
|
MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription);
|
||||||
~MainMenu();
|
~MainMenu();
|
||||||
|
|
||||||
void onResChange(int w, int h);
|
void onResChange(int w, int h);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <MyGUI_FactoryManager.h>
|
#include <MyGUI_FactoryManager.h>
|
||||||
|
|
||||||
#include <components/esm/globalmap.hpp>
|
#include <components/esm/globalmap.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
|
@ -26,7 +27,6 @@
|
||||||
#include "../mwrender/globalmap.hpp"
|
#include "../mwrender/globalmap.hpp"
|
||||||
#include "../mwrender/localmap.hpp"
|
#include "../mwrender/localmap.hpp"
|
||||||
|
|
||||||
#include "widgets.hpp"
|
|
||||||
#include "confirmationdialog.hpp"
|
#include "confirmationdialog.hpp"
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ namespace
|
||||||
|
|
||||||
enum LocalMapWidgetDepth
|
enum LocalMapWidgetDepth
|
||||||
{
|
{
|
||||||
Local_CompassLayer = 0,
|
Local_MarkerAboveFogLayer = 0,
|
||||||
Local_MarkerAboveFogLayer = 1,
|
Local_CompassLayer = 1,
|
||||||
Local_FogLayer = 2,
|
Local_FogLayer = 2,
|
||||||
Local_MarkerLayer = 3,
|
Local_MarkerLayer = 3,
|
||||||
Local_MapLayer = 4
|
Local_MapLayer = 4
|
||||||
|
@ -91,31 +91,41 @@ namespace MWGui
|
||||||
|
|
||||||
void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent)
|
void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent)
|
||||||
{
|
{
|
||||||
mMarkers.push_back(marker);
|
mMarkers.insert(std::make_pair(marker.mCell, marker));
|
||||||
if (triggerEvent)
|
if (triggerEvent)
|
||||||
eventMarkersChanged();
|
eventMarkersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker)
|
void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker)
|
||||||
{
|
{
|
||||||
std::vector<ESM::CustomMarker>::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker);
|
std::pair<ContainerType::iterator, ContainerType::iterator> range = mMarkers.equal_range(marker.mCell);
|
||||||
if (it != mMarkers.end())
|
|
||||||
mMarkers.erase(it);
|
|
||||||
else
|
|
||||||
throw std::runtime_error("can't find marker to delete");
|
|
||||||
|
|
||||||
eventMarkersChanged();
|
for (ContainerType::iterator it = range.first; it != range.second; ++it)
|
||||||
|
{
|
||||||
|
if (it->second == marker)
|
||||||
|
{
|
||||||
|
mMarkers.erase(it);
|
||||||
|
eventMarkersChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("can't find marker to delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote)
|
void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote)
|
||||||
{
|
{
|
||||||
std::vector<ESM::CustomMarker>::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker);
|
std::pair<ContainerType::iterator, ContainerType::iterator> range = mMarkers.equal_range(marker.mCell);
|
||||||
if (it != mMarkers.end())
|
|
||||||
it->mNote = newNote;
|
|
||||||
else
|
|
||||||
throw std::runtime_error("can't find marker to update");
|
|
||||||
|
|
||||||
eventMarkersChanged();
|
for (ContainerType::iterator it = range.first; it != range.second; ++it)
|
||||||
|
{
|
||||||
|
if (it->second == marker)
|
||||||
|
{
|
||||||
|
it->second.mNote = newNote;
|
||||||
|
eventMarkersChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("can't find marker to update");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomMarkerCollection::clear()
|
void CustomMarkerCollection::clear()
|
||||||
|
@ -124,16 +134,21 @@ namespace MWGui
|
||||||
eventMarkersChanged();
|
eventMarkersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::CustomMarker>::const_iterator CustomMarkerCollection::begin() const
|
CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::begin() const
|
||||||
{
|
{
|
||||||
return mMarkers.begin();
|
return mMarkers.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::CustomMarker>::const_iterator CustomMarkerCollection::end() const
|
CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::end() const
|
||||||
{
|
{
|
||||||
return mMarkers.end();
|
return mMarkers.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId &cellId) const
|
||||||
|
{
|
||||||
|
return mMarkers.equal_range(cellId);
|
||||||
|
}
|
||||||
|
|
||||||
size_t CustomMarkerCollection::size() const
|
size_t CustomMarkerCollection::size() const
|
||||||
{
|
{
|
||||||
return mMarkers.size();
|
return mMarkers.size();
|
||||||
|
@ -298,44 +313,43 @@ namespace MWGui
|
||||||
MyGUI::Gui::getInstance().destroyWidget(*it);
|
MyGUI::Gui::getInstance().destroyWidget(*it);
|
||||||
mCustomMarkerWidgets.clear();
|
mCustomMarkerWidgets.clear();
|
||||||
|
|
||||||
for (std::vector<ESM::CustomMarker>::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it)
|
for (int dX = -1; dX <= 1; ++dX)
|
||||||
{
|
{
|
||||||
const ESM::CustomMarker& marker = *it;
|
for (int dY =-1; dY <= 1; ++dY)
|
||||||
|
|
||||||
if (marker.mCell.mPaged != !mInterior)
|
|
||||||
continue;
|
|
||||||
if (mInterior)
|
|
||||||
{
|
{
|
||||||
if (marker.mCell.mWorldspace != mPrefix)
|
ESM::CellId cellId;
|
||||||
continue;
|
cellId.mPaged = !mInterior;
|
||||||
}
|
cellId.mWorldspace = (mInterior ? mPrefix : "sys::default");
|
||||||
else
|
cellId.mIndex.mX = mCurX+dX;
|
||||||
{
|
cellId.mIndex.mY = mCurY+dY;
|
||||||
if (std::abs(marker.mCell.mIndex.mX - mCurX) > 1)
|
|
||||||
continue;
|
|
||||||
if (std::abs(marker.mCell.mIndex.mY - mCurY) > 1)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkerUserData markerPos (mLocalMapRender);
|
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId);
|
||||||
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos);
|
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it)
|
||||||
|
{
|
||||||
|
const ESM::CustomMarker& marker = it->second;
|
||||||
|
|
||||||
MyGUI::IntCoord widgetCoord(widgetPos.left - 8,
|
MarkerUserData markerPos (mLocalMapRender);
|
||||||
widgetPos.top - 8,
|
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos);
|
||||||
16, 16);
|
|
||||||
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("CustomMarkerButton",
|
MyGUI::IntCoord widgetCoord(widgetPos.left - 8,
|
||||||
widgetCoord, MyGUI::Align::Default);
|
widgetPos.top - 8,
|
||||||
markerWidget->setDepth(Local_MarkerAboveFogLayer);
|
16, 16);
|
||||||
markerWidget->setUserString("ToolTipType", "Layout");
|
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("CustomMarkerButton",
|
||||||
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
widgetCoord, MyGUI::Align::Default);
|
||||||
markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote));
|
markerWidget->setDepth(Local_MarkerAboveFogLayer);
|
||||||
markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f));
|
markerWidget->setUserString("ToolTipType", "Layout");
|
||||||
markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f));
|
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
||||||
markerWidget->setUserData(marker);
|
markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote));
|
||||||
markerWidget->setNeedMouseFocus(true);
|
markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f));
|
||||||
customMarkerCreated(markerWidget);
|
markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f));
|
||||||
mCustomMarkerWidgets.push_back(markerWidget);
|
markerWidget->setUserData(marker);
|
||||||
|
markerWidget->setNeedMouseFocus(true);
|
||||||
|
customMarkerCreated(markerWidget);
|
||||||
|
mCustomMarkerWidgets.push_back(markerWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,11 +424,9 @@ namespace MWGui
|
||||||
MWBase::World::DoorMarker marker = *it;
|
MWBase::World::DoorMarker marker = *it;
|
||||||
|
|
||||||
std::vector<std::string> destNotes;
|
std::vector<std::string> destNotes;
|
||||||
for (std::vector<ESM::CustomMarker>::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it)
|
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest);
|
||||||
{
|
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it)
|
||||||
if (it->mCell == marker.dest)
|
destNotes.push_back(it->second.mNote);
|
||||||
destNotes.push_back(it->mNote);
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkerUserData data (mLocalMapRender);
|
MarkerUserData data (mLocalMapRender);
|
||||||
data.notes = destNotes;
|
data.notes = destNotes;
|
||||||
|
@ -770,15 +782,19 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::Widget* markerWidget = mGlobalMap->createWidget<MyGUI::Widget>("MarkerButton",
|
MyGUI::Widget* markerWidget = mGlobalMap->createWidget<MyGUI::Widget>("MarkerButton",
|
||||||
widgetCoord, MyGUI::Align::Default);
|
widgetCoord, MyGUI::Align::Default);
|
||||||
|
|
||||||
|
markerWidget->setUserString("Caption_TextOneLine", name);
|
||||||
|
|
||||||
|
setGlobalMapMarkerTooltip(markerWidget, x, y);
|
||||||
|
|
||||||
|
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
||||||
|
|
||||||
markerWidget->setNeedMouseFocus(true);
|
markerWidget->setNeedMouseFocus(true);
|
||||||
markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
|
markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
|
||||||
markerWidget->setUserString("ToolTipType", "Layout");
|
|
||||||
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
|
||||||
markerWidget->setUserString("Caption_TextOneLine", name);
|
|
||||||
markerWidget->setDepth(Global_MarkerLayer);
|
markerWidget->setDepth(Global_MarkerLayer);
|
||||||
markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
||||||
markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
||||||
mGlobalMapMarkers.push_back(markerWidget);
|
mGlobalMapMarkers[std::make_pair(x,y)] = markerWidget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,6 +819,45 @@ namespace MWGui
|
||||||
NoDrop::onFrame(dt);
|
NoDrop::onFrame(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y)
|
||||||
|
{
|
||||||
|
ESM::CellId cellId;
|
||||||
|
cellId.mIndex.mX = x;
|
||||||
|
cellId.mIndex.mY = y;
|
||||||
|
cellId.mWorldspace = "sys::default";
|
||||||
|
cellId.mPaged = true;
|
||||||
|
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId);
|
||||||
|
std::vector<std::string> destNotes;
|
||||||
|
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it)
|
||||||
|
destNotes.push_back(it->second.mNote);
|
||||||
|
|
||||||
|
if (!destNotes.empty())
|
||||||
|
{
|
||||||
|
MarkerUserData data (NULL);
|
||||||
|
data.notes = destNotes;
|
||||||
|
data.caption = markerWidget->getUserString("Caption_TextOneLine");
|
||||||
|
markerWidget->setUserData(data);
|
||||||
|
markerWidget->setUserString("ToolTipType", "MapMarker");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
markerWidget->setUserString("ToolTipType", "Layout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapWindow::updateCustomMarkers()
|
||||||
|
{
|
||||||
|
LocalMapBase::updateCustomMarkers();
|
||||||
|
|
||||||
|
for (std::map<std::pair<int, int>, MyGUI::Widget*>::iterator widgetIt = mGlobalMapMarkers.begin(); widgetIt != mGlobalMapMarkers.end(); ++widgetIt)
|
||||||
|
{
|
||||||
|
int x = widgetIt->first.first;
|
||||||
|
int y = widgetIt->first.second;
|
||||||
|
MyGUI::Widget* markerWidget = widgetIt->second;
|
||||||
|
setGlobalMapMarkerTooltip(markerWidget, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||||
{
|
{
|
||||||
if (_id!=MyGUI::MouseButton::Left) return;
|
if (_id!=MyGUI::MouseButton::Left) return;
|
||||||
|
@ -900,8 +955,8 @@ namespace MWGui
|
||||||
mGlobalMapRender->clear();
|
mGlobalMapRender->clear();
|
||||||
mChanged = true;
|
mChanged = true;
|
||||||
|
|
||||||
for (std::vector<MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it)
|
for (std::map<std::pair<int, int>, MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it)
|
||||||
MyGUI::Gui::getInstance().destroyWidget(*it);
|
MyGUI::Gui::getInstance().destroyWidget(it->second);
|
||||||
mGlobalMapMarkers.clear();
|
mGlobalMapMarkers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1021,6 +1076,8 @@ namespace MWGui
|
||||||
|
|
||||||
bool LocalMapBase::MarkerUserData::isPositionExplored() const
|
bool LocalMapBase::MarkerUserData::isPositionExplored() const
|
||||||
{
|
{
|
||||||
|
if (!mLocalMapRender)
|
||||||
|
return true;
|
||||||
return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior);
|
return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,20 @@ namespace MWGui
|
||||||
|
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
|
||||||
std::vector<ESM::CustomMarker>::const_iterator begin() const;
|
typedef std::multimap<ESM::CellId, ESM::CustomMarker> ContainerType;
|
||||||
std::vector<ESM::CustomMarker>::const_iterator end() const;
|
|
||||||
|
typedef std::pair<ContainerType::const_iterator, ContainerType::const_iterator> RangeType;
|
||||||
|
|
||||||
|
ContainerType::const_iterator begin() const;
|
||||||
|
ContainerType::const_iterator end() const;
|
||||||
|
|
||||||
|
RangeType getMarkers(const ESM::CellId& cellId) const;
|
||||||
|
|
||||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||||
EventHandle_Void eventMarkersChanged;
|
EventHandle_Void eventMarkersChanged;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<ESM::CustomMarker> mMarkers;
|
ContainerType mMarkers;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LocalMapBase
|
class LocalMapBase
|
||||||
|
@ -120,7 +126,7 @@ namespace MWGui
|
||||||
std::vector<MyGUI::Widget*> mMagicMarkerWidgets;
|
std::vector<MyGUI::Widget*> mMagicMarkerWidgets;
|
||||||
std::vector<MyGUI::Widget*> mCustomMarkerWidgets;
|
std::vector<MyGUI::Widget*> mCustomMarkerWidgets;
|
||||||
|
|
||||||
void updateCustomMarkers();
|
virtual void updateCustomMarkers();
|
||||||
|
|
||||||
void applyFogOfWar();
|
void applyFogOfWar();
|
||||||
|
|
||||||
|
@ -197,6 +203,8 @@ namespace MWGui
|
||||||
|
|
||||||
void onFrame(float dt);
|
void onFrame(float dt);
|
||||||
|
|
||||||
|
virtual void updateCustomMarkers();
|
||||||
|
|
||||||
/// Clear all savegame-specific data
|
/// Clear all savegame-specific data
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
@ -215,6 +223,7 @@ namespace MWGui
|
||||||
void onNoteDoubleClicked(MyGUI::Widget* sender);
|
void onNoteDoubleClicked(MyGUI::Widget* sender);
|
||||||
void onChangeScrollWindowCoord(MyGUI::Widget* sender);
|
void onChangeScrollWindowCoord(MyGUI::Widget* sender);
|
||||||
void globalMapUpdatePlayer();
|
void globalMapUpdatePlayer();
|
||||||
|
void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y);
|
||||||
|
|
||||||
MyGUI::ScrollView* mGlobalMap;
|
MyGUI::ScrollView* mGlobalMap;
|
||||||
std::auto_ptr<MyGUI::ITexture> mGlobalMapTexture;
|
std::auto_ptr<MyGUI::ITexture> mGlobalMapTexture;
|
||||||
|
@ -242,7 +251,7 @@ namespace MWGui
|
||||||
|
|
||||||
MWRender::GlobalMap* mGlobalMapRender;
|
MWRender::GlobalMap* mGlobalMapRender;
|
||||||
|
|
||||||
std::vector<MyGUI::Widget*> mGlobalMapMarkers;
|
std::map<std::pair<int, int>, MyGUI::Widget*> mGlobalMapMarkers;
|
||||||
|
|
||||||
EditNoteDialog mEditNoteDialog;
|
EditNoteDialog mEditNoteDialog;
|
||||||
ESM::CustomMarker mEditingMarker;
|
ESM::CustomMarker mEditingMarker;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "pickpocketitemmodel.hpp"
|
#include "pickpocketitemmodel.hpp"
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/esm/loadskil.hpp>
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
#include <MyGUI_ImageBox.h>
|
#include <MyGUI_ImageBox.h>
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/quickkeys.hpp>
|
#include <components/esm/quickkeys.hpp>
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
@ -14,18 +15,15 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
#include "../mwgui/inventorywindow.hpp"
|
#include "../mwgui/inventorywindow.hpp"
|
||||||
|
|
||||||
#include "windowmanagerimp.hpp"
|
|
||||||
#include "itemselection.hpp"
|
#include "itemselection.hpp"
|
||||||
|
|
||||||
#include "spellview.hpp"
|
#include "spellview.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "itemwidget.hpp"
|
#include "itemwidget.hpp"
|
||||||
#include "sortfilteritemmodel.hpp"
|
#include "sortfilteritemmodel.hpp"
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include <components/esm/records.hpp>
|
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
|
@ -233,6 +233,7 @@ namespace MWGui
|
||||||
if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE)
|
if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE)
|
||||||
mResolutionList->addItem(str);
|
mResolutionList->addItem(str);
|
||||||
}
|
}
|
||||||
|
highlightCurrentResolution();
|
||||||
|
|
||||||
std::string tf = Settings::Manager::getString("texture filtering", "General");
|
std::string tf = Settings::Manager::getString("texture filtering", "General");
|
||||||
mTextureFilteringButton->setCaption(textureFilteringToStr(tf));
|
mTextureFilteringButton->setCaption(textureFilteringToStr(tf));
|
||||||
|
@ -299,8 +300,28 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::onResolutionCancel()
|
void SettingsWindow::onResolutionCancel()
|
||||||
|
{
|
||||||
|
highlightCurrentResolution();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::highlightCurrentResolution()
|
||||||
{
|
{
|
||||||
mResolutionList->setIndexSelected(MyGUI::ITEM_NONE);
|
mResolutionList->setIndexSelected(MyGUI::ITEM_NONE);
|
||||||
|
|
||||||
|
int currentX = Settings::Manager::getInt("resolution x", "Video");
|
||||||
|
int currentY = Settings::Manager::getInt("resolution y", "Video");
|
||||||
|
|
||||||
|
for (size_t i=0; i<mResolutionList->getItemCount(); ++i)
|
||||||
|
{
|
||||||
|
int resX, resY;
|
||||||
|
parseResolution (resX, resY, mResolutionList->getItemNameAt(i));
|
||||||
|
|
||||||
|
if (resX == currentX && resY == currentY)
|
||||||
|
{
|
||||||
|
mResolutionList->setIndexSelected(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos)
|
void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos)
|
||||||
|
|
|
@ -59,6 +59,7 @@ namespace MWGui
|
||||||
void onResolutionSelected(MyGUI::ListBox* _sender, size_t index);
|
void onResolutionSelected(MyGUI::ListBox* _sender, size_t index);
|
||||||
void onResolutionAccept();
|
void onResolutionAccept();
|
||||||
void onResolutionCancel();
|
void onResolutionCancel();
|
||||||
|
void highlightCurrentResolution();
|
||||||
|
|
||||||
void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos);
|
void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/containerstore.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace MWGui
|
||||||
, mLastMouseY(0)
|
, mLastMouseY(0)
|
||||||
, mEnabled(true)
|
, mEnabled(true)
|
||||||
, mFullHelp(false)
|
, mFullHelp(false)
|
||||||
|
, mShowOwned(0)
|
||||||
{
|
{
|
||||||
getWidget(mDynamicToolTipBox, "DynamicToolTipBox");
|
getWidget(mDynamicToolTipBox, "DynamicToolTipBox");
|
||||||
|
|
||||||
|
@ -55,6 +56,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
mMainWidget->getChildAt(i)->setVisible(false);
|
mMainWidget->getChildAt(i)->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mShowOwned = Settings::Manager::getInt("show owned", "Game");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolTips::setEnabled(bool enabled)
|
void ToolTips::setEnabled(bool enabled)
|
||||||
|
@ -346,10 +349,41 @@ namespace MWGui
|
||||||
|
|
||||||
return tooltipSize;
|
return tooltipSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ToolTips::checkOwned()
|
||||||
|
{
|
||||||
|
if(!mFocusObject.isEmpty())
|
||||||
|
{
|
||||||
|
const MWWorld::CellRef& cellref = mFocusObject.getCellRef();
|
||||||
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
MWWorld::Ptr victim;
|
||||||
|
|
||||||
|
MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager();
|
||||||
|
bool allowed = mm->isAllowedToUse(ptr, cellref, victim);
|
||||||
|
|
||||||
|
return !allowed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
|
MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
|
||||||
{
|
{
|
||||||
mDynamicToolTipBox->setVisible(true);
|
mDynamicToolTipBox->setVisible(true);
|
||||||
|
|
||||||
|
if(mShowOwned == 1 || mShowOwned == 3)
|
||||||
|
{
|
||||||
|
if(checkOwned())
|
||||||
|
{
|
||||||
|
mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string caption = info.caption;
|
std::string caption = info.caption;
|
||||||
std::string image = info.icon;
|
std::string image = info.icon;
|
||||||
|
|
|
@ -87,7 +87,10 @@ namespace MWGui
|
||||||
static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace);
|
static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace);
|
||||||
static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass);
|
static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass);
|
||||||
static void createMagicEffectToolTip(MyGUI::Widget* widget, short id);
|
static void createMagicEffectToolTip(MyGUI::Widget* widget, short id);
|
||||||
|
|
||||||
|
bool checkOwned();
|
||||||
|
/// Returns True if taking mFocusObject would be crime
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MyGUI::Widget* mDynamicToolTipBox;
|
MyGUI::Widget* mDynamicToolTipBox;
|
||||||
|
|
||||||
|
@ -119,6 +122,8 @@ namespace MWGui
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
|
|
||||||
bool mFullHelp;
|
bool mFullHelp;
|
||||||
|
|
||||||
|
int mShowOwned;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/manualref.hpp"
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/containerstore.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
|
@ -539,6 +539,9 @@ namespace MWGui
|
||||||
, mRepeatStepTime(0.1f)
|
, mRepeatStepTime(0.1f)
|
||||||
, mIsIncreasing(true)
|
, mIsIncreasing(true)
|
||||||
{
|
{
|
||||||
|
#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,2)
|
||||||
|
ScrollBar::setRepeatEnabled(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MWScrollBar::~MWScrollBar()
|
MWScrollBar::~MWScrollBar()
|
||||||
|
|
|
@ -21,16 +21,16 @@ namespace MWGui
|
||||||
// Events
|
// Events
|
||||||
typedef MyGUI::delegates::CMultiDelegate1<WindowBase*> EventHandle_WindowBase;
|
typedef MyGUI::delegates::CMultiDelegate1<WindowBase*> EventHandle_WindowBase;
|
||||||
|
|
||||||
///Unhides the window
|
/// Notify that window has been made visible
|
||||||
virtual void open() {}
|
virtual void open() {}
|
||||||
///Hides the window
|
/// Notify that window has been hidden
|
||||||
virtual void close () {}
|
virtual void close () {}
|
||||||
///Gracefully exits the window
|
/// Gracefully exits the window
|
||||||
virtual void exit() {}
|
virtual void exit() {}
|
||||||
///Sets the visibility of the window
|
/// Sets the visibility of the window
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
///Returns the visibility state of the window
|
/// Returns the visibility state of the window
|
||||||
virtual bool isVisible();
|
bool isVisible();
|
||||||
void center();
|
void center();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
#include <components/sdlutil/sdlcursormanager.hpp>
|
#include <components/sdlutil/sdlcursormanager.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include <components/fontloader/fontloader.hpp>
|
#include <components/fontloader/fontloader.hpp>
|
||||||
|
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
@ -42,6 +45,7 @@
|
||||||
|
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
#include "../mwbase/statemanager.hpp"
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "../mwrender/vismask.hpp"
|
#include "../mwrender/vismask.hpp"
|
||||||
|
|
||||||
|
@ -55,8 +59,6 @@
|
||||||
|
|
||||||
#include "../mwrender/localmap.hpp"
|
#include "../mwrender/localmap.hpp"
|
||||||
|
|
||||||
#include "../mwsound/soundmanagerimp.hpp"
|
|
||||||
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "journalwindow.hpp"
|
#include "journalwindow.hpp"
|
||||||
#include "journalviewmodel.hpp"
|
#include "journalviewmodel.hpp"
|
||||||
|
@ -110,7 +112,7 @@ namespace MWGui
|
||||||
WindowManager::WindowManager(
|
WindowManager::WindowManager(
|
||||||
osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem
|
osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem
|
||||||
, const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts,
|
, const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts,
|
||||||
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map<std::string, std::string>& fallbackMap)
|
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map<std::string, std::string>& fallbackMap, const std::string& versionDescription)
|
||||||
: mResourceSystem(resourceSystem)
|
: mResourceSystem(resourceSystem)
|
||||||
, mViewer(viewer)
|
, mViewer(viewer)
|
||||||
, mConsoleOnlyScripts(consoleOnlyScripts)
|
, mConsoleOnlyScripts(consoleOnlyScripts)
|
||||||
|
@ -184,6 +186,8 @@ namespace MWGui
|
||||||
, mRestAllowed(true)
|
, mRestAllowed(true)
|
||||||
, mFPS(0.0f)
|
, mFPS(0.0f)
|
||||||
, mFallbackMap(fallbackMap)
|
, mFallbackMap(fallbackMap)
|
||||||
|
, mShowOwned(0)
|
||||||
|
, mVersionDescription(versionDescription)
|
||||||
{
|
{
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale);
|
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale);
|
||||||
|
@ -232,8 +236,9 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
|
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
|
||||||
|
|
||||||
|
// Create all cursors in advance
|
||||||
|
createCursors();
|
||||||
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
|
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
|
||||||
|
|
||||||
mCursorManager->setEnabled(true);
|
mCursorManager->setEnabled(true);
|
||||||
|
|
||||||
// hide mygui's pointer
|
// hide mygui's pointer
|
||||||
|
@ -257,6 +262,8 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged);
|
MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged);
|
||||||
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
|
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
|
||||||
|
|
||||||
|
mShowOwned = Settings::Manager::getInt("show owned", "Game");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::initUI()
|
void WindowManager::initUI()
|
||||||
|
@ -268,7 +275,7 @@ namespace MWGui
|
||||||
mDragAndDrop = new DragAndDrop();
|
mDragAndDrop = new DragAndDrop();
|
||||||
|
|
||||||
mRecharge = new Recharge();
|
mRecharge = new Recharge();
|
||||||
mMenu = new MainMenu(w, h, mResourceSystem->getVFS());
|
mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription);
|
||||||
mLocalMapRender = new MWRender::LocalMap(mViewer);
|
mLocalMapRender = new MWRender::LocalMap(mViewer);
|
||||||
mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender);
|
mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender);
|
||||||
trackWindow(mMap, "map");
|
trackWindow(mMap, "map");
|
||||||
|
@ -893,6 +900,9 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::updateMap()
|
void WindowManager::updateMap()
|
||||||
{
|
{
|
||||||
|
if (!mLocalMapRender)
|
||||||
|
return;
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3();
|
osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3();
|
||||||
|
@ -1031,6 +1041,12 @@ namespace MWGui
|
||||||
void WindowManager::setFocusObject(const MWWorld::Ptr& focus)
|
void WindowManager::setFocusObject(const MWWorld::Ptr& focus)
|
||||||
{
|
{
|
||||||
mToolTips->setFocusObject(focus);
|
mToolTips->setFocusObject(focus);
|
||||||
|
|
||||||
|
if(mHud && (mShowOwned == 2 || mShowOwned == 3))
|
||||||
|
{
|
||||||
|
bool owned = mToolTips->checkOwned();
|
||||||
|
mHud->setCrosshairOwned(owned);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y)
|
void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y)
|
||||||
|
@ -1078,11 +1094,22 @@ namespace MWGui
|
||||||
void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result)
|
void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result)
|
||||||
{
|
{
|
||||||
std::string tag(_tag);
|
std::string tag(_tag);
|
||||||
|
|
||||||
|
std::string MyGuiPrefix = "setting=";
|
||||||
|
size_t MyGuiPrefixLength = MyGuiPrefix.length();
|
||||||
|
|
||||||
std::string tokenToFind = "sCell=";
|
std::string tokenToFind = "sCell=";
|
||||||
size_t tokenLength = tokenToFind.length();
|
size_t tokenLength = tokenToFind.length();
|
||||||
|
|
||||||
if (tag.compare(0, tokenLength, tokenToFind) == 0)
|
if(tag.compare(0, MyGuiPrefixLength, MyGuiPrefix) == 0)
|
||||||
|
{
|
||||||
|
tag = tag.substr(MyGuiPrefixLength, tag.length());
|
||||||
|
std::string settingSection = tag.substr(0, tag.find(","));
|
||||||
|
std::string settingTag = tag.substr(tag.find(",")+1, tag.length());
|
||||||
|
|
||||||
|
_result = Settings::Manager::getString(settingTag, settingSection);
|
||||||
|
}
|
||||||
|
else if (tag.compare(0, tokenLength, tokenToFind) == 0)
|
||||||
{
|
{
|
||||||
_result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength));
|
_result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength));
|
||||||
}
|
}
|
||||||
|
@ -1175,31 +1202,7 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::onCursorChange(const std::string &name)
|
void WindowManager::onCursorChange(const std::string &name)
|
||||||
{
|
{
|
||||||
if(!mCursorManager->cursorChanged(name))
|
mCursorManager->cursorChanged(name);
|
||||||
return; //the cursor manager doesn't want any more info about this cursor
|
|
||||||
//See if we can get the information we need out of the cursor resource
|
|
||||||
ResourceImageSetPointerFix* imgSetPtr = dynamic_cast<ResourceImageSetPointerFix*>(MyGUI::PointerManager::getInstance().getByName(name));
|
|
||||||
if(imgSetPtr != NULL)
|
|
||||||
{
|
|
||||||
MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet();
|
|
||||||
|
|
||||||
std::string tex_name = imgSet->getIndexInfo(0,0).texture;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP);
|
|
||||||
tex->setUnRefImageDataAfterApply(false); // FIXME?
|
|
||||||
|
|
||||||
//everything looks good, send it to the cursor manager
|
|
||||||
if(tex.valid())
|
|
||||||
{
|
|
||||||
Uint8 size_x = imgSetPtr->getSize().width;
|
|
||||||
Uint8 size_y = imgSetPtr->getSize().height;
|
|
||||||
Uint8 hotspot_x = imgSetPtr->getHotSpot().left;
|
|
||||||
Uint8 hotspot_y = imgSetPtr->getHotSpot().top;
|
|
||||||
int rotation = imgSetPtr->getRotation();
|
|
||||||
|
|
||||||
mCursorManager->receiveCursorInfo(name, rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::popGuiMode()
|
void WindowManager::popGuiMode()
|
||||||
|
@ -1666,10 +1669,10 @@ namespace MWGui
|
||||||
writer.endRecord(ESM::REC_ASPL);
|
writer.endRecord(ESM::REC_ASPL);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<ESM::CustomMarker>::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it)
|
for (CustomMarkerCollection::ContainerType::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it)
|
||||||
{
|
{
|
||||||
writer.startRecord(ESM::REC_MARK);
|
writer.startRecord(ESM::REC_MARK);
|
||||||
(*it).save(writer);
|
it->second.save(writer);
|
||||||
writer.endRecord(ESM::REC_MARK);
|
writer.endRecord(ESM::REC_MARK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1957,6 +1960,33 @@ namespace MWGui
|
||||||
return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS());
|
return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::createCursors()
|
||||||
|
{
|
||||||
|
MyGUI::ResourceManager::EnumeratorPtr enumerator = MyGUI::ResourceManager::getInstance().getEnumerator();
|
||||||
|
while (enumerator.next())
|
||||||
|
{
|
||||||
|
MyGUI::IResource* resource = enumerator.current().second;
|
||||||
|
ResourceImageSetPointerFix* imgSetPointer = dynamic_cast<ResourceImageSetPointerFix*>(resource);
|
||||||
|
if (!imgSetPointer)
|
||||||
|
continue;
|
||||||
|
std::string tex_name = imgSetPointer->getImageSet()->getIndexInfo(0,0).texture;
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Texture2D> tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP);
|
||||||
|
|
||||||
|
if(tex.valid())
|
||||||
|
{
|
||||||
|
//everything looks good, send it to the cursor manager
|
||||||
|
Uint8 size_x = imgSetPointer->getSize().width;
|
||||||
|
Uint8 size_y = imgSetPointer->getSize().height;
|
||||||
|
Uint8 hotspot_x = imgSetPointer->getHotSpot().left;
|
||||||
|
Uint8 hotspot_y = imgSetPointer->getHotSpot().top;
|
||||||
|
int rotation = imgSetPointer->getRotation();
|
||||||
|
|
||||||
|
mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::createTextures()
|
void WindowManager::createTextures()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
|
@ -116,7 +116,7 @@ namespace MWGui
|
||||||
|
|
||||||
WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem,
|
WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem,
|
||||||
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts,
|
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts,
|
||||||
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map<std::string,std::string>& fallbackMap);
|
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map<std::string,std::string>& fallbackMap, const std::string& versionDescription);
|
||||||
virtual ~WindowManager();
|
virtual ~WindowManager();
|
||||||
|
|
||||||
void initUI();
|
void initUI();
|
||||||
|
@ -486,11 +486,16 @@ namespace MWGui
|
||||||
float mFPS;
|
float mFPS;
|
||||||
|
|
||||||
std::map<std::string, std::string> mFallbackMap;
|
std::map<std::string, std::string> mFallbackMap;
|
||||||
|
|
||||||
|
int mShowOwned;
|
||||||
|
|
||||||
|
std::string mVersionDescription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
||||||
* Supported syntax:
|
* Supported syntax:
|
||||||
* #{GMSTName}: retrieves String value of the GMST called GMSTName
|
* #{GMSTName}: retrieves String value of the GMST called GMSTName
|
||||||
|
* #{setting=CATEGORY_NAME,SETTING_NAME}: retrieves String value of SETTING_NAME under category CATEGORY_NAME from settings.cfg
|
||||||
* #{sCell=CellID}: retrieves translated name of the given CellID (used only by some Morrowind localisations, in others cell ID is == cell name)
|
* #{sCell=CellID}: retrieves translated name of the given CellID (used only by some Morrowind localisations, in others cell ID is == cell name)
|
||||||
* #{fontcolour=FontColourName}: retrieves the value of the fallback setting "FontColor_color_<FontColourName>" from openmw.cfg,
|
* #{fontcolour=FontColourName}: retrieves the value of the fallback setting "FontColor_color_<FontColourName>" from openmw.cfg,
|
||||||
* in the format "r g b a", float values in range 0-1. Useful for "Colour" and "TextColour" properties in skins.
|
* in the format "r g b a", float values in range 0-1. Useful for "Colour" and "TextColour" properties in skins.
|
||||||
|
@ -511,6 +516,7 @@ namespace MWGui
|
||||||
void onClipboardRequested(const std::string& _type, std::string& _data);
|
void onClipboardRequested(const std::string& _type, std::string& _data);
|
||||||
|
|
||||||
void createTextures();
|
void createTextures();
|
||||||
|
void createCursors();
|
||||||
void setMenuTransparency(float value);
|
void setMenuTransparency(float value);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
|
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/manualref.hpp"
|
|
||||||
#include "../mwworld/actionequip.hpp"
|
#include "../mwworld/actionequip.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
|
@ -66,44 +67,6 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
|
||||||
{
|
|
||||||
if (ptr.getClass().hasInventoryStore(ptr))
|
|
||||||
{
|
|
||||||
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
|
||||||
MWWorld::ContainerStoreIterator item =
|
|
||||||
inv.getSlot(slot);
|
|
||||||
if (item != inv.end())
|
|
||||||
{
|
|
||||||
if (!item->getClass().hasItemHealth(*item))
|
|
||||||
return false;
|
|
||||||
int charge = item->getClass().getItemHealth(*item);
|
|
||||||
|
|
||||||
if (charge == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
|
||||||
// This was also a bug in the original engine.
|
|
||||||
charge -=
|
|
||||||
std::min(static_cast<int>(disintegrate),
|
|
||||||
charge);
|
|
||||||
item->getCellRef().setCharge(charge);
|
|
||||||
|
|
||||||
if (charge == 0)
|
|
||||||
{
|
|
||||||
// Will unequip the broken item and try to find a replacement
|
|
||||||
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
|
||||||
inv.autoEquip(ptr);
|
|
||||||
else
|
|
||||||
inv.unequipItem(*item, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CheckActorCommanded : public MWMechanics::EffectSourceVisitor
|
class CheckActorCommanded : public MWMechanics::EffectSourceVisitor
|
||||||
{
|
{
|
||||||
MWWorld::Ptr mActor;
|
MWWorld::Ptr mActor;
|
||||||
|
@ -515,8 +478,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool wasDead = creatureStats.isDead();
|
bool wasDead = creatureStats.isDead();
|
||||||
|
|
||||||
// FIXME: effect ticks should go into separate functions so they can be used with either
|
// tickable effects (i.e. effects having a lasting impact after expiry)
|
||||||
// magnitude (instant effect) or magnitude*duration
|
// these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here
|
||||||
|
for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it)
|
||||||
|
{
|
||||||
|
effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration);
|
||||||
|
}
|
||||||
|
|
||||||
// attributes
|
// attributes
|
||||||
for(int i = 0;i < ESM::Attribute::Length;++i)
|
for(int i = 0;i < ESM::Attribute::Length;++i)
|
||||||
|
@ -526,9 +493,6 @@ namespace MWMechanics
|
||||||
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() -
|
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() -
|
||||||
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()));
|
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()));
|
||||||
|
|
||||||
stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration);
|
|
||||||
stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration);
|
|
||||||
|
|
||||||
creatureStats.setAttribute(i, stat);
|
creatureStats.setAttribute(i, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,12 +522,6 @@ namespace MWMechanics
|
||||||
// Fatigue can be decreased below zero meaning the actor will be knocked out
|
// Fatigue can be decreased below zero meaning the actor will be knocked out
|
||||||
i == 2);
|
i == 2);
|
||||||
|
|
||||||
|
|
||||||
float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude()
|
|
||||||
- creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).getMagnitude()
|
|
||||||
- creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).getMagnitude();
|
|
||||||
stat.setCurrent(stat.getCurrent() + currentDiff * duration, i == 2);
|
|
||||||
|
|
||||||
creatureStats.setDynamic(i, stat);
|
creatureStats.setDynamic(i, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,90 +549,11 @@ namespace MWMechanics
|
||||||
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
|
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply disintegration (reduces item health)
|
|
||||||
float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).getMagnitude();
|
|
||||||
if (disintegrateWeapon > 0)
|
|
||||||
disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration);
|
|
||||||
float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).getMagnitude();
|
|
||||||
if (disintegrateArmor > 0)
|
|
||||||
{
|
|
||||||
// According to UESP
|
|
||||||
int priorities[] = {
|
|
||||||
MWWorld::InventoryStore::Slot_CarriedLeft,
|
|
||||||
MWWorld::InventoryStore::Slot_Cuirass,
|
|
||||||
MWWorld::InventoryStore::Slot_LeftPauldron,
|
|
||||||
MWWorld::InventoryStore::Slot_RightPauldron,
|
|
||||||
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
|
||||||
MWWorld::InventoryStore::Slot_RightGauntlet,
|
|
||||||
MWWorld::InventoryStore::Slot_Helmet,
|
|
||||||
MWWorld::InventoryStore::Slot_Greaves,
|
|
||||||
MWWorld::InventoryStore::Slot_Boots
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
|
|
||||||
{
|
|
||||||
if (disintegrateSlot(ptr, priorities[i], disintegrateArmor*duration))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool receivedMagicDamage = false;
|
|
||||||
|
|
||||||
if (creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth).getMagnitude() > 0.0f
|
|
||||||
|| creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth).getMagnitude() > 0.0f)
|
|
||||||
receivedMagicDamage = true;
|
|
||||||
|
|
||||||
// Apply damage ticks
|
|
||||||
int damageEffects[] = {
|
|
||||||
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
|
|
||||||
ESM::MagicEffect::SunDamage
|
|
||||||
};
|
|
||||||
|
|
||||||
DynamicStat<float> health = creatureStats.getHealth();
|
|
||||||
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
|
|
||||||
{
|
|
||||||
float magnitude = creatureStats.getMagicEffects().get(damageEffects[i]).getMagnitude();
|
|
||||||
|
|
||||||
if (damageEffects[i] == ESM::MagicEffect::SunDamage)
|
|
||||||
{
|
|
||||||
// isInCell shouldn't be needed, but updateActor called during game start
|
|
||||||
if (!ptr.isInCell() || !ptr.getCell()->isExterior())
|
|
||||||
continue;
|
|
||||||
float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour();
|
|
||||||
float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13)));
|
|
||||||
float damageScale = 1.f - timeDiff / 7.f;
|
|
||||||
// When cloudy, the sun damage effect is halved
|
|
||||||
static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
|
||||||
"fMagicSunBlockedMult")->getFloat();
|
|
||||||
|
|
||||||
int weather = MWBase::Environment::get().getWorld()->getCurrentWeather();
|
|
||||||
if (weather > 1)
|
|
||||||
damageScale *= fMagicSunBlockedMult;
|
|
||||||
health.setCurrent(health.getCurrent() - magnitude * duration * damageScale);
|
|
||||||
|
|
||||||
if (magnitude * damageScale > 0.0f)
|
|
||||||
receivedMagicDamage = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
health.setCurrent(health.getCurrent() - magnitude * duration);
|
|
||||||
|
|
||||||
if (magnitude > 0.0f)
|
|
||||||
receivedMagicDamage = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
|
||||||
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
|
||||||
|
|
||||||
creatureStats.setHealth(health);
|
|
||||||
|
|
||||||
if (!wasDead && creatureStats.isDead())
|
if (!wasDead && creatureStats.isDead())
|
||||||
{
|
{
|
||||||
// The actor was killed by a magic effect. Figure out if the player was responsible for it.
|
// The actor was killed by a magic effect. Figure out if the player was responsible for it.
|
||||||
const ActiveSpells& spells = creatureStats.getActiveSpells();
|
const ActiveSpells& spells = creatureStats.getActiveSpells();
|
||||||
bool killedByPlayer = false;
|
bool killedByPlayer = false;
|
||||||
bool murderedByPlayer = false;
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -684,33 +563,29 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
int effectId = effectIt->mEffectId;
|
int effectId = effectIt->mEffectId;
|
||||||
bool isDamageEffect = false;
|
bool isDamageEffect = false;
|
||||||
|
|
||||||
|
int damageEffects[] = {
|
||||||
|
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
|
||||||
|
ESM::MagicEffect::SunDamage, ESM::MagicEffect::DamageHealth, ESM::MagicEffect::AbsorbHealth
|
||||||
|
};
|
||||||
|
|
||||||
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
|
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
|
||||||
{
|
{
|
||||||
if (damageEffects[i] == effectId)
|
if (damageEffects[i] == effectId)
|
||||||
isDamageEffect = true;
|
isDamageEffect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::AbsorbHealth)
|
|
||||||
isDamageEffect = true;
|
|
||||||
|
|
||||||
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(spell.mCasterActorId);
|
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(spell.mCasterActorId);
|
||||||
if (isDamageEffect && caster == player)
|
if (isDamageEffect && caster == player)
|
||||||
{
|
|
||||||
killedByPlayer = true;
|
killedByPlayer = true;
|
||||||
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
|
||||||
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
|
||||||
// for bystanders it is not possible to tell who attacked first, anyway.
|
|
||||||
if (ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1
|
|
||||||
&& ptr != player)
|
|
||||||
murderedByPlayer = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (murderedByPlayer)
|
if (killedByPlayer)
|
||||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder);
|
{
|
||||||
if (killedByPlayer && player.getClass().getNpcStats(player).isWerewolf())
|
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player);
|
||||||
player.getClass().getNpcStats(player).addWerewolfKill();
|
if (player.getClass().getNpcStats(player).isWerewolf())
|
||||||
|
player.getClass().getNpcStats(player).addWerewolfKill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: dirty flag for magic effects to avoid some unnecessary work below?
|
// TODO: dirty flag for magic effects to avoid some unnecessary work below?
|
||||||
|
@ -794,9 +669,6 @@ namespace MWMechanics
|
||||||
skill.setModifier(static_cast<int>(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() -
|
skill.setModifier(static_cast<int>(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() -
|
||||||
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() -
|
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() -
|
||||||
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()));
|
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()));
|
||||||
|
|
||||||
skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration);
|
|
||||||
skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,18 +1069,18 @@ namespace MWMechanics
|
||||||
killDeadActors();
|
killDeadActors();
|
||||||
|
|
||||||
// check if we still have any player enemies to switch music
|
// check if we still have any player enemies to switch music
|
||||||
static bool isBattleMusic = false;
|
static int currentMusic = 0;
|
||||||
|
|
||||||
if (isBattleMusic && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() &&
|
if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() &&
|
||||||
MWBase::Environment::get().getSoundManager()->isMusicPlaying()))
|
MWBase::Environment::get().getSoundManager()->isMusicPlaying()))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||||
isBattleMusic = false;
|
currentMusic = 1;
|
||||||
}
|
}
|
||||||
else if (!isBattleMusic && hostilesCount > 0)
|
else if (currentMusic != 2 && hostilesCount > 0)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
||||||
isBattleMusic = true;
|
currentMusic = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float sneakTimer = 0.f; // times update of sneak icon
|
static float sneakTimer = 0.f; // times update of sneak icon
|
||||||
|
|
|
@ -36,13 +36,13 @@ namespace
|
||||||
|
|
||||||
float getZAngleToDir(const osg::Vec3f& dir)
|
float getZAngleToDir(const osg::Vec3f& dir)
|
||||||
{
|
{
|
||||||
return osg::RadiansToDegrees(std::atan2(dir.x(), dir.y()));
|
return std::atan2(dir.x(), dir.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f)
|
float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f)
|
||||||
{
|
{
|
||||||
float len = (dirLen > 0.0f)? dirLen : dir.length();
|
float len = (dirLen > 0.0f)? dirLen : dir.length();
|
||||||
return osg::RadiansToDegrees(-std::asin(dir.z() / len));
|
return -std::asin(dir.z() / len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -221,12 +221,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
if(movement.mRotation[2] != 0)
|
if(movement.mRotation[2] != 0)
|
||||||
{
|
{
|
||||||
if(zTurn(actor, osg::DegreesToRadians(movement.mRotation[2]))) movement.mRotation[2] = 0;
|
if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(movement.mRotation[0] != 0)
|
if(movement.mRotation[0] != 0)
|
||||||
{
|
{
|
||||||
if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0;
|
if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool& attack = storage.mAttack;
|
bool& attack = storage.mAttack;
|
||||||
|
|
|
@ -104,7 +104,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
// change the angle a bit, too
|
// change the angle a bit, too
|
||||||
zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { //Not stuck, so reset things
|
else { //Not stuck, so reset things
|
||||||
|
@ -117,7 +117,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
|
||||||
}
|
}
|
||||||
|
|
||||||
zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,6 +184,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
const ESM::Position &targetPos = target.getRefData().getPosition();
|
const ESM::Position &targetPos = target.getRefData().getPosition();
|
||||||
|
|
||||||
float distTo = (targetPos.asVec3() - vActorPos).length();
|
float distTo = (targetPos.asVec3() - vActorPos).length();
|
||||||
|
|
||||||
|
// Small threshold for changing target
|
||||||
|
if (it == mPackages.begin())
|
||||||
|
distTo = std::max(0.f, distTo - 50.f);
|
||||||
|
|
||||||
if (distTo < nearestDist)
|
if (distTo < nearestDist)
|
||||||
{
|
{
|
||||||
nearestDist = distTo;
|
nearestDist = distTo;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aiwander.hpp"
|
#include "aiwander.hpp"
|
||||||
|
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
@ -28,6 +30,12 @@ namespace MWMechanics
|
||||||
static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
|
static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
|
||||||
static const int GREETING_SHOULD_END = 10;
|
static const int GREETING_SHOULD_END = 10;
|
||||||
|
|
||||||
|
// to prevent overcrowding
|
||||||
|
static const int DESTINATION_TOLERANCE = 64;
|
||||||
|
|
||||||
|
// distance must be long enough that NPC will need to move to get there.
|
||||||
|
static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2;
|
||||||
|
|
||||||
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
||||||
{
|
{
|
||||||
std::string("idle2"),
|
std::string("idle2"),
|
||||||
|
@ -43,10 +51,10 @@ namespace MWMechanics
|
||||||
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
||||||
struct AiWanderStorage : AiTemporaryBase
|
struct AiWanderStorage : AiTemporaryBase
|
||||||
{
|
{
|
||||||
// the z rotation angle (degrees) we want to reach
|
// the z rotation angle to reach
|
||||||
// used every frame when mRotate is true
|
// when mTurnActorGivingGreetingToFacePlayer is true
|
||||||
float mTargetAngleRadians;
|
float mTargetAngleRadians;
|
||||||
bool mRotate;
|
bool mTurnActorGivingGreetingToFacePlayer;
|
||||||
float mReaction; // update some actions infrequently
|
float mReaction; // update some actions infrequently
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,27 +64,21 @@ namespace MWMechanics
|
||||||
const MWWorld::CellStore* mCell; // for detecting cell change
|
const MWWorld::CellStore* mCell; // for detecting cell change
|
||||||
|
|
||||||
// AiWander states
|
// AiWander states
|
||||||
bool mChooseAction;
|
AiWander::WanderState mState;
|
||||||
bool mIdleNow;
|
|
||||||
bool mMoveNow;
|
|
||||||
bool mWalking;
|
|
||||||
|
|
||||||
unsigned short mPlayedIdle;
|
unsigned short mIdleAnimation;
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
|
|
||||||
AiWanderStorage():
|
AiWanderStorage():
|
||||||
mTargetAngleRadians(0),
|
mTargetAngleRadians(0),
|
||||||
mRotate(false),
|
mTurnActorGivingGreetingToFacePlayer(false),
|
||||||
mReaction(0),
|
mReaction(0),
|
||||||
mSaidGreeting(AiWander::Greet_None),
|
mSaidGreeting(AiWander::Greet_None),
|
||||||
mGreetingTimer(0),
|
mGreetingTimer(0),
|
||||||
mCell(NULL),
|
mCell(NULL),
|
||||||
mChooseAction(true),
|
mState(AiWander::Wander_ChooseAction),
|
||||||
mIdleNow(false),
|
mIdleAnimation(0)
|
||||||
mMoveNow(false),
|
|
||||||
mWalking(false),
|
|
||||||
mPlayedIdle(0)
|
|
||||||
{};
|
{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,7 +111,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
|
|
||||||
mStoredAvailableNodes = false;
|
mPopulateAvailableNodes = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +185,7 @@ namespace MWMechanics
|
||||||
if(!currentCell || cellChange)
|
if(!currentCell || cellChange)
|
||||||
{
|
{
|
||||||
currentCell = actor.getCell();
|
currentCell = actor.getCell();
|
||||||
mStoredAvailableNodes = false; // prob. not needed since mDistance = 0
|
mPopulateAvailableNodes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cStats.setDrawState(DrawState_Nothing);
|
cStats.setDrawState(DrawState_Nothing);
|
||||||
|
@ -192,156 +194,81 @@ namespace MWMechanics
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
|
||||||
|
|
||||||
bool& idleNow = storage.mIdleNow;
|
WanderState& wanderState = storage.mState;
|
||||||
bool& moveNow = storage.mMoveNow;
|
|
||||||
bool& walking = storage.mWalking;
|
|
||||||
// Check if an idle actor is too close to a door - if so start walking
|
// Check if an idle actor is too close to a door - if so start walking
|
||||||
mDoorCheckDuration += duration;
|
mDoorCheckDuration += duration;
|
||||||
if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL)
|
if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL)
|
||||||
{
|
{
|
||||||
mDoorCheckDuration = 0; // restart timer
|
mDoorCheckDuration = 0; // restart timer
|
||||||
if(mDistance && // actor is not intended to be stationary
|
if(mDistance && // actor is not intended to be stationary
|
||||||
idleNow && // but is in idle
|
(wanderState == Wander_IdleNow) && // but is in idle
|
||||||
!walking && // FIXME: some actors are idle while walking
|
|
||||||
proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only
|
proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only
|
||||||
{
|
{
|
||||||
idleNow = false;
|
wanderState = Wander_MoveNow;
|
||||||
moveNow = true;
|
|
||||||
mTrimCurrentNode = false; // just in case
|
mTrimCurrentNode = false; // just in case
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we there yet?
|
// Are we there yet?
|
||||||
bool& chooseAction = storage.mChooseAction;
|
if ((wanderState == Wander_Walking) &&
|
||||||
if(walking &&
|
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE))
|
||||||
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f))
|
|
||||||
{
|
{
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
moveNow = false;
|
wanderState = Wander_ChooseAction;
|
||||||
walking = false;
|
|
||||||
chooseAction = true;
|
|
||||||
mHasReturnPosition = false;
|
mHasReturnPosition = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(walking) // have not yet reached the destination
|
if (wanderState == Wander_Walking) // have not yet reached the destination
|
||||||
{
|
{
|
||||||
// turn towards the next point in mPath
|
// turn towards the next point in mPath
|
||||||
zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
|
||||||
// Returns true if evasive action needs to be taken
|
evadeObstacles(actor, storage, duration);
|
||||||
if(mObstacleCheck.check(actor, duration))
|
|
||||||
{
|
|
||||||
// first check if we're walking into a door
|
|
||||||
if(proximityToDoor(actor)) // NOTE: checks interior cells only
|
|
||||||
{
|
|
||||||
// remove allowed points then select another random destination
|
|
||||||
mTrimCurrentNode = true;
|
|
||||||
trimAllowedNodes(mAllowedNodes, storage.mPathFinder);
|
|
||||||
mObstacleCheck.clear();
|
|
||||||
storage.mPathFinder.clearPath();
|
|
||||||
walking = false;
|
|
||||||
moveNow = true;
|
|
||||||
}
|
|
||||||
else // probably walking into another NPC
|
|
||||||
{
|
|
||||||
// TODO: diagonal should have same animation as walk forward
|
|
||||||
// but doesn't seem to do that?
|
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f;
|
|
||||||
// change the angle a bit, too
|
|
||||||
zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
|
||||||
}
|
|
||||||
mStuckCount++; // TODO: maybe no longer needed
|
|
||||||
}
|
|
||||||
//#if 0
|
|
||||||
// TODO: maybe no longer needed
|
|
||||||
if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
|
||||||
{
|
|
||||||
//std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl;
|
|
||||||
mObstacleCheck.clear();
|
|
||||||
|
|
||||||
stopWalking(actor, storage);
|
|
||||||
moveNow = false;
|
|
||||||
walking = false;
|
|
||||||
chooseAction = true;
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer;
|
||||||
float& targetAngleRadians = storage.mTargetAngleRadians;
|
|
||||||
bool& rotate = storage.mRotate;
|
|
||||||
if (rotate)
|
if (rotate)
|
||||||
{
|
{
|
||||||
// Reduce the turning animation glitch by using a *HUGE* value of
|
// Reduce the turning animation glitch by using a *HUGE* value of
|
||||||
// epsilon... TODO: a proper fix might be in either the physics or the
|
// epsilon... TODO: a proper fix might be in either the physics or the
|
||||||
// animation subsystem
|
// animation subsystem
|
||||||
if (zTurn(actor, targetAngleRadians, osg::DegreesToRadians(5.f)))
|
if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f)))
|
||||||
rotate = false;
|
rotate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if idle animation finished
|
// Check if idle animation finished
|
||||||
short unsigned& playedIdle = storage.mPlayedIdle;
|
short unsigned& idleAnimation = storage.mIdleAnimation;
|
||||||
GreetingState& greetingState = storage.mSaidGreeting;
|
GreetingState& greetingState = storage.mSaidGreeting;
|
||||||
if(idleNow && !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None))
|
if ((wanderState == Wander_IdleNow) &&
|
||||||
|
!checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None))
|
||||||
{
|
{
|
||||||
playedIdle = 0;
|
wanderState = Wander_ChooseAction;
|
||||||
idleNow = false;
|
|
||||||
chooseAction = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
if(chooseAction)
|
if (wanderState == Wander_ChooseAction)
|
||||||
{
|
{
|
||||||
playedIdle = 0;
|
idleAnimation = getRandomIdle();
|
||||||
getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection
|
|
||||||
|
|
||||||
if(!playedIdle && mDistance)
|
if(!idleAnimation && mDistance)
|
||||||
{
|
{
|
||||||
chooseAction = false;
|
wanderState = Wander_MoveNow;
|
||||||
moveNow = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
||||||
MWWorld::TimeStamp currentTime = world->getTimeStamp();
|
MWWorld::TimeStamp currentTime = world->getTimeStamp();
|
||||||
mStartTime = currentTime;
|
mStartTime = currentTime;
|
||||||
playIdle(actor, playedIdle);
|
playIdle(actor, idleAnimation);
|
||||||
chooseAction = false;
|
wanderState = Wander_IdleNow;
|
||||||
idleNow = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play idle voiced dialogue entries randomly
|
playIdleDialogueRandomly(actor);
|
||||||
int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified();
|
|
||||||
if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor)
|
|
||||||
&& MWBase::Environment::get().getSoundManager()->sayDone(actor))
|
|
||||||
{
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
|
||||||
|
|
||||||
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
|
|
||||||
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
|
||||||
|
|
||||||
float roll = Misc::Rng::rollProbability() * 10000.0f;
|
|
||||||
|
|
||||||
// In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds
|
|
||||||
// due to the roll being an integer.
|
|
||||||
// Our implementation does not have these issues, so needs to be recalibrated. We chose to
|
|
||||||
// use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration.
|
|
||||||
float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f);
|
|
||||||
|
|
||||||
// Only say Idle voices when player is in LOS
|
|
||||||
// A bit counterintuitive, likely vanilla did this to reduce the appearance of
|
|
||||||
// voices going through walls?
|
|
||||||
if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2()
|
|
||||||
< 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
|
|
||||||
&& MWBase::Environment::get().getWorld()->getLOS(player, actor))
|
|
||||||
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
|
||||||
}
|
|
||||||
|
|
||||||
float& lastReaction = storage.mReaction;
|
float& lastReaction = storage.mReaction;
|
||||||
lastReaction += duration;
|
lastReaction += duration;
|
||||||
|
@ -358,17 +285,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// End package if duration is complete or mid-night hits:
|
// End package if duration is complete or mid-night hits:
|
||||||
MWWorld::TimeStamp currentTime = world->getTimeStamp();
|
MWWorld::TimeStamp currentTime = world->getTimeStamp();
|
||||||
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
|
if((currentTime.getHour() >= mStartTime.getHour() + mDuration) ||
|
||||||
{
|
(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()))
|
||||||
if(!mRepeat)
|
|
||||||
{
|
|
||||||
stopWalking(actor, storage);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mStartTime = currentTime;
|
|
||||||
}
|
|
||||||
else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())
|
|
||||||
{
|
{
|
||||||
if(!mRepeat)
|
if(!mRepeat)
|
||||||
{
|
{
|
||||||
|
@ -381,7 +299,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialization to discover & store allowed node points for this actor.
|
// Initialization to discover & store allowed node points for this actor.
|
||||||
if(!mStoredAvailableNodes)
|
if (mPopulateAvailableNodes)
|
||||||
{
|
{
|
||||||
getAllowedNodes(actor, currentCell->getCell());
|
getAllowedNodes(actor, currentCell->getCell());
|
||||||
}
|
}
|
||||||
|
@ -399,9 +317,6 @@ namespace MWMechanics
|
||||||
mHasReturnPosition = false;
|
mHasReturnPosition = false;
|
||||||
if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20)
|
if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20)
|
||||||
{
|
{
|
||||||
chooseAction = false;
|
|
||||||
idleNow = false;
|
|
||||||
|
|
||||||
if (!storage.mPathFinder.isPathConstructed())
|
if (!storage.mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition));
|
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition));
|
||||||
|
@ -410,139 +325,215 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
storage.mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false);
|
||||||
|
|
||||||
if(storage.mPathFinder.isPathConstructed())
|
if(storage.mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
moveNow = false;
|
wanderState = Wander_Walking;
|
||||||
walking = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow interrupting a walking actor to trigger a greeting
|
// Allow interrupting a walking actor to trigger a greeting
|
||||||
if(idleNow || walking)
|
if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking))
|
||||||
{
|
{
|
||||||
// Play a random voice greeting if the player gets too close
|
playGreetingIfPlayerGetsTooClose(actor, storage);
|
||||||
int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified();
|
|
||||||
float helloDistance = static_cast<float>(hello);
|
|
||||||
static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore()
|
|
||||||
.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->getInt();
|
|
||||||
|
|
||||||
helloDistance *= iGreetDistanceMultiplier;
|
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
|
||||||
osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
|
|
||||||
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
|
||||||
float playerDistSqr = (playerPos - actorPos).length2();
|
|
||||||
|
|
||||||
int& greetingTimer = storage.mGreetingTimer;
|
|
||||||
if (greetingState == Greet_None)
|
|
||||||
{
|
|
||||||
if ((playerDistSqr <= helloDistance*helloDistance) &&
|
|
||||||
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
|
|
||||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
|
|
||||||
greetingTimer++;
|
|
||||||
|
|
||||||
if (greetingTimer >= GREETING_SHOULD_START)
|
|
||||||
{
|
|
||||||
greetingState = Greet_InProgress;
|
|
||||||
MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
|
|
||||||
greetingTimer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(greetingState == Greet_InProgress)
|
|
||||||
{
|
|
||||||
greetingTimer++;
|
|
||||||
|
|
||||||
if(walking)
|
|
||||||
{
|
|
||||||
stopWalking(actor, storage);
|
|
||||||
moveNow = false;
|
|
||||||
walking = false;
|
|
||||||
mObstacleCheck.clear();
|
|
||||||
idleNow = true;
|
|
||||||
getRandomIdle(playedIdle);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!rotate)
|
|
||||||
{
|
|
||||||
osg::Vec3f dir = playerPos - actorPos;
|
|
||||||
|
|
||||||
float faceAngleRadians = std::atan2(dir.x(), dir.y());
|
|
||||||
targetAngleRadians = faceAngleRadians;
|
|
||||||
rotate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (greetingTimer >= GREETING_SHOULD_END)
|
|
||||||
{
|
|
||||||
greetingState = Greet_Done;
|
|
||||||
greetingTimer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (greetingState == MWMechanics::AiWander::Greet_Done)
|
|
||||||
{
|
|
||||||
float resetDist = 2*helloDistance;
|
|
||||||
if (playerDistSqr >= resetDist*resetDist)
|
|
||||||
greetingState = Greet_None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(moveNow && mDistance)
|
if ((wanderState == Wander_MoveNow) && mDistance)
|
||||||
{
|
{
|
||||||
// Construct a new path if there isn't one
|
// Construct a new path if there isn't one
|
||||||
if(!storage.mPathFinder.isPathConstructed())
|
if(!storage.mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
assert(mAllowedNodes.size());
|
if (mAllowedNodes.size())
|
||||||
unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size());
|
|
||||||
// NOTE: initially constructed with local (i.e. cell) co-ordinates
|
|
||||||
// convert dest to use world co-ordinates
|
|
||||||
ESM::Pathgrid::Point dest(mAllowedNodes[randNode]);
|
|
||||||
if (currentCell->getCell()->isExterior())
|
|
||||||
{
|
{
|
||||||
dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE;
|
setPathToAnAllowedNode(actor, storage, pos);
|
||||||
dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// actor position is already in world co-ordinates
|
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
|
||||||
storage.mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
|
||||||
|
|
||||||
if(storage.mPathFinder.isPathConstructed())
|
|
||||||
{
|
|
||||||
// buildPath inserts dest in case it is not a pathgraph point
|
|
||||||
// index which is a duplicate for AiWander. However below code
|
|
||||||
// does not work since getPath() returns a copy of path not a
|
|
||||||
// reference
|
|
||||||
//if(storage.mPathFinder.getPathSize() > 1)
|
|
||||||
//storage.mPathFinder.getPath().pop_back();
|
|
||||||
|
|
||||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
|
||||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
|
||||||
// check if mCurrentNode was taken out of mAllowedNodes
|
|
||||||
if(mTrimCurrentNode && mAllowedNodes.size() > 1)
|
|
||||||
mTrimCurrentNode = false;
|
|
||||||
else
|
|
||||||
mAllowedNodes.push_back(mCurrentNode);
|
|
||||||
mCurrentNode = temp;
|
|
||||||
|
|
||||||
moveNow = false;
|
|
||||||
walking = true;
|
|
||||||
}
|
|
||||||
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
|
||||||
else
|
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // AiWander package not yet completed
|
return false; // AiWander package not yet completed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration)
|
||||||
|
{
|
||||||
|
if (mObstacleCheck.check(actor, duration))
|
||||||
|
{
|
||||||
|
// first check if we're walking into a door
|
||||||
|
if (proximityToDoor(actor)) // NOTE: checks interior cells only
|
||||||
|
{
|
||||||
|
// remove allowed points then select another random destination
|
||||||
|
mTrimCurrentNode = true;
|
||||||
|
trimAllowedNodes(mAllowedNodes, storage.mPathFinder);
|
||||||
|
mObstacleCheck.clear();
|
||||||
|
storage.mPathFinder.clearPath();
|
||||||
|
storage.mState = Wander_MoveNow;
|
||||||
|
}
|
||||||
|
else // probably walking into another NPC
|
||||||
|
{
|
||||||
|
// TODO: diagonal should have same animation as walk forward
|
||||||
|
// but doesn't seem to do that?
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f;
|
||||||
|
// change the angle a bit, too
|
||||||
|
const ESM::Position& pos = actor.getRefData().getPosition();
|
||||||
|
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]));
|
||||||
|
}
|
||||||
|
mStuckCount++; // TODO: maybe no longer needed
|
||||||
|
}
|
||||||
|
//#if 0
|
||||||
|
// TODO: maybe no longer needed
|
||||||
|
if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||||
|
{
|
||||||
|
//std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl;
|
||||||
|
mObstacleCheck.clear();
|
||||||
|
|
||||||
|
stopWalking(actor, storage);
|
||||||
|
storage.mState = Wander_ChooseAction;
|
||||||
|
mStuckCount = 0;
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||||
|
if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor)
|
||||||
|
&& MWBase::Environment::get().getSoundManager()->sayDone(actor))
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
|
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
||||||
|
|
||||||
|
float roll = Misc::Rng::rollProbability() * 10000.0f;
|
||||||
|
|
||||||
|
// In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds
|
||||||
|
// due to the roll being an integer.
|
||||||
|
// Our implementation does not have these issues, so needs to be recalibrated. We chose to
|
||||||
|
// use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration.
|
||||||
|
float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f);
|
||||||
|
|
||||||
|
// Only say Idle voices when player is in LOS
|
||||||
|
// A bit counterintuitive, likely vanilla did this to reduce the appearance of
|
||||||
|
// voices going through walls?
|
||||||
|
const ESM::Position& pos = actor.getRefData().getPosition();
|
||||||
|
if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2()
|
||||||
|
< 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
|
||||||
|
&& MWBase::Environment::get().getWorld()->getLOS(player, actor))
|
||||||
|
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||||
|
{
|
||||||
|
// Play a random voice greeting if the player gets too close
|
||||||
|
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||||
|
float helloDistance = static_cast<float>(hello);
|
||||||
|
static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->getInt();
|
||||||
|
|
||||||
|
helloDistance *= iGreetDistanceMultiplier;
|
||||||
|
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
|
||||||
|
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||||
|
float playerDistSqr = (playerPos - actorPos).length2();
|
||||||
|
|
||||||
|
int& greetingTimer = storage.mGreetingTimer;
|
||||||
|
GreetingState& greetingState = storage.mSaidGreeting;
|
||||||
|
if (greetingState == Greet_None)
|
||||||
|
{
|
||||||
|
if ((playerDistSqr <= helloDistance*helloDistance) &&
|
||||||
|
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
|
||||||
|
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
|
||||||
|
greetingTimer++;
|
||||||
|
|
||||||
|
if (greetingTimer >= GREETING_SHOULD_START)
|
||||||
|
{
|
||||||
|
greetingState = Greet_InProgress;
|
||||||
|
MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
|
||||||
|
greetingTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (greetingState == Greet_InProgress)
|
||||||
|
{
|
||||||
|
greetingTimer++;
|
||||||
|
|
||||||
|
if (storage.mState == Wander_Walking)
|
||||||
|
{
|
||||||
|
stopWalking(actor, storage);
|
||||||
|
mObstacleCheck.clear();
|
||||||
|
storage.mState = Wander_IdleNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
turnActorToFacePlayer(actorPos, playerPos, storage);
|
||||||
|
|
||||||
|
if (greetingTimer >= GREETING_SHOULD_END)
|
||||||
|
{
|
||||||
|
greetingState = Greet_Done;
|
||||||
|
greetingTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (greetingState == MWMechanics::AiWander::Greet_Done)
|
||||||
|
{
|
||||||
|
float resetDist = 2 * helloDistance;
|
||||||
|
if (playerDistSqr >= resetDist*resetDist)
|
||||||
|
greetingState = Greet_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage)
|
||||||
|
{
|
||||||
|
osg::Vec3f dir = playerPosition - actorPosition;
|
||||||
|
|
||||||
|
float faceAngleRadians = std::atan2(dir.x(), dir.y());
|
||||||
|
storage.mTargetAngleRadians = faceAngleRadians;
|
||||||
|
storage.mTurnActorGivingGreetingToFacePlayer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos)
|
||||||
|
{
|
||||||
|
unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size());
|
||||||
|
ESM::Pathgrid::Point dest(mAllowedNodes[randNode]);
|
||||||
|
ToWorldCoordinates(dest, storage.mCell->getCell());
|
||||||
|
|
||||||
|
// actor position is already in world co-ordinates
|
||||||
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
||||||
|
|
||||||
|
// don't take shortcuts for wandering
|
||||||
|
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false);
|
||||||
|
|
||||||
|
if (storage.mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||||
|
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||||
|
// check if mCurrentNode was taken out of mAllowedNodes
|
||||||
|
if (mTrimCurrentNode && mAllowedNodes.size() > 1)
|
||||||
|
mTrimCurrentNode = false;
|
||||||
|
else
|
||||||
|
mAllowedNodes.push_back(mCurrentNode);
|
||||||
|
mCurrentNode = temp;
|
||||||
|
|
||||||
|
storage.mState = Wander_Walking;
|
||||||
|
}
|
||||||
|
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||||
|
else
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
|
||||||
|
{
|
||||||
|
if (cell->isExterior())
|
||||||
|
{
|
||||||
|
point.mX += cell->mData.mX * ESM::Land::REAL_SIZE;
|
||||||
|
point.mY += cell->mData.mY * ESM::Land::REAL_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
|
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
|
||||||
const PathFinder& pathfinder)
|
const PathFinder& pathfinder)
|
||||||
{
|
{
|
||||||
|
@ -611,9 +602,10 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::getRandomIdle(short unsigned& playedIdle)
|
short unsigned AiWander::getRandomIdle()
|
||||||
{
|
{
|
||||||
unsigned short idleRoll = 0;
|
unsigned short idleRoll = 0;
|
||||||
|
short unsigned selectedAnimation = 0;
|
||||||
|
|
||||||
for(unsigned int counter = 0; counter < mIdle.size(); counter++)
|
for(unsigned int counter = 0; counter < mIdle.size(); counter++)
|
||||||
{
|
{
|
||||||
|
@ -624,10 +616,11 @@ namespace MWMechanics
|
||||||
unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier));
|
unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier));
|
||||||
if(randSelect < idleChance && randSelect > idleRoll)
|
if(randSelect < idleChance && randSelect > idleRoll)
|
||||||
{
|
{
|
||||||
playedIdle = counter+2;
|
selectedAnimation = counter + GroupIndex_MinIdle;
|
||||||
idleRoll = randSelect;
|
idleRoll = randSelect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return selectedAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state)
|
void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state)
|
||||||
|
@ -635,7 +628,7 @@ namespace MWMechanics
|
||||||
if (mDistance == 0)
|
if (mDistance == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mStoredAvailableNodes)
|
if (mPopulateAvailableNodes)
|
||||||
getAllowedNodes(actor, actor.getCell()->getCell());
|
getAllowedNodes(actor, actor.getCell()->getCell());
|
||||||
|
|
||||||
if (mAllowedNodes.empty())
|
if (mAllowedNodes.empty())
|
||||||
|
@ -646,22 +639,21 @@ namespace MWMechanics
|
||||||
int index = Misc::Rng::rollDice(mAllowedNodes.size());
|
int index = Misc::Rng::rollDice(mAllowedNodes.size());
|
||||||
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
||||||
|
|
||||||
// apply a slight offset to prevent overcrowding
|
dest.mX += OffsetToPreventOvercrowding();
|
||||||
dest.mX += static_cast<int>(Misc::Rng::rollProbability() * 128 - 64);
|
dest.mY += OffsetToPreventOvercrowding();
|
||||||
dest.mY += static_cast<int>(Misc::Rng::rollProbability() * 128 - 64);
|
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
||||||
|
|
||||||
if (actor.getCell()->isExterior())
|
|
||||||
{
|
|
||||||
dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE;
|
|
||||||
dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
|
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
|
||||||
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
|
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
|
||||||
actor.getClass().adjustPosition(actor, false);
|
actor.getClass().adjustPosition(actor, false);
|
||||||
|
|
||||||
// may have changed cell
|
// may have changed cell
|
||||||
mStoredAvailableNodes = false;
|
mPopulateAvailableNodes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AiWander::OffsetToPreventOvercrowding()
|
||||||
|
{
|
||||||
|
return static_cast<int>(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell)
|
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell)
|
||||||
|
@ -690,70 +682,86 @@ namespace MWMechanics
|
||||||
// ... pathgrids don't usually include water, so swimmers ignore them
|
// ... pathgrids don't usually include water, so swimmers ignore them
|
||||||
if (mDistance && !actor.getClass().isPureWaterCreature(actor))
|
if (mDistance && !actor.getClass().isPureWaterCreature(actor))
|
||||||
{
|
{
|
||||||
float cellXOffset = 0;
|
// get NPC's position in local (i.e. cell) co-ordinates
|
||||||
float cellYOffset = 0;
|
osg::Vec3f npcPos(mInitialActorPosition);
|
||||||
if(cell->isExterior())
|
if(cell->isExterior())
|
||||||
{
|
{
|
||||||
cellXOffset = static_cast<float>(cell->mData.mX * ESM::Land::REAL_SIZE);
|
npcPos[0] = npcPos[0] - static_cast<float>(cell->mData.mX * ESM::Land::REAL_SIZE);
|
||||||
cellYOffset = static_cast<float>(cell->mData.mY * ESM::Land::REAL_SIZE);
|
npcPos[1] = npcPos[1] - static_cast<float>(cell->mData.mY * ESM::Land::REAL_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert npcPos to local (i.e. cell) co-ordinates
|
|
||||||
osg::Vec3f npcPos(mInitialActorPosition);
|
|
||||||
npcPos[0] = npcPos[0] - cellXOffset;
|
|
||||||
npcPos[1] = npcPos[1] - cellYOffset;
|
|
||||||
|
|
||||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||||
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
||||||
|
int pointIndex = 0;
|
||||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||||
{
|
{
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
||||||
if((npcPos - nodePos).length2() <= mDistance * mDistance)
|
if((npcPos - nodePos).length2() <= mDistance * mDistance)
|
||||||
|
{
|
||||||
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||||
|
pointIndex = counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mAllowedNodes.size() == 1)
|
||||||
|
{
|
||||||
|
AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex);
|
||||||
}
|
}
|
||||||
if(!mAllowedNodes.empty())
|
if(!mAllowedNodes.empty())
|
||||||
{
|
{
|
||||||
osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0]));
|
SetCurrentNodeToClosestAllowedNode(npcPos);
|
||||||
float closestNode = (npcPos - firstNodePos).length2();
|
|
||||||
unsigned int index = 0;
|
|
||||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
|
||||||
{
|
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree]));
|
|
||||||
float tempDist = (npcPos - nodePos).length2();
|
|
||||||
if(tempDist < closestNode)
|
|
||||||
index = counterThree;
|
|
||||||
}
|
|
||||||
mCurrentNode = mAllowedNodes[index];
|
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// In vanilla Morrowind, sometimes distance is too small to include at least two points,
|
|
||||||
// in which case, we will take the two closest points regardless of the wander distance
|
mPopulateAvailableNodes = false;
|
||||||
// This is a backup option, as std::sort is potentially O(n^2) in time.
|
}
|
||||||
if (mAllowedNodes.empty())
|
|
||||||
|
// When only one path grid point in wander distance,
|
||||||
|
// additional points for NPC to wander to are:
|
||||||
|
// 1. NPC's initial location
|
||||||
|
// 2. Partway along the path between the point and its connected points.
|
||||||
|
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex)
|
||||||
|
{
|
||||||
|
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos));
|
||||||
|
for (std::vector<ESM::Pathgrid::Edge>::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->mV0 == pointIndex)
|
||||||
{
|
{
|
||||||
// Start with list of PathGrid nodes, sorted by distance from actor
|
AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]);
|
||||||
std::vector<PathDistance> nodeDistances;
|
|
||||||
for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
|
||||||
{
|
|
||||||
float distance = (npcPos - PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])).length2();
|
|
||||||
nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter)));
|
|
||||||
}
|
|
||||||
std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance);
|
|
||||||
|
|
||||||
// make closest node the current node
|
|
||||||
mCurrentNode = *nodeDistances[0].second;
|
|
||||||
|
|
||||||
// give Actor a 2nd node to walk to
|
|
||||||
mAllowedNodes.push_back(*nodeDistances[1].second);
|
|
||||||
}
|
}
|
||||||
mStoredAvailableNodes = true; // set only if successful in finding allowed nodes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right)
|
void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end)
|
||||||
{
|
{
|
||||||
return left.first < right.first;
|
osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start);
|
||||||
|
osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart;
|
||||||
|
float length = delta.length();
|
||||||
|
delta.normalize();
|
||||||
|
|
||||||
|
int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE);
|
||||||
|
|
||||||
|
// must not travel longer than distance between waypoints or NPC goes past waypoint
|
||||||
|
distance = std::min(distance, static_cast<int>(length));
|
||||||
|
delta *= distance;
|
||||||
|
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos)
|
||||||
|
{
|
||||||
|
float distanceToClosestNode = FLT_MAX;
|
||||||
|
unsigned int index = 0;
|
||||||
|
for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++)
|
||||||
|
{
|
||||||
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree]));
|
||||||
|
float tempDist = (npcPos - nodePos).length2();
|
||||||
|
if (tempDist < distanceToClosestNode)
|
||||||
|
{
|
||||||
|
index = counterThree;
|
||||||
|
distanceToClosestNode = tempDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCurrentNode = mAllowedNodes[index];
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
|
|
@ -63,6 +63,13 @@ namespace MWMechanics
|
||||||
Greet_InProgress,
|
Greet_InProgress,
|
||||||
Greet_Done
|
Greet_Done
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum WanderState {
|
||||||
|
Wander_ChooseAction,
|
||||||
|
Wander_IdleNow,
|
||||||
|
Wander_MoveNow,
|
||||||
|
Wander_Walking
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
// NOTE: mDistance and mDuration must be set already
|
// NOTE: mDistance and mDuration must be set already
|
||||||
void init();
|
void init();
|
||||||
|
@ -70,7 +77,12 @@ namespace MWMechanics
|
||||||
void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||||
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||||
void getRandomIdle(unsigned short& playedIdle);
|
short unsigned getRandomIdle();
|
||||||
|
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
|
||||||
|
void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
|
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration);
|
||||||
|
void playIdleDialogueRandomly(const MWWorld::Ptr& actor);
|
||||||
|
void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage);
|
||||||
|
|
||||||
int mDistance; // how far the actor can wander from the spawn point
|
int mDistance; // how far the actor can wander from the spawn point
|
||||||
int mDuration;
|
int mDuration;
|
||||||
|
@ -88,8 +100,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if false triggers calculating allowed nodes based on mDistance
|
// do we need to calculate allowed nodes based on mDistance
|
||||||
bool mStoredAvailableNodes;
|
bool mPopulateAvailableNodes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,15 +130,19 @@ namespace MWMechanics
|
||||||
GroupIndex_MaxIdle = 9
|
GroupIndex_MaxIdle = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// convert point from local (i.e. cell) to world co-ordinates
|
||||||
|
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell);
|
||||||
|
|
||||||
|
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos);
|
||||||
|
|
||||||
|
void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex);
|
||||||
|
|
||||||
|
void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end);
|
||||||
|
|
||||||
/// lookup table for converting idleSelect value to groupName
|
/// lookup table for converting idleSelect value to groupName
|
||||||
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
|
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
|
||||||
|
|
||||||
/// record distances of pathgrid point nodes to actor
|
static int OffsetToPreventOvercrowding();
|
||||||
/// first value is distance between actor and node, second value is PathGrid node
|
|
||||||
typedef std::pair<float, const ESM::Pathgrid::Point*> PathDistance;
|
|
||||||
|
|
||||||
/// used to sort array of PathDistance objects into ascending order
|
|
||||||
static bool sortByDistance(const PathDistance& left, const PathDistance& right);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -236,7 +237,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i
|
||||||
return prefix + toString(roll);
|
return prefix + toString(roll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
|
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force)
|
||||||
{
|
{
|
||||||
// hit recoils/knockdown animations handling
|
// hit recoils/knockdown animations handling
|
||||||
if(mPtr.getClass().isActor())
|
if(mPtr.getClass().isActor())
|
||||||
|
@ -251,26 +252,28 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
{
|
{
|
||||||
mHitState = CharState_KnockOut;
|
mHitState = CharState_KnockOut;
|
||||||
mCurrentHit = "knockout";
|
mCurrentHit = "knockout";
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
||||||
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true);
|
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true);
|
||||||
}
|
}
|
||||||
else if(knockdown)
|
else if(knockdown)
|
||||||
{
|
{
|
||||||
mHitState = CharState_KnockDown;
|
mHitState = CharState_KnockDown;
|
||||||
mCurrentHit = "knockdown";
|
mCurrentHit = "knockdown";
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
else if (recovery)
|
else if (recovery)
|
||||||
{
|
{
|
||||||
mHitState = CharState_Hit;
|
mHitState = CharState_Hit;
|
||||||
mCurrentHit = chooseRandomGroup("hit");
|
mCurrentHit = chooseRandomGroup("hit");
|
||||||
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
else if (block)
|
else if (block)
|
||||||
{
|
{
|
||||||
mHitState = CharState_Block;
|
mHitState = CharState_Block;
|
||||||
mCurrentHit = "shield";
|
mCurrentHit = "shield";
|
||||||
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "block start", "block stop", 0.0f, 0);
|
MWRender::Animation::AnimPriority priorityBlock (Priority_Hit);
|
||||||
|
priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block;
|
||||||
|
mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel upper body animations
|
// Cancel upper body animations
|
||||||
|
@ -303,7 +306,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
{
|
{
|
||||||
mHitState = CharState_KnockDown;
|
mHitState = CharState_KnockDown;
|
||||||
mAnimation->disable(mCurrentHit);
|
mAnimation->disable(mCurrentHit);
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "loop stop", "stop", 0.0f, 0);
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,40 +314,41 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
if (!mPtr.getClass().isBipedal(mPtr))
|
if (!mPtr.getClass().isBipedal(mPtr))
|
||||||
weap = sWeaponTypeListEnd;
|
weap = sWeaponTypeListEnd;
|
||||||
|
|
||||||
if(force && mJumpState != JumpState_None)
|
if(force || jump != mJumpState)
|
||||||
{
|
{
|
||||||
std::string jump;
|
bool startAtLoop = (jump == mJumpState);
|
||||||
MWRender::Animation::Group jumpgroup = MWRender::Animation::Group_All;
|
mJumpState = jump;
|
||||||
|
|
||||||
|
std::string jumpAnimName;
|
||||||
|
MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All;
|
||||||
if(mJumpState != JumpState_None)
|
if(mJumpState != JumpState_None)
|
||||||
{
|
{
|
||||||
jump = "jump";
|
jumpAnimName = "jump";
|
||||||
if(weap != sWeaponTypeListEnd)
|
if(weap != sWeaponTypeListEnd)
|
||||||
{
|
{
|
||||||
jump += weap->shortgroup;
|
jumpAnimName += weap->shortgroup;
|
||||||
if(!mAnimation->hasAnimation(jump))
|
if(!mAnimation->hasAnimation(jumpAnimName))
|
||||||
{
|
{
|
||||||
jumpgroup = MWRender::Animation::Group_LowerBody;
|
jumpmask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
jump = "jump";
|
jumpAnimName = "jump";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mJumpState == JumpState_InAir)
|
if(mJumpState == JumpState_InAir)
|
||||||
{
|
{
|
||||||
int mode = ((jump == mCurrentJump) ? 2 : 1);
|
|
||||||
|
|
||||||
mAnimation->disable(mCurrentJump);
|
mAnimation->disable(mCurrentJump);
|
||||||
mCurrentJump = jump;
|
mCurrentJump = jumpAnimName;
|
||||||
if (mAnimation->hasAnimation("jump"))
|
if (mAnimation->hasAnimation("jump"))
|
||||||
mAnimation->play(mCurrentJump, Priority_Jump, jumpgroup, false,
|
mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false,
|
||||||
1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mAnimation->disable(mCurrentJump);
|
mAnimation->disable(mCurrentJump);
|
||||||
mCurrentJump.clear();
|
mCurrentJump.clear();
|
||||||
if (mAnimation->hasAnimation("jump"))
|
if (mAnimation->hasAnimation("jump"))
|
||||||
mAnimation->play(jump, Priority_Jump, jumpgroup, true,
|
mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true,
|
||||||
1.0f, "loop stop", "stop", 0.0f, 0);
|
1.0f, "loop stop", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,55 +357,55 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
{
|
{
|
||||||
mMovementState = movement;
|
mMovementState = movement;
|
||||||
|
|
||||||
std::string movement;
|
std::string movementAnimName;
|
||||||
MWRender::Animation::Group movegroup = MWRender::Animation::Group_All;
|
MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All;
|
||||||
const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState));
|
const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState));
|
||||||
if(movestate != sMovementListEnd)
|
if(movestate != sMovementListEnd)
|
||||||
{
|
{
|
||||||
movement = movestate->groupname;
|
movementAnimName = movestate->groupname;
|
||||||
if(weap != sWeaponTypeListEnd && movement.find("swim") == std::string::npos)
|
if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos)
|
||||||
{
|
{
|
||||||
movement += weap->shortgroup;
|
movementAnimName += weap->shortgroup;
|
||||||
if(!mAnimation->hasAnimation(movement))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
{
|
{
|
||||||
movegroup = MWRender::Animation::Group_LowerBody;
|
movemask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
movement = movestate->groupname;
|
movementAnimName = movestate->groupname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!mAnimation->hasAnimation(movement))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
{
|
{
|
||||||
std::string::size_type swimpos = movement.find("swim");
|
std::string::size_type swimpos = movementAnimName.find("swim");
|
||||||
if(swimpos == std::string::npos)
|
if(swimpos == std::string::npos)
|
||||||
{
|
{
|
||||||
std::string::size_type runpos = movement.find("run");
|
std::string::size_type runpos = movementAnimName.find("run");
|
||||||
if (runpos != std::string::npos)
|
if (runpos != std::string::npos)
|
||||||
{
|
{
|
||||||
movement.replace(runpos, runpos+3, "walk");
|
movementAnimName.replace(runpos, runpos+3, "walk");
|
||||||
if (!mAnimation->hasAnimation(movement))
|
if (!mAnimation->hasAnimation(movementAnimName))
|
||||||
movement.clear();
|
movementAnimName.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
movement.clear();
|
movementAnimName.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
movegroup = MWRender::Animation::Group_LowerBody;
|
movemask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
movement.erase(swimpos, 4);
|
movementAnimName.erase(swimpos, 4);
|
||||||
if(!mAnimation->hasAnimation(movement))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
movement.clear();
|
movementAnimName.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're playing the same animation, restart from the loop start instead of the
|
/* If we're playing the same animation, restart from the loop start instead of the
|
||||||
* beginning. */
|
* beginning. */
|
||||||
int mode = ((movement == mCurrentMovement) ? 2 : 1);
|
int mode = ((movementAnimName == mCurrentMovement) ? 2 : 1);
|
||||||
|
|
||||||
mMovementAnimationControlled = true;
|
mMovementAnimationControlled = true;
|
||||||
|
|
||||||
mAnimation->disable(mCurrentMovement);
|
mAnimation->disable(mCurrentMovement);
|
||||||
mCurrentMovement = movement;
|
mCurrentMovement = movementAnimName;
|
||||||
if(!mCurrentMovement.empty())
|
if(!mCurrentMovement.empty())
|
||||||
{
|
{
|
||||||
float vel, speedmult = 1.0f;
|
float vel, speedmult = 1.0f;
|
||||||
|
@ -447,7 +451,17 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
MWRender::Animation::AnimPriority priorityMovement (Priority_Movement);
|
||||||
|
if ((movement == CharState_TurnLeft || movement == CharState_TurnRight)
|
||||||
|
&& mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()
|
||||||
|
&& MWBase::Environment::get().getWorld()->isFirstPerson())
|
||||||
|
{
|
||||||
|
priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0;
|
||||||
|
priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0;
|
||||||
|
priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAnimation->play(mCurrentMovement, priorityMovement, movemask, false,
|
||||||
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,7 +470,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
|
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
|
||||||
// the idle animation should be displayed
|
// the idle animation should be displayed
|
||||||
if ((mUpperBodyState != UpperCharState_Nothing
|
if ((mUpperBodyState != UpperCharState_Nothing
|
||||||
|| mMovementState != CharState_None
|
|| (mMovementState != CharState_None && mMovementState != CharState_TurnLeft && mMovementState != CharState_TurnRight)
|
||||||
|| mHitState != CharState_None)
|
|| mHitState != CharState_None)
|
||||||
&& !mPtr.getClass().isBipedal(mPtr))
|
&& !mPtr.getClass().isBipedal(mPtr))
|
||||||
idle = CharState_None;
|
idle = CharState_None;
|
||||||
|
@ -486,7 +500,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
mAnimation->disable(mCurrentIdle);
|
mAnimation->disable(mCurrentIdle);
|
||||||
mCurrentIdle = idle;
|
mCurrentIdle = idle;
|
||||||
if(!mCurrentIdle.empty())
|
if(!mCurrentIdle.empty())
|
||||||
mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false,
|
mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false,
|
||||||
1.0f, "start", "stop", 0.0f, ~0ul, true);
|
1.0f, "start", "stop", 0.0f, ~0ul, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +616,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death)
|
||||||
mCurrentJump = "";
|
mCurrentJump = "";
|
||||||
mMovementAnimationControlled = true;
|
mMovementAnimationControlled = true;
|
||||||
|
|
||||||
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All,
|
||||||
false, 1.0f, "start", "stop", startpoint, 0);
|
false, 1.0f, "start", "stop", startpoint, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,7 +718,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
|
|
||||||
|
|
||||||
if(mDeathState == CharState_None)
|
if(mDeathState == CharState_None)
|
||||||
refreshCurrentAnims(mIdleState, mMovementState, true);
|
refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true);
|
||||||
|
|
||||||
mAnimation->runAnimation(0.f);
|
mAnimation->runAnimation(0.f);
|
||||||
}
|
}
|
||||||
|
@ -868,10 +882,10 @@ void CharacterController::updateIdleStormState()
|
||||||
mAnimation->getInfo("idlestorm", &complete);
|
mAnimation->getInfo("idlestorm", &complete);
|
||||||
|
|
||||||
if (complete == 0)
|
if (complete == 0)
|
||||||
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false,
|
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false,
|
||||||
1.0f, "start", "loop start", 0.0f, 0);
|
1.0f, "start", "loop start", 0.0f, 0);
|
||||||
else if (complete == 1)
|
else if (complete == 1)
|
||||||
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false,
|
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false,
|
||||||
1.0f, "loop start", "loop stop", 0.0f, ~0ul);
|
1.0f, "loop start", "loop stop", 0.0f, ~0ul);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -882,7 +896,7 @@ void CharacterController::updateIdleStormState()
|
||||||
{
|
{
|
||||||
if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop"))
|
if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop"))
|
||||||
{
|
{
|
||||||
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true,
|
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, true,
|
||||||
1.0f, "loop stop", "stop", 0.0f, 0);
|
1.0f, "loop stop", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -989,7 +1003,7 @@ bool CharacterController::updateCreatureState()
|
||||||
if (!mCurrentWeapon.empty())
|
if (!mCurrentWeapon.empty())
|
||||||
{
|
{
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
||||||
MWRender::Animation::Group_All, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
1, startKey, stopKey,
|
1, startKey, stopKey,
|
||||||
0.0f, 0);
|
0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
|
@ -1051,6 +1065,9 @@ bool CharacterController::updateWeaponState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
|
||||||
|
priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0;
|
||||||
|
|
||||||
bool forcestateupdate = false;
|
bool forcestateupdate = false;
|
||||||
if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut
|
if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut
|
||||||
&& mHitState != CharState_Hit)
|
&& mHitState != CharState_Hit)
|
||||||
|
@ -1063,8 +1080,8 @@ bool CharacterController::updateWeaponState()
|
||||||
if(weaptype == WeapType_None)
|
if(weaptype == WeapType_None)
|
||||||
{
|
{
|
||||||
getWeaponGroup(mWeaponType, weapgroup);
|
getWeaponGroup(mWeaponType, weapgroup);
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_UnEquipingWeap;
|
mUpperBodyState = UpperCharState_UnEquipingWeap;
|
||||||
}
|
}
|
||||||
|
@ -1074,8 +1091,8 @@ bool CharacterController::updateWeaponState()
|
||||||
mAnimation->showWeapons(false);
|
mAnimation->showWeapons(false);
|
||||||
mAnimation->setWeaponGroup(weapgroup);
|
mAnimation->setWeaponGroup(weapgroup);
|
||||||
|
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
1.0f, "equip start", "equip stop", 0.0f, 0);
|
1.0f, "equip start", "equip stop", 0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_EquipingWeap;
|
mUpperBodyState = UpperCharState_EquipingWeap;
|
||||||
|
|
||||||
|
@ -1145,7 +1162,7 @@ bool CharacterController::updateWeaponState()
|
||||||
bool animPlaying;
|
bool animPlaying;
|
||||||
if(mAttackingOrSpell)
|
if(mAttackingOrSpell)
|
||||||
{
|
{
|
||||||
if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None)
|
if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||||
mAttackType.clear();
|
mAttackType.clear();
|
||||||
|
@ -1154,6 +1171,10 @@ bool CharacterController::updateWeaponState()
|
||||||
// Unset casting flag, otherwise pressing the mouse button down would
|
// Unset casting flag, otherwise pressing the mouse button down would
|
||||||
// continue casting every frame if there is no animation
|
// continue casting every frame if there is no animation
|
||||||
mAttackingOrSpell = false;
|
mAttackingOrSpell = false;
|
||||||
|
if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
|
||||||
|
}
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
|
@ -1191,8 +1212,8 @@ bool CharacterController::updateWeaponState()
|
||||||
case 2: mAttackType = "target"; break;
|
case 2: mAttackType = "target"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
weapSpeed, mAttackType+" start", mAttackType+" stop",
|
weapSpeed, mAttackType+" start", mAttackType+" stop",
|
||||||
0.0f, 0);
|
0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_CastingSpell;
|
mUpperBodyState = UpperCharState_CastingSpell;
|
||||||
|
@ -1223,8 +1244,8 @@ bool CharacterController::updateWeaponState()
|
||||||
else if(item.getTypeName() == typeid(ESM::Probe).name())
|
else if(item.getTypeName() == typeid(ESM::Probe).name())
|
||||||
Security(mPtr).probeTrap(target, item, resultMessage, resultSound);
|
Security(mPtr).probeTrap(target, item, resultMessage, resultSound);
|
||||||
}
|
}
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
1.0f, "start", "stop", 0.0, 0);
|
1.0f, "start", "stop", 0.0, 0);
|
||||||
mUpperBodyState = UpperCharState_FollowStartToFollowStop;
|
mUpperBodyState = UpperCharState_FollowStartToFollowStop;
|
||||||
|
|
||||||
|
@ -1250,8 +1271,8 @@ bool CharacterController::updateWeaponState()
|
||||||
determineAttackType();
|
determineAttackType();
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
weapSpeed, mAttackType+" start", mAttackType+" min attack",
|
weapSpeed, mAttackType+" start", mAttackType+" min attack",
|
||||||
0.0f, 0);
|
0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
|
@ -1301,8 +1322,8 @@ bool CharacterController::updateWeaponState()
|
||||||
mAttackStrength = attackStrength;
|
mAttackStrength = attackStrength;
|
||||||
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
weapSpeed, mAttackType+" max attack", mAttackType+" min hit",
|
weapSpeed, mAttackType+" max attack", mAttackType+" min hit",
|
||||||
1.0f-complete, 0);
|
1.0f-complete, 0);
|
||||||
|
|
||||||
|
@ -1371,15 +1392,6 @@ bool CharacterController::updateWeaponState()
|
||||||
mAnimation->attachArrow();
|
mAnimation->attachArrow();
|
||||||
|
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it
|
|
||||||
if(mHitState == CharState_Hit)
|
|
||||||
{
|
|
||||||
mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody);
|
|
||||||
//commenting out following 2 lines will give a bit different combat dynamics(slower)
|
|
||||||
mHitState = CharState_None;
|
|
||||||
mCurrentHit.clear();
|
|
||||||
mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
|
else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
|
||||||
mUpperBodyState = UpperCharState_Nothing;
|
mUpperBodyState = UpperCharState_Nothing;
|
||||||
|
@ -1397,8 +1409,8 @@ bool CharacterController::updateWeaponState()
|
||||||
case UpperCharState_MinAttackToMaxAttack:
|
case UpperCharState_MinAttackToMaxAttack:
|
||||||
//hack to avoid body pos desync when jumping/sneaking in 'max attack' state
|
//hack to avoid body pos desync when jumping/sneaking in 'max attack' state
|
||||||
if(!mAnimation->isPlaying(mCurrentWeapon))
|
if(!mAnimation->isPlaying(mCurrentWeapon))
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
|
0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
|
||||||
break;
|
break;
|
||||||
case UpperCharState_MaxAttackToMinHit:
|
case UpperCharState_MaxAttackToMinHit:
|
||||||
|
@ -1440,33 +1452,16 @@ bool CharacterController::updateWeaponState()
|
||||||
{
|
{
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
weapSpeed, start, stop, 0.0f, 0);
|
weapSpeed, start, stop, 0.0f, 0);
|
||||||
else
|
else
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
weapSpeed, start, stop, 0.0f, 0);
|
weapSpeed, start, stop, 0.0f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if playing combat animation and lowerbody is not busy switch to whole body animation
|
|
||||||
if((weaptype != WeapType_None || mUpperBodyState == UpperCharState_UnEquipingWeap) && animPlaying)
|
|
||||||
{
|
|
||||||
if( mMovementState != CharState_None ||
|
|
||||||
mJumpState != JumpState_None ||
|
|
||||||
mHitState != CharState_None ||
|
|
||||||
MWBase::Environment::get().getWorld()->isSwimming(mPtr) ||
|
|
||||||
cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak))
|
|
||||||
{
|
|
||||||
mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||||
|
@ -1475,7 +1470,7 @@ bool CharacterController::updateWeaponState()
|
||||||
&& updateCarriedLeftVisible(mWeaponType))
|
&& updateCarriedLeftVisible(mWeaponType))
|
||||||
|
|
||||||
{
|
{
|
||||||
mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm,
|
mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm,
|
||||||
false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true);
|
false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true);
|
||||||
}
|
}
|
||||||
else if (mAnimation->isPlaying("torch"))
|
else if (mAnimation->isPlaying("torch"))
|
||||||
|
@ -1505,7 +1500,7 @@ void CharacterController::update(float duration)
|
||||||
mAnimQueue.pop_front();
|
mAnimQueue.pop_front();
|
||||||
|
|
||||||
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
1.0f, "start", "stop", 0.0f, mAnimQueue.front().second);
|
1.0f, "start", "stop", 0.0f, mAnimQueue.front().second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1562,6 +1557,8 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
CharacterState movestate = CharState_None;
|
CharacterState movestate = CharState_None;
|
||||||
CharacterState idlestate = CharState_SpecialIdle;
|
CharacterState idlestate = CharState_SpecialIdle;
|
||||||
|
JumpingState jumpstate = JumpState_None;
|
||||||
|
|
||||||
bool forcestateupdate = false;
|
bool forcestateupdate = false;
|
||||||
|
|
||||||
mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f;
|
mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f;
|
||||||
|
@ -1644,7 +1641,7 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
forcestateupdate = (mJumpState != JumpState_InAir);
|
forcestateupdate = (mJumpState != JumpState_InAir);
|
||||||
mJumpState = JumpState_InAir;
|
jumpstate = JumpState_InAir;
|
||||||
|
|
||||||
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat();
|
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat();
|
||||||
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
|
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
|
||||||
|
@ -1689,7 +1686,7 @@ void CharacterController::update(float duration)
|
||||||
else if(mJumpState == JumpState_InAir)
|
else if(mJumpState == JumpState_InAir)
|
||||||
{
|
{
|
||||||
forcestateupdate = true;
|
forcestateupdate = true;
|
||||||
mJumpState = JumpState_Landing;
|
jumpstate = JumpState_Landing;
|
||||||
vec.z() = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
float height = cls.getCreatureStats(mPtr).land();
|
float height = cls.getCreatureStats(mPtr).land();
|
||||||
|
@ -1720,7 +1717,7 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mJumpState = JumpState_None;
|
jumpstate = JumpState_None;
|
||||||
vec.z() = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
inJump = false;
|
inJump = false;
|
||||||
|
@ -1786,19 +1783,22 @@ void CharacterController::update(float duration)
|
||||||
mAnimQueue.pop_front();
|
mAnimQueue.pop_front();
|
||||||
|
|
||||||
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
1.0f, "start", "stop", 0.0f, mAnimQueue.front().second);
|
1.0f, "start", "stop", 0.0f, mAnimQueue.front().second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used.
|
|
||||||
if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr))
|
|
||||||
forcestateupdate = updateWeaponState() || forcestateupdate;
|
|
||||||
else
|
|
||||||
forcestateupdate = updateCreatureState() || forcestateupdate;
|
|
||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
{
|
||||||
|
// bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used.
|
||||||
|
if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr))
|
||||||
|
forcestateupdate = updateWeaponState() || forcestateupdate;
|
||||||
|
else
|
||||||
|
forcestateupdate = updateCreatureState() || forcestateupdate;
|
||||||
|
|
||||||
|
refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate);
|
||||||
|
}
|
||||||
|
|
||||||
if (inJump)
|
if (inJump)
|
||||||
mMovementAnimationControlled = false;
|
mMovementAnimationControlled = false;
|
||||||
|
|
||||||
|
@ -1894,7 +1894,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int
|
||||||
|
|
||||||
mIdleState = CharState_SpecialIdle;
|
mIdleState = CharState_SpecialIdle;
|
||||||
mAnimation->play(groupname, Priority_Default,
|
mAnimation->play(groupname, Priority_Default,
|
||||||
MWRender::Animation::Group_All, false, 1.0f,
|
MWRender::Animation::BlendMask_All, false, 1.0f,
|
||||||
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
||||||
}
|
}
|
||||||
else if(mode == 0)
|
else if(mode == 0)
|
||||||
|
@ -1934,7 +1934,7 @@ void CharacterController::forceStateUpdate()
|
||||||
return;
|
return;
|
||||||
clearAnimQueue();
|
clearAnimQueue();
|
||||||
|
|
||||||
refreshCurrentAnims(mIdleState, mMovementState, true);
|
refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true);
|
||||||
if(mDeathState != CharState_None)
|
if(mDeathState != CharState_None)
|
||||||
{
|
{
|
||||||
playRandomDeath();
|
playRandomDeath();
|
||||||
|
@ -2052,12 +2052,13 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell)
|
||||||
|
|
||||||
bool CharacterController::readyToPrepareAttack() const
|
bool CharacterController::readyToPrepareAttack() const
|
||||||
{
|
{
|
||||||
return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped;
|
return (mHitState == CharState_None || mHitState == CharState_Block)
|
||||||
|
&& mUpperBodyState <= UpperCharState_WeapEquiped;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::readyToStartAttack() const
|
bool CharacterController::readyToStartAttack() const
|
||||||
{
|
{
|
||||||
if (mHitState != CharState_None)
|
if (mHitState != CharState_None && mHitState != CharState_Block)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr))
|
||||||
|
|
|
@ -32,6 +32,7 @@ enum Priority {
|
||||||
Priority_Movement,
|
Priority_Movement,
|
||||||
Priority_Hit,
|
Priority_Hit,
|
||||||
Priority_Weapon,
|
Priority_Weapon,
|
||||||
|
Priority_Block,
|
||||||
Priority_Knockdown,
|
Priority_Knockdown,
|
||||||
Priority_Torch,
|
Priority_Torch,
|
||||||
Priority_Storm,
|
Priority_Storm,
|
||||||
|
@ -185,7 +186,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
|
|
||||||
void determineAttackType();
|
void determineAttackType();
|
||||||
|
|
||||||
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
|
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
|
||||||
|
|
||||||
void clearAnimQueue();
|
void clearAnimQueue();
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <components/esm/creaturestats.hpp>
|
#include <components/esm/creaturestats.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/stolenitems.hpp>
|
#include <components/esm/stolenitems.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
@ -1329,6 +1330,27 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker)
|
||||||
|
{
|
||||||
|
if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (victim == attacker)
|
||||||
|
return; // known to happen
|
||||||
|
|
||||||
|
if (!victim.getClass().isNpc())
|
||||||
|
return; // TODO: implement animal rights
|
||||||
|
|
||||||
|
const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim);
|
||||||
|
|
||||||
|
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
||||||
|
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
||||||
|
// for bystanders it is not possible to tell who attacked first, anyway.
|
||||||
|
if (victimStats.getCrimeId() != -1)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)
|
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)
|
||||||
{
|
{
|
||||||
if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled())
|
if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled())
|
||||||
|
|
|
@ -120,6 +120,11 @@ namespace MWMechanics
|
||||||
OffenseType type, int arg=0, bool victimAware=false);
|
OffenseType type, int arg=0, bool victimAware=false);
|
||||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||||
|
|
||||||
|
/// Notify that actor was killed, add a murder bounty if applicable
|
||||||
|
/// @note No-op for non-player attackers
|
||||||
|
virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||||
|
|
||||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||||
/// @param container The container the item is in; may be empty for an item in the world
|
/// @param container The container the item is in; may be empty for an item in the world
|
||||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||||
|
@ -175,13 +180,15 @@ namespace MWMechanics
|
||||||
|
|
||||||
/// Has the player stolen this item from the given owner?
|
/// Has the player stolen this item from the given owner?
|
||||||
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid);
|
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid);
|
||||||
|
|
||||||
|
/// @return is \a ptr allowed to take/use \a cellref or is it a crime?
|
||||||
|
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||||
OffenseType type, int arg=0);
|
OffenseType type, int arg=0);
|
||||||
|
|
||||||
/// @return is \a ptr allowed to take/use \a cellref or is it a crime?
|
|
||||||
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -264,7 +264,7 @@ namespace MWMechanics
|
||||||
float directionX = nextPoint.mX - x;
|
float directionX = nextPoint.mX - x;
|
||||||
float directionY = nextPoint.mY - y;
|
float directionY = nextPoint.mY - y;
|
||||||
|
|
||||||
return osg::RadiansToDegrees(std::atan2(directionX, directionY));
|
return std::atan2(directionX, directionY);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathFinder::checkPathCompleted(float x, float y, float tolerance)
|
bool PathFinder::checkPathCompleted(float x, float y, float tolerance)
|
||||||
|
|
|
@ -19,6 +19,8 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
PathFinder();
|
PathFinder();
|
||||||
|
|
||||||
|
static const int PathTolerance = 32;
|
||||||
|
|
||||||
static float sgn(float val)
|
static float sgn(float val)
|
||||||
{
|
{
|
||||||
if(val > 0)
|
if(val > 0)
|
||||||
|
@ -35,13 +37,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
void clearPath();
|
void clearPath();
|
||||||
|
|
||||||
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
bool checkPathCompleted(float x, float y, float tolerance = PathTolerance);
|
||||||
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
|
||||||
|
|
||||||
bool checkPathCompleted(float x, float y, float tolerance=32.f);
|
|
||||||
///< \Returns true if we are within \a tolerance units of the last path point.
|
///< \Returns true if we are within \a tolerance units of the last path point.
|
||||||
|
|
||||||
/// In degrees
|
/// In radians
|
||||||
float getZAngleToNext(float x, float y) const;
|
float getZAngleToNext(float x, float y) const;
|
||||||
|
|
||||||
bool isPathConstructed() const
|
bool isPathConstructed() const
|
||||||
|
@ -92,6 +91,8 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
|
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
||||||
|
|
||||||
std::list<ESM::Pathgrid::Point> mPath;
|
std::list<ESM::Pathgrid::Point> mPath;
|
||||||
|
|
||||||
|
|
|
@ -313,27 +313,27 @@ namespace MWMechanics
|
||||||
return path; // for some reason couldn't build a path
|
return path; // for some reason couldn't build a path
|
||||||
|
|
||||||
// reconstruct path to return, using world co-ordinates
|
// reconstruct path to return, using world co-ordinates
|
||||||
float xCell = 0;
|
int xCell = 0;
|
||||||
float yCell = 0;
|
int yCell = 0;
|
||||||
if (mIsExterior)
|
if (mIsExterior)
|
||||||
{
|
{
|
||||||
xCell = static_cast<float>(mPathgrid->mData.mX * ESM::Land::REAL_SIZE);
|
xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE;
|
||||||
yCell = static_cast<float>(mPathgrid->mData.mY * ESM::Land::REAL_SIZE);
|
yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(graphParent[current] != -1)
|
while(graphParent[current] != -1)
|
||||||
{
|
{
|
||||||
ESM::Pathgrid::Point pt = mPathgrid->mPoints[current];
|
ESM::Pathgrid::Point pt = mPathgrid->mPoints[current];
|
||||||
pt.mX += static_cast<int>(xCell);
|
pt.mX += xCell;
|
||||||
pt.mY += static_cast<int>(yCell);
|
pt.mY += yCell;
|
||||||
path.push_front(pt);
|
path.push_front(pt);
|
||||||
current = graphParent[current];
|
current = graphParent[current];
|
||||||
}
|
}
|
||||||
|
|
||||||
// add first node to path explicitly
|
// add first node to path explicitly
|
||||||
ESM::Pathgrid::Point pt = mPathgrid->mPoints[start];
|
ESM::Pathgrid::Point pt = mPathgrid->mPoints[start];
|
||||||
pt.mX += static_cast<int>(xCell);
|
pt.mX += xCell;
|
||||||
pt.mY += static_cast<int>(yCell);
|
pt.mY += yCell;
|
||||||
path.push_front(pt);
|
path.push_front(pt);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
|
@ -65,57 +67,6 @@ namespace
|
||||||
target.getClass().getCreatureStats(target).setDynamic(attribute, value);
|
target.getClass().getCreatureStats(target).setDynamic(attribute, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor the effect tick functions in Actors so they can be reused here
|
|
||||||
void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude)
|
|
||||||
{
|
|
||||||
int effectId = effect.mId;
|
|
||||||
if (effectId == ESM::MagicEffect::DamageHealth)
|
|
||||||
{
|
|
||||||
applyDynamicStatsEffect(0, target, magnitude * -1);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::RestoreHealth)
|
|
||||||
{
|
|
||||||
applyDynamicStatsEffect(0, target, magnitude);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::DamageFatigue)
|
|
||||||
{
|
|
||||||
applyDynamicStatsEffect(2, target, magnitude * -1);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::RestoreFatigue)
|
|
||||||
{
|
|
||||||
applyDynamicStatsEffect(2, target, magnitude);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::DamageMagicka)
|
|
||||||
{
|
|
||||||
applyDynamicStatsEffect(1, target, magnitude * -1);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::RestoreMagicka)
|
|
||||||
{
|
|
||||||
applyDynamicStatsEffect(1, target, magnitude);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute)
|
|
||||||
{
|
|
||||||
int attribute = effect.mArg;
|
|
||||||
MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute);
|
|
||||||
if (effectId == ESM::MagicEffect::DamageAttribute)
|
|
||||||
value.damage(magnitude);
|
|
||||||
else
|
|
||||||
value.restore(magnitude);
|
|
||||||
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
|
|
||||||
}
|
|
||||||
else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill)
|
|
||||||
{
|
|
||||||
if (target.getTypeName() != typeid(ESM::NPC).name())
|
|
||||||
return;
|
|
||||||
int skill = effect.mArg;
|
|
||||||
MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill);
|
|
||||||
if (effectId == ESM::MagicEffect::DamageSkill)
|
|
||||||
value.damage(magnitude);
|
|
||||||
else
|
|
||||||
value.restore(magnitude);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -530,7 +481,14 @@ namespace MWMechanics
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hasDuration && target.getClass().isActor())
|
if (hasDuration && target.getClass().isActor())
|
||||||
applyInstantEffectTick(EffectKey(*effectIt), target, magnitude);
|
{
|
||||||
|
bool wasDead = target.getClass().getCreatureStats(target).isDead();
|
||||||
|
effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude);
|
||||||
|
bool isDead = target.getClass().getCreatureStats(target).isDead();
|
||||||
|
|
||||||
|
if (!wasDead && isDead)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
|
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
|
||||||
}
|
}
|
||||||
|
@ -960,4 +918,170 @@ namespace MWMechanics
|
||||||
|| (effectId >= ESM::MagicEffect::SummonFabricant
|
|| (effectId >= ESM::MagicEffect::SummonFabricant
|
||||||
&& effectId <= ESM::MagicEffect::SummonCreature05));
|
&& effectId <= ESM::MagicEffect::SummonCreature05));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
||||||
|
{
|
||||||
|
if (ptr.getClass().hasInventoryStore(ptr))
|
||||||
|
{
|
||||||
|
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||||
|
MWWorld::ContainerStoreIterator item =
|
||||||
|
inv.getSlot(slot);
|
||||||
|
if (item != inv.end())
|
||||||
|
{
|
||||||
|
if (!item->getClass().hasItemHealth(*item))
|
||||||
|
return false;
|
||||||
|
int charge = item->getClass().getItemHealth(*item);
|
||||||
|
|
||||||
|
if (charge == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
||||||
|
// This was also a bug in the original engine.
|
||||||
|
charge -=
|
||||||
|
std::min(static_cast<int>(disintegrate),
|
||||||
|
charge);
|
||||||
|
item->getCellRef().setCharge(charge);
|
||||||
|
|
||||||
|
if (charge == 0)
|
||||||
|
{
|
||||||
|
// Will unequip the broken item and try to find a replacement
|
||||||
|
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
|
inv.autoEquip(ptr);
|
||||||
|
else
|
||||||
|
inv.unequipItem(*item, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude)
|
||||||
|
{
|
||||||
|
DynamicStat<float> stat = creatureStats.getDynamic(index);
|
||||||
|
stat.setCurrent(stat.getCurrent() + magnitude, index == 2);
|
||||||
|
creatureStats.setDynamic(index, stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
|
||||||
|
{
|
||||||
|
if (magnitude == 0.f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool receivedMagicDamage = false;
|
||||||
|
|
||||||
|
switch (effectKey.mId)
|
||||||
|
{
|
||||||
|
case ESM::MagicEffect::DamageAttribute:
|
||||||
|
{
|
||||||
|
AttributeValue attr = creatureStats.getAttribute(effectKey.mArg);
|
||||||
|
attr.damage(magnitude);
|
||||||
|
creatureStats.setAttribute(effectKey.mArg, attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::MagicEffect::RestoreAttribute:
|
||||||
|
{
|
||||||
|
AttributeValue attr = creatureStats.getAttribute(effectKey.mArg);
|
||||||
|
attr.restore(magnitude);
|
||||||
|
creatureStats.setAttribute(effectKey.mArg, attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::MagicEffect::RestoreHealth:
|
||||||
|
case ESM::MagicEffect::RestoreMagicka:
|
||||||
|
case ESM::MagicEffect::RestoreFatigue:
|
||||||
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude);
|
||||||
|
break;
|
||||||
|
case ESM::MagicEffect::DamageHealth:
|
||||||
|
case ESM::MagicEffect::DamageMagicka:
|
||||||
|
case ESM::MagicEffect::DamageFatigue:
|
||||||
|
receivedMagicDamage = true;
|
||||||
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
|
||||||
|
break;
|
||||||
|
case ESM::MagicEffect::AbsorbHealth:
|
||||||
|
case ESM::MagicEffect::AbsorbMagicka:
|
||||||
|
case ESM::MagicEffect::AbsorbFatigue:
|
||||||
|
if (magnitude > 0.f)
|
||||||
|
receivedMagicDamage = true;
|
||||||
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::MagicEffect::DisintegrateArmor:
|
||||||
|
{
|
||||||
|
// According to UESP
|
||||||
|
int priorities[] = {
|
||||||
|
MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||||
|
MWWorld::InventoryStore::Slot_Cuirass,
|
||||||
|
MWWorld::InventoryStore::Slot_LeftPauldron,
|
||||||
|
MWWorld::InventoryStore::Slot_RightPauldron,
|
||||||
|
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
||||||
|
MWWorld::InventoryStore::Slot_RightGauntlet,
|
||||||
|
MWWorld::InventoryStore::Slot_Helmet,
|
||||||
|
MWWorld::InventoryStore::Slot_Greaves,
|
||||||
|
MWWorld::InventoryStore::Slot_Boots
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
|
||||||
|
{
|
||||||
|
if (disintegrateSlot(actor, priorities[i], magnitude))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::MagicEffect::DisintegrateWeapon:
|
||||||
|
disintegrateSlot(actor, MWWorld::InventoryStore::Slot_CarriedRight, magnitude);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESM::MagicEffect::SunDamage:
|
||||||
|
{
|
||||||
|
// isInCell shouldn't be needed, but updateActor called during game start
|
||||||
|
if (!actor.isInCell() || !actor.getCell()->isExterior())
|
||||||
|
break;
|
||||||
|
float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour();
|
||||||
|
float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13)));
|
||||||
|
float damageScale = 1.f - timeDiff / 7.f;
|
||||||
|
// When cloudy, the sun damage effect is halved
|
||||||
|
static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
|
"fMagicSunBlockedMult")->getFloat();
|
||||||
|
|
||||||
|
int weather = MWBase::Environment::get().getWorld()->getCurrentWeather();
|
||||||
|
if (weather > 1)
|
||||||
|
damageScale *= fMagicSunBlockedMult;
|
||||||
|
|
||||||
|
adjustDynamicStat(creatureStats, 0, -magnitude * damageScale);
|
||||||
|
if (magnitude * damageScale > 0.f)
|
||||||
|
receivedMagicDamage = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ESM::MagicEffect::FireDamage:
|
||||||
|
case ESM::MagicEffect::ShockDamage:
|
||||||
|
case ESM::MagicEffect::FrostDamage:
|
||||||
|
case ESM::MagicEffect::Poison:
|
||||||
|
{
|
||||||
|
adjustDynamicStat(creatureStats, 0, -magnitude);
|
||||||
|
receivedMagicDamage = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ESM::MagicEffect::DamageSkill:
|
||||||
|
case ESM::MagicEffect::RestoreSkill:
|
||||||
|
{
|
||||||
|
if (!actor.getClass().isNpc())
|
||||||
|
break;
|
||||||
|
NpcStats &npcStats = actor.getClass().getNpcStats(actor);
|
||||||
|
SkillValue& skill = npcStats.getSkill(effectKey.mArg);
|
||||||
|
if (effectKey.mId == ESM::MagicEffect::RestoreSkill)
|
||||||
|
skill.restore(magnitude);
|
||||||
|
else
|
||||||
|
skill.damage(magnitude);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
|
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
struct EffectKey;
|
struct EffectKey;
|
||||||
class MagicEffects;
|
class MagicEffects;
|
||||||
|
class CreatureStats;
|
||||||
|
|
||||||
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
|
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
|
||||||
|
|
||||||
|
@ -60,6 +61,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
|
||||||
|
|
||||||
class CastSpell
|
class CastSpell
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <components/esm/loadspel.hpp>
|
#include <components/esm/loadspel.hpp>
|
||||||
#include <components/esm/spellstate.hpp>
|
#include <components/esm/spellstate.hpp>
|
||||||
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue