forked from teamnwah/openmw-tes3coop
Merge pull request #457 from OpenMW/master while resolving conflicts
Conflicts: CMakeLists.txt apps/openmw/engine.cpp apps/openmw/main.cpp apps/openmw/mwgui/windowmanagerimp.cpp apps/openmw/mwmechanics/character.cpp components/CMakeLists.txt
This commit is contained in:
commit
6cb5ac6e63
111 changed files with 1582 additions and 678 deletions
|
@ -34,6 +34,8 @@ MacOS:
|
||||||
tags:
|
tags:
|
||||||
- macos
|
- macos
|
||||||
- xcode
|
- xcode
|
||||||
|
except:
|
||||||
|
- branches # because our CI VMs are not public, MRs can't use them and timeout
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
|
@ -43,4 +45,25 @@ MacOS:
|
||||||
- cd build; make -j2 package
|
- cd build; make -j2 package
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- build/OpenMW-*.dmg
|
- build/OpenMW-*.dmg
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
tags:
|
||||||
|
- win10
|
||||||
|
- msvc2017
|
||||||
|
except:
|
||||||
|
- branches # because our CI VMs are not public, MRs can't use them and timeout
|
||||||
|
stage: build
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
# - env # turn on for debugging
|
||||||
|
- sh %CI_PROJECT_DIR%/CI/before_script.msvc.sh -c Release -p x64 -v 2017 -V
|
||||||
|
- SET msBuildLocation="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe"
|
||||||
|
- call %msBuildLocation% MSVC2017_64\OpenMW.sln /t:Build /p:Configuration=Release /m:%NUMBER_OF_PROCESSORS%
|
||||||
|
- 7z a OpenMW_MSVC2017_64_%CI_BUILD_REF_NAME%_%CI_BUILD_ID%.zip %CI_PROJECT_DIR%\MSVC2017_64\Release\
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- deps
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- "*.zip"
|
||||||
|
|
|
@ -143,6 +143,7 @@ Programmers
|
||||||
Rohit Nirmal
|
Rohit Nirmal
|
||||||
Roman Melnik (Kromgart)
|
Roman Melnik (Kromgart)
|
||||||
Roman Proskuryakov (kpp)
|
Roman Proskuryakov (kpp)
|
||||||
|
Roman Siromakha (elsid)
|
||||||
Sandy Carter (bwrsandman)
|
Sandy Carter (bwrsandman)
|
||||||
Scott Howard
|
Scott Howard
|
||||||
scrawl
|
scrawl
|
||||||
|
|
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -2,6 +2,7 @@
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #1990: Sunrise/sunset not set correct
|
Bug #1990: Sunrise/sunset not set correct
|
||||||
|
Bug #2131: Lustidrike's spell misses the player every time
|
||||||
Bug #2222: Fatigue's effect on selling price is backwards
|
Bug #2222: Fatigue's effect on selling price is backwards
|
||||||
Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped
|
Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped
|
||||||
Bug #2455: Creatures attacks degrade armor
|
Bug #2455: Creatures attacks degrade armor
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
Bug #2852: No murder bounty when a player follower commits murder
|
Bug #2852: No murder bounty when a player follower commits murder
|
||||||
Bug #2862: [macOS] Can't quit launcher using Command-Q or OpenMW->Quit
|
Bug #2862: [macOS] Can't quit launcher using Command-Q or OpenMW->Quit
|
||||||
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
||||||
|
Bug #3249: Fixed revert function not updating views properly
|
||||||
Bug #3374: Touch spells not hitting kwama foragers
|
Bug #3374: Touch spells not hitting kwama foragers
|
||||||
Bug #3486: [Mod] NPC Commands does not work
|
Bug #3486: [Mod] NPC Commands does not work
|
||||||
Bug #3591: Angled hit distance too low
|
Bug #3591: Angled hit distance too low
|
||||||
|
@ -22,15 +24,18 @@
|
||||||
Bug #3997: Almalexia doesn't pace
|
Bug #3997: Almalexia doesn't pace
|
||||||
Bug #4036: Weird behaviour of AI packages if package target has non-unique ID
|
Bug #4036: Weird behaviour of AI packages if package target has non-unique ID
|
||||||
Bug #4047: OpenMW not reporting its version number in MacOS; OpenMW-CS not doing it fully
|
Bug #4047: OpenMW not reporting its version number in MacOS; OpenMW-CS not doing it fully
|
||||||
|
Bug #4110: Fixed undo / redo menu text losing the assigned shortcuts
|
||||||
Bug #4125: OpenMW logo cropped on bugtracker
|
Bug #4125: OpenMW logo cropped on bugtracker
|
||||||
Bug #4215: OpenMW shows book text after last EOL tag
|
Bug #4215: OpenMW shows book text after last EOL tag
|
||||||
Bug #4221: Characters get stuck in V-shaped terrain
|
Bug #4221: Characters get stuck in V-shaped terrain
|
||||||
Bug #4251: Stationary NPCs do not return to their position after combat
|
Bug #4251: Stationary NPCs do not return to their position after combat
|
||||||
|
Bug #4274: Pre-0.43 death animations are not forward-compatible with 0.43+
|
||||||
Bug #4286: Scripted animations can be interrupted
|
Bug #4286: Scripted animations can be interrupted
|
||||||
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
|
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
|
||||||
Bug #4293: Faction members are not aware of faction ownerships in barter
|
Bug #4293: Faction members are not aware of faction ownerships in barter
|
||||||
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
|
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
|
||||||
Bug #4327: Missing animations during spell/weapon stance switching
|
Bug #4327: Missing animations during spell/weapon stance switching
|
||||||
|
Bug #4358: Running animation is interrupted when magic mode is toggled
|
||||||
Bug #4368: Settings window ok button doesn't have key focus by default
|
Bug #4368: Settings window ok button doesn't have key focus by default
|
||||||
Bug #4393: NPCs walk back to where they were after using ResetActors
|
Bug #4393: NPCs walk back to where they were after using ResetActors
|
||||||
Bug #4416: Handle exception if we try to play non-music file
|
Bug #4416: Handle exception if we try to play non-music file
|
||||||
|
@ -47,12 +52,23 @@
|
||||||
Bug #4457: Item without CanCarry flag prevents shield autoequipping in dark areas
|
Bug #4457: Item without CanCarry flag prevents shield autoequipping in dark areas
|
||||||
Bug #4458: AiWander console command handles idle chances incorrectly
|
Bug #4458: AiWander console command handles idle chances incorrectly
|
||||||
Bug #4459: NotCell dialogue condition doesn't support partial matches
|
Bug #4459: NotCell dialogue condition doesn't support partial matches
|
||||||
|
Bug #4460: Script function "Equip" doesn't bypass beast restrictions
|
||||||
Bug #4461: "Open" spell from non-player caster isn't a crime
|
Bug #4461: "Open" spell from non-player caster isn't a crime
|
||||||
|
Bug #4464: OpenMW keeps AiState cached storages even after we cancel AI packages
|
||||||
Bug #4469: Abot Silt Striders – Model turn 90 degrees on horizontal
|
Bug #4469: Abot Silt Striders – Model turn 90 degrees on horizontal
|
||||||
Bug #4474: No fallback when getVampireHead fails
|
Bug #4474: No fallback when getVampireHead fails
|
||||||
Bug #4475: Scripted animations should not cause movement
|
Bug #4475: Scripted animations should not cause movement
|
||||||
Bug #4479: "Game" category on Advanced page is getting too long
|
Bug #4479: "Game" category on Advanced page is getting too long
|
||||||
Bug #4480: Segfalt in QuickKeysMenu when item no longer in inventory
|
Bug #4480: Segfault in QuickKeysMenu when item no longer in inventory
|
||||||
|
Bug #4489: Goodbye doesn't block dialogue hyperlinks
|
||||||
|
Bug #4490: PositionCell on player gives "Error: tried to add local script twice"
|
||||||
|
Bug #4491: Training cap based off Base Skill instead of Modified Skill
|
||||||
|
Bug #4495: Crossbow animations blending is buggy
|
||||||
|
Bug #4496: SpellTurnLeft and SpellTurnRight animation groups are unused
|
||||||
|
Bug #4497: File names starting with x or X are not classified as animation
|
||||||
|
Bug #4503: Cast and ExplodeSpell commands increase alteration skill
|
||||||
|
Feature #2606: Editor: Implemented (optional) case sensitive global search
|
||||||
|
Feature #3083: Play animation when NPC is casting spell via script
|
||||||
Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results
|
Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results
|
||||||
Feature #3641: Editor: Limit FPS in 3d preview window
|
Feature #3641: Editor: Limit FPS in 3d preview window
|
||||||
Feature #4222: 360° screenshots
|
Feature #4222: 360° screenshots
|
||||||
|
@ -62,6 +78,8 @@
|
||||||
Feature #4404: Editor: All EnumDelegate fields should have their items sorted alphabetically
|
Feature #4404: Editor: All EnumDelegate fields should have their items sorted alphabetically
|
||||||
Feature #4444: Per-group KF-animation files support
|
Feature #4444: Per-group KF-animation files support
|
||||||
Feature #4466: Editor: Add option to ignore "Base" records when running verifier
|
Feature #4466: Editor: Add option to ignore "Base" records when running verifier
|
||||||
|
Feature #4012: Editor: Write a log file if OpenCS crashes
|
||||||
|
Task #2490: Don't open command prompt window on Release-mode builds automatically
|
||||||
|
|
||||||
0.44.0
|
0.44.0
|
||||||
------
|
------
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# set -x # turn-on for debugging
|
||||||
|
|
||||||
MISSINGTOOLS=0
|
MISSINGTOOLS=0
|
||||||
|
|
||||||
|
@ -76,7 +77,6 @@ while [ $# -gt 0 ]; do
|
||||||
h )
|
h )
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $0 [-cdehkpuvV]
|
Usage: $0 [-cdehkpuvV]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-c <Release/Debug>
|
-c <Release/Debug>
|
||||||
Set the configuration, can also be set with environment variable CONFIGURATION.
|
Set the configuration, can also be set with environment variable CONFIGURATION.
|
||||||
|
@ -232,10 +232,9 @@ fi
|
||||||
case $VS_VERSION in
|
case $VS_VERSION in
|
||||||
15|15.0|2017 )
|
15|15.0|2017 )
|
||||||
GENERATOR="Visual Studio 15 2017"
|
GENERATOR="Visual Studio 15 2017"
|
||||||
TOOLSET="vc140"
|
TOOLSET="vc141"
|
||||||
TOOLSET_REAL="vc141"
|
|
||||||
MSVC_REAL_VER="15"
|
MSVC_REAL_VER="15"
|
||||||
MSVC_VER="14"
|
MSVC_VER="14.1"
|
||||||
MSVC_YEAR="2015"
|
MSVC_YEAR="2015"
|
||||||
MSVC_DISPLAY_YEAR="2017"
|
MSVC_DISPLAY_YEAR="2017"
|
||||||
;;
|
;;
|
||||||
|
@ -243,9 +242,8 @@ case $VS_VERSION in
|
||||||
14|14.0|2015 )
|
14|14.0|2015 )
|
||||||
GENERATOR="Visual Studio 14 2015"
|
GENERATOR="Visual Studio 14 2015"
|
||||||
TOOLSET="vc140"
|
TOOLSET="vc140"
|
||||||
TOOLSET_REAL="vc140"
|
|
||||||
MSVC_REAL_VER="14"
|
MSVC_REAL_VER="14"
|
||||||
MSVC_VER="14"
|
MSVC_VER="14.0"
|
||||||
MSVC_YEAR="2015"
|
MSVC_YEAR="2015"
|
||||||
MSVC_DISPLAY_YEAR="2015"
|
MSVC_DISPLAY_YEAR="2015"
|
||||||
;;
|
;;
|
||||||
|
@ -253,9 +251,8 @@ case $VS_VERSION in
|
||||||
12|12.0|2013 )
|
12|12.0|2013 )
|
||||||
GENERATOR="Visual Studio 12 2013"
|
GENERATOR="Visual Studio 12 2013"
|
||||||
TOOLSET="vc120"
|
TOOLSET="vc120"
|
||||||
TOOLSET_REAL="vc120"
|
|
||||||
MSVC_REAL_VER="12"
|
MSVC_REAL_VER="12"
|
||||||
MSVC_VER="12"
|
MSVC_VER="12.0"
|
||||||
MSVC_YEAR="2013"
|
MSVC_YEAR="2013"
|
||||||
MSVC_DISPLAY_YEAR="2013"
|
MSVC_DISPLAY_YEAR="2013"
|
||||||
;;
|
;;
|
||||||
|
@ -325,9 +322,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
|
|
||||||
# Boost
|
# Boost
|
||||||
if [ -z $APPVEYOR ]; then
|
if [ -z $APPVEYOR ]; then
|
||||||
download "Boost 1.61.0" \
|
download "Boost 1.67.0" \
|
||||||
"https://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \
|
"https://sourceforge.net/projects/boost/files/boost-binaries/1.67.0/boost_1_67_0-msvc-${MSVC_VER}-${BITS}.exe" \
|
||||||
"boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe"
|
"boost-1.67.0-msvc${MSVC_YEAR}-win${BITS}.exe"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Bullet
|
# Bullet
|
||||||
|
@ -365,8 +362,8 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
QT_SUFFIX=""
|
QT_SUFFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
download "Qt 5.7.2" \
|
download "Qt 5.7.0" \
|
||||||
"https://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \
|
"https://download.qt.io/archive/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \
|
||||||
"qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \
|
"qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \
|
||||||
"https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \
|
"https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \
|
||||||
"qt-5-install.qs"
|
"qt-5-install.qs"
|
||||||
|
@ -403,9 +400,9 @@ echo
|
||||||
|
|
||||||
# Boost
|
# Boost
|
||||||
if [ -z $APPVEYOR ]; then
|
if [ -z $APPVEYOR ]; then
|
||||||
printf "Boost 1.61.0... "
|
printf "Boost 1.67.0... "
|
||||||
else
|
else
|
||||||
if [ $MSVC_VER -eq 12 ]; then
|
if [ $MSVC_VER -eq 12.0 ]; then
|
||||||
printf "Boost 1.58.0 AppVeyor... "
|
printf "Boost 1.58.0 AppVeyor... "
|
||||||
else
|
else
|
||||||
printf "Boost 1.67.0 AppVeyor... "
|
printf "Boost 1.67.0 AppVeyor... "
|
||||||
|
@ -417,17 +414,27 @@ fi
|
||||||
|
|
||||||
BOOST_SDK="$(real_pwd)/Boost"
|
BOOST_SDK="$(real_pwd)/Boost"
|
||||||
|
|
||||||
if [ -d Boost ] && grep "BOOST_VERSION 106100" Boost/boost/version.hpp > /dev/null; then
|
# Boost's installer is still based on ms-dos API that doesn't support larger than 260 char path names
|
||||||
|
# We work around this by installing to root of the current working drive and then move it to our deps
|
||||||
|
# get the current working drive's root, we'll install to that temporarily
|
||||||
|
CWD_DRIVE_ROOT="$(powershell -command '(get-location).Drive.Root')Boost_temp"
|
||||||
|
CWD_DRIVE_ROOT_BASH=$(echo "$CWD_DRIVE_ROOT" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
|
||||||
|
if [ -d CWD_DRIVE_ROOT_BASH ]; then
|
||||||
|
printf "Cannot continue, ${CWD_DRIVE_ROOT_BASH} aka ${CWD_DRIVE_ROOT} already exists. Please remove before re-running. ";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d ${BOOST_SDK} ] && grep "BOOST_VERSION 106700" Boost/boost/version.hpp > /dev/null; then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf Boost
|
rm -rf Boost
|
||||||
"${DEPS}/boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe" //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent
|
[ -n "$CI" ] && CI_EXTRA_INNO_OPTIONS="//SUPPRESSMSGBOXES //LOG='boost_install.log'"
|
||||||
|
"${DEPS}/boost-1.67.0-msvc${MSVC_YEAR}-win${BITS}.exe" //DIR="${CWD_DRIVE_ROOT}" //VERYSILENT //NORESTART ${CI_EXTRA_INNO_OPTIONS}
|
||||||
|
mv "${CWD_DRIVE_ROOT_BASH}" "${BOOST_SDK}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
|
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
|
||||||
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.0"
|
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}"
|
||||||
add_cmake_opts -DBoost_COMPILER="-${TOOLSET}"
|
add_cmake_opts -DBoost_COMPILER="-${TOOLSET}"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
else
|
else
|
||||||
# Appveyor unstable has all the boost we need already
|
# Appveyor unstable has all the boost we need already
|
||||||
|
@ -444,19 +451,17 @@ fi
|
||||||
|
|
||||||
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
|
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
|
||||||
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.${LIB_SUFFIX}"
|
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.${LIB_SUFFIX}"
|
||||||
add_cmake_opts -DBoost_COMPILER="-${TOOLSET_REAL}"
|
add_cmake_opts -DBoost_COMPILER="-${TOOLSET}"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Bullet
|
# Bullet
|
||||||
printf "Bullet 2.86... "
|
printf "Bullet 2.86... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
|
|
||||||
if [ -d Bullet ]; then
|
if [ -d Bullet ]; then
|
||||||
printf -- "Exists. (No version checking) "
|
printf -- "Exists. (No version checking) "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
|
@ -464,49 +469,38 @@ printf "Bullet 2.86... "
|
||||||
eval 7z x -y "${DEPS}/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
eval 7z x -y "${DEPS}/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||||
mv "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}" Bullet
|
mv "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}" Bullet
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export BULLET_ROOT="$(real_pwd)/Bullet"
|
export BULLET_ROOT="$(real_pwd)/Bullet"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# FFmpeg
|
# FFmpeg
|
||||||
printf "FFmpeg 3.2.4... "
|
printf "FFmpeg 3.2.4... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
|
|
||||||
if [ -d FFmpeg ] && grep "FFmpeg version: 3.2.4" FFmpeg/README.txt > /dev/null; then
|
if [ -d FFmpeg ] && grep "FFmpeg version: 3.2.4" FFmpeg/README.txt > /dev/null; then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf FFmpeg
|
rm -rf FFmpeg
|
||||||
|
|
||||||
eval 7z x -y "${DEPS}/ffmpeg-3.2.4-win${BITS}.zip" $STRIP
|
eval 7z x -y "${DEPS}/ffmpeg-3.2.4-win${BITS}.zip" $STRIP
|
||||||
eval 7z x -y "${DEPS}/ffmpeg-3.2.4-dev-win${BITS}.zip" $STRIP
|
eval 7z x -y "${DEPS}/ffmpeg-3.2.4-dev-win${BITS}.zip" $STRIP
|
||||||
|
|
||||||
mv "ffmpeg-3.2.4-win${BITS}-shared" FFmpeg
|
mv "ffmpeg-3.2.4-win${BITS}-shared" FFmpeg
|
||||||
cp -r "ffmpeg-3.2.4-win${BITS}-dev/"* FFmpeg/
|
cp -r "ffmpeg-3.2.4-win${BITS}-dev/"* FFmpeg/
|
||||||
rm -rf "ffmpeg-3.2.4-win${BITS}-dev"
|
rm -rf "ffmpeg-3.2.4-win${BITS}-dev"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export FFMPEG_HOME="$(real_pwd)/FFmpeg"
|
export FFMPEG_HOME="$(real_pwd)/FFmpeg"
|
||||||
add_runtime_dlls "$(pwd)/FFmpeg/bin/"{avcodec-57,avformat-57,avutil-55,swresample-2,swscale-4}.dll
|
add_runtime_dlls "$(pwd)/FFmpeg/bin/"{avcodec-57,avformat-57,avutil-55,swresample-2,swscale-4}.dll
|
||||||
|
|
||||||
if [ $BITS -eq 32 ]; then
|
if [ $BITS -eq 32 ]; then
|
||||||
add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\""
|
add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# MyGUI
|
# MyGUI
|
||||||
printf "MyGUI 3.2.2... "
|
printf "MyGUI 3.2.2... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
|
|
||||||
if [ -d MyGUI ] && \
|
if [ -d MyGUI ] && \
|
||||||
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||||
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||||
|
@ -518,21 +512,17 @@ printf "MyGUI 3.2.2... "
|
||||||
eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||||
mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI
|
mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export MYGUI_HOME="$(real_pwd)/MyGUI"
|
export MYGUI_HOME="$(real_pwd)/MyGUI"
|
||||||
|
|
||||||
if [ $CONFIGURATION == "Debug" ]; then
|
if [ $CONFIGURATION == "Debug" ]; then
|
||||||
SUFFIX="_d"
|
SUFFIX="_d"
|
||||||
else
|
else
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
fi
|
fi
|
||||||
add_runtime_dlls "$(pwd)/MyGUI/bin/${CONFIGURATION}/MyGUIEngine${SUFFIX}.dll"
|
add_runtime_dlls "$(pwd)/MyGUI/bin/${CONFIGURATION}/MyGUIEngine${SUFFIX}.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# OpenAL
|
# OpenAL
|
||||||
printf "OpenAL-Soft 1.17.2... "
|
printf "OpenAL-Soft 1.17.2... "
|
||||||
{
|
{
|
||||||
|
@ -542,24 +532,18 @@ printf "OpenAL-Soft 1.17.2... "
|
||||||
rm -rf openal-soft-1.17.2-bin
|
rm -rf openal-soft-1.17.2-bin
|
||||||
eval 7z x -y OpenAL-Soft-1.17.2.zip $STRIP
|
eval 7z x -y OpenAL-Soft-1.17.2.zip $STRIP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OPENAL_SDK="$(real_pwd)/openal-soft-1.17.2-bin"
|
OPENAL_SDK="$(real_pwd)/openal-soft-1.17.2-bin"
|
||||||
|
|
||||||
add_cmake_opts -DOPENAL_INCLUDE_DIR="${OPENAL_SDK}/include/AL" \
|
add_cmake_opts -DOPENAL_INCLUDE_DIR="${OPENAL_SDK}/include/AL" \
|
||||||
-DOPENAL_LIBRARY="${OPENAL_SDK}/libs/Win${BITS}/OpenAL32.lib"
|
-DOPENAL_LIBRARY="${OPENAL_SDK}/libs/Win${BITS}/OpenAL32.lib"
|
||||||
|
|
||||||
add_runtime_dlls "$(pwd)/openal-soft-1.17.2-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll"
|
add_runtime_dlls "$(pwd)/openal-soft-1.17.2-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# OSG
|
# OSG
|
||||||
printf "OSG 3.4.1-scrawl... "
|
printf "OSG 3.4.1-scrawl... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
|
|
||||||
if [ -d OSG ] && \
|
if [ -d OSG ] && \
|
||||||
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
||||||
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
|
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
|
||||||
|
@ -571,28 +555,21 @@ printf "OSG 3.4.1-scrawl... "
|
||||||
eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||||
mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG
|
mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OSG_SDK="$(real_pwd)/OSG"
|
OSG_SDK="$(real_pwd)/OSG"
|
||||||
|
|
||||||
add_cmake_opts -DOSG_DIR="$OSG_SDK"
|
add_cmake_opts -DOSG_DIR="$OSG_SDK"
|
||||||
|
|
||||||
if [ $CONFIGURATION == "Debug" ]; then
|
if [ $CONFIGURATION == "Debug" ]; then
|
||||||
SUFFIX="d"
|
SUFFIX="d"
|
||||||
else
|
else
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
|
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
|
||||||
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll
|
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll
|
||||||
|
|
||||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
|
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
|
||||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll
|
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Qt
|
# Qt
|
||||||
if [ -z $APPVEYOR ]; then
|
if [ -z $APPVEYOR ]; then
|
||||||
printf "Qt 5.7.0... "
|
printf "Qt 5.7.0... "
|
||||||
|
@ -605,71 +582,53 @@ fi
|
||||||
else
|
else
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z $APPVEYOR ]; then
|
if [ -z $APPVEYOR ]; then
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
QT_SDK="$(real_pwd)/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}"
|
QT_SDK="$(real_pwd)/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}"
|
||||||
|
|
||||||
if [ -d Qt ] && head -n2 Qt/InstallationLog.txt | grep "5.7.0" > /dev/null; then
|
if [ -d Qt ] && head -n2 Qt/InstallationLog.txt | grep "5.7.0" > /dev/null; then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf Qt
|
rm -rf Qt
|
||||||
cp "${DEPS}/qt-5-install.qs" qt-install.qs
|
cp "${DEPS}/qt-5-install.qs" qt-install.qs
|
||||||
|
|
||||||
|
|
||||||
sed -i "s|INSTALL_DIR|$(real_pwd)/Qt|" qt-install.qs
|
sed -i "s|INSTALL_DIR|$(real_pwd)/Qt|" qt-install.qs
|
||||||
sed -i "s/qt.VERSION.winBITS_msvcYEAR/qt.57.win${BITS}_msvc${MSVC_YEAR}${SUFFIX}/" qt-install.qs
|
sed -i "s/qt.VERSION.winBITS_msvcYEAR/qt.57.win${BITS}_msvc${MSVC_YEAR}${SUFFIX}/" qt-install.qs
|
||||||
|
|
||||||
printf -- "(Installation might take a while) "
|
printf -- "(Installation might take a while) "
|
||||||
"${DEPS}/qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" --script qt-install.qs --silent
|
"${DEPS}/qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" --script qt-install.qs --silent
|
||||||
|
|
||||||
mv qt-install.qs Qt/
|
mv qt-install.qs Qt/
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
printf " Cleaning up extraneous data... "
|
printf " Cleaning up extraneous data... "
|
||||||
rm -r "$(real_pwd)/Qt/"{dist,Docs,Examples,Tools,vcredist,components.xml,MaintenanceTool.dat,MaintenanceTool.exe,MaintenanceTool.ini,network.xml,qt-install.qs}
|
rm -r "$(real_pwd)/Qt/"{dist,Docs,Examples,Tools,vcredist,components.xml,MaintenanceTool.dat,MaintenanceTool.exe,MaintenanceTool.ini,network.xml,qt-install.qs}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd $QT_SDK
|
cd $QT_SDK
|
||||||
|
|
||||||
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
||||||
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
||||||
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
||||||
|
|
||||||
if [ $CONFIGURATION == "Debug" ]; then
|
if [ $CONFIGURATION == "Debug" ]; then
|
||||||
SUFFIX="d"
|
SUFFIX="d"
|
||||||
else
|
else
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
add_runtime_dlls "$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
add_runtime_dlls "$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
||||||
add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll"
|
add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
else
|
else
|
||||||
QT_SDK="C:/Qt/5.10/msvc${MSVC_DISPLAY_YEAR}${SUFFIX}"
|
QT_SDK="C:/Qt/5.10/msvc${MSVC_DISPLAY_YEAR}${SUFFIX}"
|
||||||
|
|
||||||
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
||||||
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
||||||
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
||||||
|
|
||||||
if [ $CONFIGURATION == "Debug" ]; then
|
if [ $CONFIGURATION == "Debug" ]; then
|
||||||
SUFFIX="d"
|
SUFFIX="d"
|
||||||
else
|
else
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
|
DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
|
||||||
|
|
||||||
add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
||||||
add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll"
|
add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# SDL2
|
# SDL2
|
||||||
printf "SDL 2.0.7... "
|
printf "SDL 2.0.7... "
|
||||||
{
|
{
|
||||||
|
@ -679,26 +638,18 @@ printf "SDL 2.0.7... "
|
||||||
rm -rf SDL2-2.0.7
|
rm -rf SDL2-2.0.7
|
||||||
eval 7z x -y SDL2-2.0.7.zip $STRIP
|
eval 7z x -y SDL2-2.0.7.zip $STRIP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export SDL2DIR="$(real_pwd)/SDL2-2.0.7"
|
export SDL2DIR="$(real_pwd)/SDL2-2.0.7"
|
||||||
|
|
||||||
add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll"
|
add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|
||||||
cd $DEPS_INSTALL/..
|
cd $DEPS_INSTALL/..
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Setting up OpenMW build..."
|
echo "Setting up OpenMW build..."
|
||||||
|
|
||||||
add_cmake_opts -DBUILD_BSATOOL=no \
|
add_cmake_opts -DBUILD_BSATOOL=no \
|
||||||
-DBUILD_ESMTOOL=no \
|
-DBUILD_ESMTOOL=no \
|
||||||
-DBUILD_MYGUI_PLUGIN=no \
|
-DBUILD_MYGUI_PLUGIN=no \
|
||||||
-DOPENMW_MP_BUILD=on
|
-DOPENMW_MP_BUILD=on
|
||||||
|
|
||||||
if [ ! -z $CI ]; then
|
if [ ! -z $CI ]; then
|
||||||
case $STEP in
|
case $STEP in
|
||||||
components )
|
components )
|
||||||
|
@ -710,7 +661,6 @@ if [ ! -z $CI ]; then
|
||||||
-DBUILD_OPENMW=no \
|
-DBUILD_OPENMW=no \
|
||||||
-DBUILD_WIZARD=no
|
-DBUILD_WIZARD=no
|
||||||
;;
|
;;
|
||||||
|
|
||||||
openmw )
|
openmw )
|
||||||
echo " Building subproject: OpenMW."
|
echo " Building subproject: OpenMW."
|
||||||
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
||||||
|
@ -719,7 +669,6 @@ if [ ! -z $CI ]; then
|
||||||
-DBUILD_OPENCS=no \
|
-DBUILD_OPENCS=no \
|
||||||
-DBUILD_WIZARD=no
|
-DBUILD_WIZARD=no
|
||||||
;;
|
;;
|
||||||
|
|
||||||
opencs )
|
opencs )
|
||||||
echo " Building subproject: OpenCS."
|
echo " Building subproject: OpenCS."
|
||||||
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
||||||
|
@ -728,7 +677,6 @@ if [ ! -z $CI ]; then
|
||||||
-DBUILD_OPENMW=no \
|
-DBUILD_OPENMW=no \
|
||||||
-DBUILD_WIZARD=no
|
-DBUILD_WIZARD=no
|
||||||
;;
|
;;
|
||||||
|
|
||||||
misc )
|
misc )
|
||||||
echo " Building subprojects: Misc."
|
echo " Building subprojects: Misc."
|
||||||
add_cmake_opts -DBUILD_OPENCS=no \
|
add_cmake_opts -DBUILD_OPENCS=no \
|
||||||
|
@ -736,7 +684,6 @@ if [ ! -z $CI ]; then
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# NOTE: Disable this when/if we want to run test cases
|
# NOTE: Disable this when/if we want to run test cases
|
||||||
#if [ -z $CI ]; then
|
#if [ -z $CI ]; then
|
||||||
echo "- Copying Runtime DLLs..."
|
echo "- Copying Runtime DLLs..."
|
||||||
|
@ -745,16 +692,13 @@ fi
|
||||||
TARGET="$(basename "$DLL")"
|
TARGET="$(basename "$DLL")"
|
||||||
if [[ "$DLL" == *":"* ]]; then
|
if [[ "$DLL" == *":"* ]]; then
|
||||||
IFS=':'; SPLIT=( ${DLL} ); unset IFS
|
IFS=':'; SPLIT=( ${DLL} ); unset IFS
|
||||||
|
|
||||||
DLL=${SPLIT[0]}
|
DLL=${SPLIT[0]}
|
||||||
TARGET=${SPLIT[1]}
|
TARGET=${SPLIT[1]}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo " ${TARGET}."
|
echo " ${TARGET}."
|
||||||
cp "$DLL" "$BUILD_CONFIG/$TARGET"
|
cp "$DLL" "$BUILD_CONFIG/$TARGET"
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "- OSG Plugin DLLs..."
|
echo "- OSG Plugin DLLs..."
|
||||||
mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1
|
mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1
|
||||||
for DLL in $OSG_PLUGINS; do
|
for DLL in $OSG_PLUGINS; do
|
||||||
|
@ -762,7 +706,6 @@ fi
|
||||||
cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1
|
cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "- Qt Platform DLLs..."
|
echo "- Qt Platform DLLs..."
|
||||||
mkdir -p ${BUILD_CONFIG}/platforms
|
mkdir -p ${BUILD_CONFIG}/platforms
|
||||||
for DLL in $QT_PLATFORMS; do
|
for DLL in $QT_PLATFORMS; do
|
||||||
|
@ -771,16 +714,13 @@ fi
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
#fi
|
#fi
|
||||||
|
|
||||||
if [ -z $VERBOSE ]; then
|
if [ -z $VERBOSE ]; then
|
||||||
printf -- "- Configuring... "
|
printf -- "- Configuring... "
|
||||||
else
|
else
|
||||||
echo "- cmake .. $CMAKE_OPTS"
|
echo "- cmake .. $CMAKE_OPTS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
run_cmd cmake .. $CMAKE_OPTS
|
run_cmd cmake .. $CMAKE_OPTS
|
||||||
RET=$?
|
RET=$?
|
||||||
|
|
||||||
if [ -z $VERBOSE ]; then
|
if [ -z $VERBOSE ]; then
|
||||||
if [ $RET -eq 0 ]; then
|
if [ $RET -eq 0 ]; then
|
||||||
echo Done.
|
echo Done.
|
||||||
|
@ -788,5 +728,4 @@ if [ -z $VERBOSE ]; then
|
||||||
echo Failed.
|
echo Failed.
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit $RET
|
exit $RET
|
||||||
|
|
|
@ -666,10 +666,10 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_OPENMW)
|
if (BUILD_OPENMW)
|
||||||
# Release builds use the debug console
|
# Release builds don't use the debug console
|
||||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||||
set_target_properties(tes3mp PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
set_target_properties(tes3mp PROPERTIES COMPILE_DEFINITIONS_RELEASE "_WINDOWS")
|
||||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Play a bit with the warning levels
|
# Play a bit with the warning levels
|
||||||
|
@ -680,7 +680,8 @@ if (WIN32)
|
||||||
# Warnings that aren't enabled normally and don't need to be enabled
|
# Warnings that aren't enabled normally and don't need to be enabled
|
||||||
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
||||||
# Not going to bother commenting them as they tend to warn on every standard library file
|
# Not going to bother commenting them as they tend to warn on every standard library file
|
||||||
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
|
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625
|
||||||
|
4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045
|
||||||
|
|
||||||
# Warnings that are thrown on standard libraries and not OpenMW
|
# Warnings that are thrown on standard libraries and not OpenMW
|
||||||
4347 # Non-template function with same name and parameter count as template function
|
4347 # Non-template function with same name and parameter count as template function
|
||||||
|
@ -701,6 +702,7 @@ if (WIN32)
|
||||||
|
|
||||||
# caused by MyGUI
|
# caused by MyGUI
|
||||||
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
|
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
|
||||||
|
4297 # function assumed not to throw an exception but does
|
||||||
|
|
||||||
# OpenMW specific warnings
|
# OpenMW specific warnings
|
||||||
4099 # Type mismatch, declared class or struct is defined with other type
|
4099 # Type mismatch, declared class or struct is defined with other type
|
||||||
|
|
|
@ -874,7 +874,6 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
|
||||||
{
|
{
|
||||||
std::vector<std::pair<std::time_t, boost::filesystem::path>> contentFiles;
|
std::vector<std::pair<std::time_t, boost::filesystem::path>> contentFiles;
|
||||||
std::string baseGameFile("Game Files:GameFile");
|
std::string baseGameFile("Game Files:GameFile");
|
||||||
std::string gameFile("");
|
|
||||||
std::time_t defaultTime = 0;
|
std::time_t defaultTime = 0;
|
||||||
ToUTF8::Utf8Encoder encoder(mEncoding);
|
ToUTF8::Utf8Encoder encoder(mEncoding);
|
||||||
|
|
||||||
|
@ -890,7 +889,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
|
||||||
multistrmap::const_iterator it = ini.begin();
|
multistrmap::const_iterator it = ini.begin();
|
||||||
for (int i=0; it != ini.end(); i++)
|
for (int i=0; it != ini.end(); i++)
|
||||||
{
|
{
|
||||||
gameFile = baseGameFile;
|
std::string gameFile = baseGameFile;
|
||||||
gameFile.append(std::to_string(i));
|
gameFile.append(std::to_string(i));
|
||||||
|
|
||||||
it = ini.find(gameFile);
|
it = ini.find(gameFile);
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
|
||||||
|
#include <components/crashcatcher/crashcatcher.hpp>
|
||||||
|
|
||||||
#include <components/fallback/validate.hpp>
|
#include <components/fallback/validate.hpp>
|
||||||
|
|
||||||
#include <components/nifosg/nifloader.hpp>
|
#include <components/nifosg/nifloader.hpp>
|
||||||
|
@ -18,12 +21,16 @@
|
||||||
|
|
||||||
using namespace Fallback;
|
using namespace Fallback;
|
||||||
|
|
||||||
CS::Editor::Editor ()
|
CS::Editor::Editor (int argc, char **argv)
|
||||||
: mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr),
|
: mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr),
|
||||||
mViewManager (mDocumentManager), mPid(""),
|
mViewManager (mDocumentManager), mPid(""),
|
||||||
mLock(), mMerge (mDocumentManager),
|
mLock(), mMerge (mDocumentManager),
|
||||||
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
||||||
{
|
{
|
||||||
|
// install the crash handler as soon as possible. note that the log path
|
||||||
|
// does not depend on config being read.
|
||||||
|
crashCatcherInstall(argc, argv, (mCfgMgr.getLogPath() / "openmw-cs-crash.log").string());
|
||||||
|
|
||||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||||
|
|
||||||
setupDataFiles (config.first);
|
setupDataFiles (config.first);
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace CS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Editor ();
|
Editor (int argc, char **argv);
|
||||||
~Editor ();
|
~Editor ();
|
||||||
|
|
||||||
bool makeIPCServer();
|
bool makeIPCServer();
|
||||||
|
|
|
@ -48,7 +48,7 @@ int main(int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// To allow background thread drawing in OSG
|
// To allow background thread drawing in OSG
|
||||||
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
|
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
||||||
|
|
||||||
CS::Editor editor;
|
CS::Editor editor(argc, argv);
|
||||||
|
|
||||||
if(!editor.makeIPCServer())
|
if(!editor.makeIPCServer())
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,8 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model,
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1)
|
Qt::CaseSensitivity caseSensitivity = mCase ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||||
|
while ((pos = text.indexOf (search, pos, caseSensitivity))!=-1)
|
||||||
{
|
{
|
||||||
std::ostringstream hint;
|
std::ostringstream hint;
|
||||||
hint
|
hint
|
||||||
|
@ -120,25 +121,26 @@ QString CSMTools::Search::flatten (const QString& text) const
|
||||||
return flat;
|
return flat;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMTools::Search::Search() : mType (Type_None), mValue (0), mIdColumn (0), mTypeColumn (0),
|
CSMTools::Search::Search() : mType (Type_None), mValue (0), mCase (false), mIdColumn (0), mTypeColumn (0),
|
||||||
mPaddingBefore (10), mPaddingAfter (10) {}
|
mPaddingBefore (10), mPaddingAfter (10) {}
|
||||||
|
|
||||||
CSMTools::Search::Search (Type type, const std::string& value)
|
CSMTools::Search::Search (Type type, bool caseSensitive, const std::string& value)
|
||||||
: mType (type), mText (value), mValue (0), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
|
: mType (type), mText (value), mValue (0), mCase (caseSensitive), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
|
||||||
{
|
{
|
||||||
if (type!=Type_Text && type!=Type_Id)
|
if (type!=Type_Text && type!=Type_Id)
|
||||||
throw std::logic_error ("Invalid search parameter (string)");
|
throw std::logic_error ("Invalid search parameter (string)");
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMTools::Search::Search (Type type, const QRegExp& value)
|
CSMTools::Search::Search (Type type, bool caseSensitive, const QRegExp& value)
|
||||||
: mType (type), mRegExp (value), mValue (0), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
|
: mType (type), mRegExp (value), mValue (0), mCase (caseSensitive), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
|
||||||
{
|
{
|
||||||
|
mRegExp.setCaseSensitivity(mCase ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||||
if (type!=Type_TextRegEx && type!=Type_IdRegEx)
|
if (type!=Type_TextRegEx && type!=Type_IdRegEx)
|
||||||
throw std::logic_error ("Invalid search parameter (RegExp)");
|
throw std::logic_error ("Invalid search parameter (RegExp)");
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMTools::Search::Search (Type type, int value)
|
CSMTools::Search::Search (Type type, bool caseSensitive, int value)
|
||||||
: mType (type), mValue (value), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
|
: mType (type), mValue (value), mCase (caseSensitive), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
|
||||||
{
|
{
|
||||||
if (type!=Type_RecordState)
|
if (type!=Type_RecordState)
|
||||||
throw std::logic_error ("invalid search parameter (int)");
|
throw std::logic_error ("invalid search parameter (int)");
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace CSMTools
|
||||||
std::string mText;
|
std::string mText;
|
||||||
QRegExp mRegExp;
|
QRegExp mRegExp;
|
||||||
int mValue;
|
int mValue;
|
||||||
|
bool mCase;
|
||||||
std::set<int> mColumns;
|
std::set<int> mColumns;
|
||||||
int mIdColumn;
|
int mIdColumn;
|
||||||
int mTypeColumn;
|
int mTypeColumn;
|
||||||
|
@ -67,11 +68,11 @@ namespace CSMTools
|
||||||
|
|
||||||
Search();
|
Search();
|
||||||
|
|
||||||
Search (Type type, const std::string& value);
|
Search (Type type, bool caseSensitive, const std::string& value);
|
||||||
|
|
||||||
Search (Type type, const QRegExp& value);
|
Search (Type type, bool caseSensitive, const QRegExp& value);
|
||||||
|
|
||||||
Search (Type type, int value);
|
Search (Type type, bool caseSensitive, int value);
|
||||||
|
|
||||||
// Configure search for the specified model.
|
// Configure search for the specified model.
|
||||||
void configure (const CSMWorld::IdTableBase *model);
|
void configure (const CSMWorld::IdTableBase *model);
|
||||||
|
|
|
@ -136,7 +136,7 @@ namespace CSMWorld
|
||||||
struct VarTypeColumn : public Column<ESXRecordT>
|
struct VarTypeColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
VarTypeColumn (ColumnBase::Display display)
|
VarTypeColumn (ColumnBase::Display display)
|
||||||
: Column<ESXRecordT> (Columns::ColumnId_ValueType, display)
|
: Column<ESXRecordT> (Columns::ColumnId_ValueType, display, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
|
@ -161,7 +161,7 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct VarValueColumn : public Column<ESXRecordT>
|
struct VarValueColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
VarValueColumn() : Column<ESXRecordT> (Columns::ColumnId_Value, ColumnBase::Display_Var) {}
|
VarValueColumn() : Column<ESXRecordT> (Columns::ColumnId_Value, ColumnBase::Display_Var, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh) {}
|
||||||
|
|
||||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,15 +84,28 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value
|
||||||
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
|
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
|
||||||
{
|
{
|
||||||
mIdCollection->setData (index.row(), index.column(), value);
|
mIdCollection->setData (index.row(), index.column(), value);
|
||||||
emit dataChanged(index, index);
|
|
||||||
|
|
||||||
// Modifying a value can also change the Modified status of a record.
|
|
||||||
int stateColumn = searchColumnIndex(Columns::ColumnId_Modification);
|
int stateColumn = searchColumnIndex(Columns::ColumnId_Modification);
|
||||||
if (stateColumn != -1)
|
if (stateColumn != -1)
|
||||||
{
|
{
|
||||||
QModelIndex stateIndex = this->index(index.row(), stateColumn);
|
if (index.column() == stateColumn)
|
||||||
emit dataChanged(stateIndex, stateIndex);
|
{
|
||||||
}
|
// modifying the state column can modify other values. we need to tell
|
||||||
|
// views that the whole row has changed.
|
||||||
|
|
||||||
|
emit dataChanged(this->index(index.row(), 0),
|
||||||
|
this->index(index.row(), columnCount(index.parent())));
|
||||||
|
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
|
// Modifying a value can also change the Modified status of a record.
|
||||||
|
QModelIndex stateIndex = this->index(index.row(), stateColumn);
|
||||||
|
emit dataChanged(stateIndex, stateIndex);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,4 +156,4 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -101,15 +101,39 @@ void CSVDoc::View::setupFileMenu()
|
||||||
file->addAction(exit);
|
file->addAction(exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void updateUndoRedoAction(QAction *action, const std::string &settingsKey)
|
||||||
|
{
|
||||||
|
QKeySequence seq;
|
||||||
|
CSMPrefs::State::get().getShortcutManager().getSequence(settingsKey, seq);
|
||||||
|
action->setShortcut(seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVDoc::View::undoActionChanged()
|
||||||
|
{
|
||||||
|
updateUndoRedoAction(mUndo, "document-edit-undo");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVDoc::View::redoActionChanged()
|
||||||
|
{
|
||||||
|
updateUndoRedoAction(mRedo, "document-edit-redo");
|
||||||
|
}
|
||||||
|
|
||||||
void CSVDoc::View::setupEditMenu()
|
void CSVDoc::View::setupEditMenu()
|
||||||
{
|
{
|
||||||
QMenu *edit = menuBar()->addMenu (tr ("Edit"));
|
QMenu *edit = menuBar()->addMenu (tr ("Edit"));
|
||||||
|
|
||||||
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo"));
|
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo"));
|
||||||
setupShortcut("document-edit-undo", mUndo);
|
setupShortcut("document-edit-undo", mUndo);
|
||||||
|
connect(mUndo, SIGNAL (changed ()), this, SLOT (undoActionChanged ()));
|
||||||
edit->addAction (mUndo);
|
edit->addAction (mUndo);
|
||||||
|
|
||||||
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("Redo"));
|
mRedo = mDocument->getUndoStack().createRedoAction (this, tr("Redo"));
|
||||||
|
connect(mRedo, SIGNAL (changed ()), this, SLOT (redoActionChanged ()));
|
||||||
setupShortcut("document-edit-redo", mRedo);
|
setupShortcut("document-edit-redo", mRedo);
|
||||||
edit->addAction (mRedo);
|
edit->addAction (mRedo);
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,10 @@ namespace CSVDoc
|
||||||
|
|
||||||
void settingChanged (const CSMPrefs::Setting *setting);
|
void settingChanged (const CSMPrefs::Setting *setting);
|
||||||
|
|
||||||
|
void undoActionChanged();
|
||||||
|
|
||||||
|
void redoActionChanged();
|
||||||
|
|
||||||
void newView();
|
void newView();
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
|
|
|
@ -372,10 +372,10 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
indices[j] -= VertexCount;
|
indices[j] -= VertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t offset = i * IndicesPerSegment;
|
size_t elementOffset = i * IndicesPerSegment;
|
||||||
for (size_t j = 0; j < IndicesPerSegment; ++j)
|
for (size_t j = 0; j < IndicesPerSegment; ++j)
|
||||||
{
|
{
|
||||||
primitives->setElement(offset++, indices[IndexPattern[j]]);
|
primitives->setElement(elementOffset++, indices[IndexPattern[j]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -651,7 +651,6 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
|
||||||
|
|
||||||
if (mDragMode == InteractionType_PrimaryEdit)
|
if (mDragMode == InteractionType_PrimaryEdit)
|
||||||
{
|
{
|
||||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
|
||||||
editMode.drag (event->pos(), mDragX, mDragY, mDragFactor); // note: terraintexturemode only uses pos
|
editMode.drag (event->pos(), mDragX, mDragY, mDragFactor); // note: terraintexturemode only uses pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ void CSVTools::SearchBox::updateSearchButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVTools::SearchBox::SearchBox (QWidget *parent)
|
CSVTools::SearchBox::SearchBox (QWidget *parent)
|
||||||
: QWidget (parent), mSearch ("Search"), mSearchEnabled (false), mReplace ("Replace All")
|
: QWidget (parent), mSearch (tr("Search")), mSearchEnabled (false), mReplace (tr("Replace All"))
|
||||||
{
|
{
|
||||||
mLayout = new QGridLayout (this);
|
mLayout = new QGridLayout (this);
|
||||||
|
|
||||||
|
@ -48,29 +48,26 @@ CSVTools::SearchBox::SearchBox (QWidget *parent)
|
||||||
++iter)
|
++iter)
|
||||||
mRecordState.addItem (QString::fromUtf8 (iter->c_str()));
|
mRecordState.addItem (QString::fromUtf8 (iter->c_str()));
|
||||||
|
|
||||||
mMode.addItem ("Text");
|
mMode.addItem (tr("Text"));
|
||||||
mMode.addItem ("Text (RegEx)");
|
mMode.addItem (tr("Text (RegEx)"));
|
||||||
mMode.addItem ("ID");
|
mMode.addItem (tr("ID"));
|
||||||
mMode.addItem ("ID (RegEx)");
|
mMode.addItem (tr("ID (RegEx)"));
|
||||||
mMode.addItem ("Record State");
|
mMode.addItem (tr("Record State"));
|
||||||
|
connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int)));
|
||||||
mLayout->addWidget (&mMode, 0, 0);
|
mLayout->addWidget (&mMode, 0, 0);
|
||||||
|
|
||||||
mLayout->addWidget (&mSearch, 0, 3);
|
connect (&mText, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
|
||||||
|
connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch()));
|
||||||
mInput.insertWidget (0, &mText);
|
mInput.insertWidget (0, &mText);
|
||||||
|
|
||||||
mInput.insertWidget (1, &mRecordState);
|
mInput.insertWidget (1, &mRecordState);
|
||||||
|
mLayout->addWidget (&mInput, 0, 1);
|
||||||
|
|
||||||
mLayout->addWidget (&mInput, 0, 1);
|
mCaseSensitive.setText (tr ("Case"));
|
||||||
|
mLayout->addWidget (&mCaseSensitive, 0, 2);
|
||||||
connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int)));
|
|
||||||
|
|
||||||
connect (&mText, SIGNAL (textChanged (const QString&)),
|
|
||||||
this, SLOT (textChanged (const QString&)));
|
|
||||||
|
|
||||||
connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool)));
|
connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool)));
|
||||||
|
mLayout->addWidget (&mSearch, 0, 3);
|
||||||
connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch()));
|
|
||||||
|
|
||||||
// replace panel
|
// replace panel
|
||||||
mReplaceInput.insertWidget (0, &mReplaceText);
|
mReplaceInput.insertWidget (0, &mReplaceText);
|
||||||
|
@ -102,23 +99,24 @@ void CSVTools::SearchBox::setSearchMode (bool enabled)
|
||||||
|
|
||||||
CSMTools::Search CSVTools::SearchBox::getSearch() const
|
CSMTools::Search CSVTools::SearchBox::getSearch() const
|
||||||
{
|
{
|
||||||
CSMTools::Search::Type type = static_cast<CSMTools::Search::Type> (mMode.currentIndex());
|
CSMTools::Search::Type type = static_cast<CSMTools::Search::Type> (mMode.currentIndex());
|
||||||
|
bool caseSensitive = mCaseSensitive.isChecked();
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case CSMTools::Search::Type_Text:
|
case CSMTools::Search::Type_Text:
|
||||||
case CSMTools::Search::Type_Id:
|
case CSMTools::Search::Type_Id:
|
||||||
|
|
||||||
return CSMTools::Search (type, std::string (mText.text().toUtf8().data()));
|
return CSMTools::Search (type, caseSensitive, std::string (mText.text().toUtf8().data()));
|
||||||
|
|
||||||
case CSMTools::Search::Type_TextRegEx:
|
case CSMTools::Search::Type_TextRegEx:
|
||||||
case CSMTools::Search::Type_IdRegEx:
|
case CSMTools::Search::Type_IdRegEx:
|
||||||
|
|
||||||
return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive));
|
return CSMTools::Search (type, caseSensitive, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive));
|
||||||
|
|
||||||
case CSMTools::Search::Type_RecordState:
|
case CSMTools::Search::Type_RecordState:
|
||||||
|
|
||||||
return CSMTools::Search (type, mRecordState.currentIndex());
|
return CSMTools::Search (type, caseSensitive, mRecordState.currentIndex());
|
||||||
|
|
||||||
case CSMTools::Search::Type_None:
|
case CSMTools::Search::Type_None:
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
@ -24,6 +25,7 @@ namespace CSVTools
|
||||||
QStackedWidget mInput;
|
QStackedWidget mInput;
|
||||||
QLineEdit mText;
|
QLineEdit mText;
|
||||||
QComboBox mRecordState;
|
QComboBox mRecordState;
|
||||||
|
QCheckBox mCaseSensitive;
|
||||||
QPushButton mSearch;
|
QPushButton mSearch;
|
||||||
QGridLayout *mLayout;
|
QGridLayout *mLayout;
|
||||||
QComboBox mMode;
|
QComboBox mMode;
|
||||||
|
|
|
@ -11,12 +11,10 @@ if (ANDROID)
|
||||||
set(GAME ${GAME} android_main.c)
|
set(GAME ${GAME} android_main.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT WIN32 AND NOT ANDROID)
|
|
||||||
set(GAME ${GAME} crashcatcher.cpp)
|
|
||||||
endif()
|
|
||||||
set(GAME_HEADER
|
set(GAME_HEADER
|
||||||
engine.hpp
|
engine.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
|
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
|
@ -83,9 +81,9 @@ add_openmw_dir (mwclass
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
|
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
|
||||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
||||||
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
aicast aiescort aiface aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||||
character actors objects aistate coordinateconverter trading aiface weaponpriority spellpriority
|
character actors objects aistate coordinateconverter trading weaponpriority spellpriority
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwstate
|
add_openmw_dir (mwstate
|
||||||
|
|
|
@ -757,28 +757,19 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
std::cout << "OSG version: " << osgGetVersion() << std::endl;
|
std::cout << "OSG version: " << osgGetVersion() << std::endl;
|
||||||
|
|
||||||
mViewer = new osgViewer::Viewer;
|
// Load settings
|
||||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
|
||||||
|
|
||||||
osg::ref_ptr<osgViewer::StatsHandler> statshandler = new osgViewer::StatsHandler;
|
|
||||||
statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3);
|
|
||||||
|
|
||||||
statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
|
||||||
"script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000);
|
|
||||||
statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
|
||||||
"mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000);
|
|
||||||
statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
|
||||||
"physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000);
|
|
||||||
|
|
||||||
mViewer->addEventHandler(statshandler);
|
|
||||||
|
|
||||||
mViewer->addEventHandler(new Resource::StatsHandler);
|
|
||||||
|
|
||||||
Settings::Manager settings;
|
Settings::Manager settings;
|
||||||
std::string settingspath;
|
std::string settingspath;
|
||||||
|
|
||||||
settingspath = loadSettings (settings);
|
settingspath = loadSettings (settings);
|
||||||
|
|
||||||
|
// Create encoder
|
||||||
|
ToUTF8::Utf8Encoder encoder (mEncoding);
|
||||||
|
mEncoder = &encoder;
|
||||||
|
|
||||||
|
// Setup viewer
|
||||||
|
mViewer = new osgViewer::Viewer;
|
||||||
|
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||||
|
|
||||||
mScreenCaptureOperation = new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(),
|
mScreenCaptureOperation = new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(),
|
||||||
Settings::Manager::getString("screenshot format", "General"));
|
Settings::Manager::getString("screenshot format", "General"));
|
||||||
|
|
||||||
|
@ -788,10 +779,6 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
|
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
|
||||||
|
|
||||||
// Create encoder
|
|
||||||
ToUTF8::Utf8Encoder encoder (mEncoding);
|
|
||||||
mEncoder = &encoder;
|
|
||||||
|
|
||||||
prepareEngine (settings);
|
prepareEngine (settings);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -814,6 +801,22 @@ void OMW::Engine::go()
|
||||||
End of tes3mp change (major)
|
End of tes3mp change (major)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Setup profiler
|
||||||
|
osg::ref_ptr<Resource::Profiler> statshandler = new Resource::Profiler;
|
||||||
|
|
||||||
|
statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
||||||
|
"script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000);
|
||||||
|
statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
||||||
|
"mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000);
|
||||||
|
statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
||||||
|
"physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000);
|
||||||
|
|
||||||
|
mViewer->addEventHandler(statshandler);
|
||||||
|
|
||||||
|
osg::ref_ptr<Resource::StatsHandler> resourceshandler = new Resource::StatsHandler;
|
||||||
|
mViewer->addEventHandler(resourceshandler);
|
||||||
|
|
||||||
|
// Start the game
|
||||||
if (!mSaveGameFile.empty())
|
if (!mSaveGameFile.empty())
|
||||||
{
|
{
|
||||||
mEnvironment.getStateManager()->loadGame(mSaveGameFile);
|
mEnvironment.getStateManager()->loadGame(mSaveGameFile);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <components/version/version.hpp>
|
#include <components/version/version.hpp>
|
||||||
|
#include <components/crashcatcher/crashcatcher.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/files/escape.hpp>
|
#include <components/files/escape.hpp>
|
||||||
#include <components/fallback/validate.hpp>
|
#include <components/fallback/validate.hpp>
|
||||||
|
@ -34,18 +35,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix))
|
|
||||||
#define USE_CRASH_CATCHER 1
|
|
||||||
#else
|
|
||||||
#define USE_CRASH_CATCHER 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USE_CRASH_CATCHER
|
|
||||||
#include <csignal>
|
|
||||||
extern int cc_install_handlers(int argc, char **argv, int num_signals, int *sigs, const char *logfile, int (*user_info)(char*, char*));
|
|
||||||
extern int is_debugger_attached(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
@ -419,18 +408,7 @@ int main(int argc, char**argv)
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
crashCatcherInstall(argc, argv, (cfgMgr.getLogPath() / "crash.log").string());
|
||||||
#if USE_CRASH_CATCHER
|
|
||||||
// Unix crash catcher
|
|
||||||
if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_attached())
|
|
||||||
{
|
|
||||||
int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT };
|
|
||||||
cc_install_handlers(argc, argv, 5, s, (cfgMgr.getLogPath() / "crash.log").string().c_str(), NULL);
|
|
||||||
std::cout << "Installing crash catcher" << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cout << "Running in a debugger, not installing crash catcher" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
|
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
|
||||||
|
|
|
@ -235,9 +235,12 @@ namespace MWBase
|
||||||
/// Resurrects the player if necessary
|
/// Resurrects the player if necessary
|
||||||
virtual void keepPlayerAlive() = 0;
|
virtual void keepPlayerAlive() = 0;
|
||||||
|
|
||||||
|
virtual bool isCastingSpell (const MWWorld::Ptr& ptr) const = 0;
|
||||||
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
||||||
virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0;
|
||||||
|
|
||||||
|
virtual void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell) = 0;
|
||||||
|
|
||||||
/// Check if the target actor was detected by an observer
|
/// Check if the target actor was detected by an observer
|
||||||
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0;
|
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0;
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace MWBase
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Make the player use an item, while updating GUI state accordingly
|
/// Make the player use an item, while updating GUI state accordingly
|
||||||
virtual void useItem(const MWWorld::Ptr& item) = 0;
|
virtual void useItem(const MWWorld::Ptr& item, bool force=false) = 0;
|
||||||
|
|
||||||
virtual void updateSpellWindow() = 0;
|
virtual void updateSpellWindow() = 0;
|
||||||
|
|
||||||
|
|
|
@ -583,7 +583,7 @@ namespace MWBase
|
||||||
*/
|
*/
|
||||||
virtual bool startSpellCast (const MWWorld::Ptr& actor) = 0;
|
virtual bool startSpellCast (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor, bool manualSpell=false) = 0;
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0;
|
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0;
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
|
|
|
@ -157,10 +157,9 @@ namespace MWClass
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MWWorld::Action> Apparatus::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
std::shared_ptr<MWWorld::Action> Apparatus::use (const MWWorld::Ptr& ptr) const
|
|
||||||
{
|
{
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionAlchemy());
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionAlchemy(force));
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr Apparatus::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const
|
MWWorld::Ptr Apparatus::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const
|
||||||
|
|
|
@ -50,8 +50,7 @@ namespace MWClass
|
||||||
virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const;
|
virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const;
|
||||||
///< Return name of inventory icon.
|
///< Return name of inventory icon.
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -387,9 +387,9 @@ namespace MWClass
|
||||||
return std::make_pair(1,"");
|
return std::make_pair(1,"");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Armor::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Armor::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr, force));
|
||||||
|
|
||||||
action->setSound(getUpSoundId(ptr));
|
action->setSound(getUpSoundId(ptr));
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,7 @@ namespace MWClass
|
||||||
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n
|
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n
|
||||||
/// Second item in the pair specifies the error message
|
/// Second item in the pair specifies the error message
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -195,7 +195,7 @@ namespace MWClass
|
||||||
return record->mId;
|
return record->mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Book::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Book::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionRead(ptr));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionRead(ptr));
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace MWClass
|
||||||
virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
|
virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
|
||||||
///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it.
|
///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it.
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr) const;
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -276,9 +276,9 @@ namespace MWClass
|
||||||
return std::make_pair (1, "");
|
return std::make_pair (1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Clothing::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Clothing::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr, force));
|
||||||
|
|
||||||
action->setSound(getUpSoundId(ptr));
|
action->setSound(getUpSoundId(ptr));
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,7 @@ namespace MWClass
|
||||||
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
|
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
|
||||||
/// Second item in the pair specifies the error message
|
/// Second item in the pair specifies the error message
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Ingredient::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Ingredient::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action (new MWWorld::ActionEat (ptr));
|
std::shared_ptr<MWWorld::Action> action (new MWWorld::ActionEat (ptr));
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ namespace MWClass
|
||||||
virtual int getValue (const MWWorld::ConstPtr& ptr) const;
|
virtual int getValue (const MWWorld::ConstPtr& ptr) const;
|
||||||
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
|
@ -186,9 +186,9 @@ namespace MWClass
|
||||||
return Class::showsInInventory(ptr);
|
return Class::showsInInventory(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Light::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Light::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr, force));
|
||||||
|
|
||||||
action->setSound(getUpSoundId(ptr));
|
action->setSound(getUpSoundId(ptr));
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,7 @@ namespace MWClass
|
||||||
virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const;
|
virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const;
|
||||||
///< Return name of inventory icon.
|
///< Return name of inventory icon.
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const;
|
virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const;
|
||||||
|
|
|
@ -140,9 +140,9 @@ namespace MWClass
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Lockpick::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Lockpick::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr, force));
|
||||||
|
|
||||||
action->setSound(getUpSoundId(ptr));
|
action->setSound(getUpSoundId(ptr));
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const;
|
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -259,7 +259,7 @@ namespace MWClass
|
||||||
return newPtr;
|
return newPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Miscellaneous::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Miscellaneous::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
if (ptr.getCellRef().getSoul().empty() || !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(ptr.getCellRef().getSoul()))
|
if (ptr.getCellRef().getSoul().empty() || !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(ptr.getCellRef().getSoul()))
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::NullAction());
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::NullAction());
|
||||||
|
|
|
@ -49,8 +49,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual float getWeight (const MWWorld::ConstPtr& ptr) const;
|
virtual float getWeight (const MWWorld::ConstPtr& ptr) const;
|
||||||
|
|
|
@ -172,7 +172,7 @@ namespace MWClass
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Potion::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Potion::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Potion> *ref =
|
MWWorld::LiveCellRef<ESM::Potion> *ref =
|
||||||
ptr.get<ESM::Potion>();
|
ptr.get<ESM::Potion>();
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace MWClass
|
||||||
virtual int getValue (const MWWorld::ConstPtr& ptr) const;
|
virtual int getValue (const MWWorld::ConstPtr& ptr) const;
|
||||||
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr) const;
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
|
@ -140,9 +140,9 @@ namespace MWClass
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Probe::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Probe::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr, force));
|
||||||
|
|
||||||
action->setSound(getUpSoundId(ptr));
|
action->setSound(getUpSoundId(ptr));
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const;
|
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -182,9 +182,9 @@ namespace MWClass
|
||||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Repair::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Repair::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionRepair(ptr));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionRepair(ptr, force));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Repair::canSell (const MWWorld::ConstPtr& item, int npcServices) const
|
bool Repair::canSell (const MWWorld::ConstPtr& item, int npcServices) const
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false)
|
||||||
const;
|
const;
|
||||||
///< Generate action for using via inventory menu (default implementation: return a
|
///< Generate action for using via inventory menu (default implementation: return a
|
||||||
/// null action).
|
/// null action).
|
||||||
|
|
|
@ -435,9 +435,9 @@ namespace MWClass
|
||||||
return std::make_pair(1, "");
|
return std::make_pair(1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionEquip(ptr, force));
|
||||||
|
|
||||||
action->setSound(getUpSoundId(ptr));
|
action->setSound(getUpSoundId(ptr));
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,7 @@ namespace MWClass
|
||||||
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
|
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
|
||||||
/// Second item in the pair specifies the error message
|
/// Second item in the pair specifies the error message
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
|
virtual std::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr, bool force=false) const;
|
||||||
const;
|
|
||||||
///< Generate action for using via inventory menu
|
///< Generate action for using via inventory menu
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
|
@ -629,6 +629,9 @@ namespace MWGui
|
||||||
|
|
||||||
void DialogueWindow::onTopicActivated(const std::string &topicId)
|
void DialogueWindow::onTopicActivated(const std::string &topicId)
|
||||||
{
|
{
|
||||||
|
if (mGoodbye)
|
||||||
|
return;
|
||||||
|
|
||||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get());
|
MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get());
|
||||||
updateTopics();
|
updateTopics();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/action.hpp"
|
#include "../mwworld/actionequip.hpp"
|
||||||
#include "../mwscript/interpretercontext.hpp"
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
@ -488,7 +488,7 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory);
|
MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryWindow::useItem(const MWWorld::Ptr &ptr)
|
void InventoryWindow::useItem(const MWWorld::Ptr &ptr, bool force)
|
||||||
{
|
{
|
||||||
const std::string& script = ptr.getClass().getScript(ptr);
|
const std::string& script = ptr.getClass().getScript(ptr);
|
||||||
|
|
||||||
|
@ -497,13 +497,24 @@ namespace MWGui
|
||||||
// early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case
|
// 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())
|
if (!ptr.getClass().getEquipmentSlots(ptr).first.empty())
|
||||||
{
|
{
|
||||||
std::pair<int, std::string> canEquip = ptr.getClass().canBeEquipped(ptr, player);
|
if (ptr.getClass().hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0)
|
||||||
if (canEquip.first == 0)
|
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second);
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}");
|
||||||
updateItemView();
|
updateItemView();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!force)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
@ -526,9 +537,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0)
|
if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0)
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr);
|
std::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr, force);
|
||||||
|
action->execute(player);
|
||||||
action->execute (player);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mSkippedToEquip = ptr;
|
mSkippedToEquip = ptr;
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace MWGui
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void useItem(const MWWorld::Ptr& ptr);
|
void useItem(const MWWorld::Ptr& ptr, bool force=false);
|
||||||
|
|
||||||
void setGuiMode(GuiMode mode);
|
void setGuiMode(GuiMode mode);
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace MWGui
|
||||||
|
|
||||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
{
|
{
|
||||||
int value = npcStats.getSkill (i).getBase ();
|
int value = npcStats.getSkill (i).getModified ();
|
||||||
|
|
||||||
skills.push_back(std::make_pair(i, value));
|
skills.push_back(std::make_pair(i, value));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1423,10 +1423,10 @@ namespace MWGui
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void WindowManager::useItem(const MWWorld::Ptr &item)
|
void WindowManager::useItem(const MWWorld::Ptr &item, bool bypassBeastRestrictions)
|
||||||
{
|
{
|
||||||
if (mInventoryWindow)
|
if (mInventoryWindow)
|
||||||
mInventoryWindow->useItem(item);
|
mInventoryWindow->useItem(item, bypassBeastRestrictions);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowManager::isAllowed (GuiWindow wnd) const
|
bool WindowManager::isAllowed (GuiWindow wnd) const
|
||||||
|
|
|
@ -196,7 +196,7 @@ namespace MWGui
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Make the player use an item, while updating GUI state accordingly
|
/// Make the player use an item, while updating GUI state accordingly
|
||||||
virtual void useItem(const MWWorld::Ptr& item);
|
virtual void useItem(const MWWorld::Ptr& item, bool bypassBeastRestrictions=false);
|
||||||
|
|
||||||
virtual void updateSpellWindow();
|
virtual void updateSpellWindow();
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
|
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
|
||||||
{
|
{
|
||||||
mCharacterController.reset(new CharacterController(ptr, animation));
|
mCharacterController.reset(new CharacterController(ptr, animation));
|
||||||
|
@ -19,10 +18,4 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
return mCharacterController.get();
|
return mCharacterController.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
AiState& Actor::getAiState()
|
|
||||||
{
|
|
||||||
return mAiState;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "aistate.hpp"
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
class Animation;
|
class Animation;
|
||||||
|
@ -29,12 +27,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
CharacterController* getCharacterController();
|
CharacterController* getCharacterController();
|
||||||
|
|
||||||
AiState& getAiState();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<CharacterController> mCharacterController;
|
std::unique_ptr<CharacterController> mCharacterController;
|
||||||
|
|
||||||
AiState mAiState;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1253,6 +1253,13 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actors::castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell)
|
||||||
|
{
|
||||||
|
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||||
|
if(iter != mActors.end())
|
||||||
|
iter->second->getCharacterController()->castSpell(spellId, manualSpell);
|
||||||
|
}
|
||||||
|
|
||||||
bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
|
bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
|
||||||
{
|
{
|
||||||
if (!actor.getClass().isActor())
|
if (!actor.getClass().isActor())
|
||||||
|
@ -1523,7 +1530,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||||
if (isConscious(iter->first))
|
if (isConscious(iter->first))
|
||||||
stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), iter->second->getAiState(), duration);
|
stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -2195,6 +2202,15 @@ namespace MWMechanics
|
||||||
return it->second->getCharacterController()->isReadyToBlock();
|
return it->second->getCharacterController()->isReadyToBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Actors::isCastingSpell(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||||
|
if (it == mActors.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return it->second->getCharacterController()->isCastingSpell();
|
||||||
|
}
|
||||||
|
|
||||||
bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
|
bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||||
|
@ -2220,7 +2236,7 @@ namespace MWMechanics
|
||||||
|| ptr.getClass().getCreatureStats(ptr).isParalyzed())
|
|| ptr.getClass().getCreatureStats(ptr).isParalyzed())
|
||||||
continue;
|
continue;
|
||||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||||
seq.fastForward(ptr, it->second->getAiState());
|
seq.fastForward(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,8 @@ namespace MWMechanics
|
||||||
///
|
///
|
||||||
/// \note Ignored, if \a ptr is not a registered actor.
|
/// \note Ignored, if \a ptr is not a registered actor.
|
||||||
|
|
||||||
|
void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell=false);
|
||||||
|
|
||||||
void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr);
|
void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr);
|
||||||
///< Updates an actor with a new Ptr
|
///< Updates an actor with a new Ptr
|
||||||
|
|
||||||
|
@ -171,6 +173,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void clear(); // Clear death counter
|
void clear(); // Clear death counter
|
||||||
|
|
||||||
|
bool isCastingSpell(const MWWorld::Ptr& ptr) const;
|
||||||
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
||||||
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
|
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
|
|
84
apps/openmw/mwmechanics/aicast.cpp
Normal file
84
apps/openmw/mwmechanics/aicast.cpp
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#include "aicast.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "aicombataction.hpp"
|
||||||
|
#include "creaturestats.hpp"
|
||||||
|
#include "spellcasting.hpp"
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
|
MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell)
|
||||||
|
: mTargetId(targetId), mSpellId(spellId), mCasting(false), mManual(manualSpell), mDistance(0)
|
||||||
|
{
|
||||||
|
ActionSpell action = ActionSpell(spellId);
|
||||||
|
bool isRanged;
|
||||||
|
mDistance = action.getCombatRange(isRanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiPackage *MWMechanics::AiCast::clone() const
|
||||||
|
{
|
||||||
|
return new AiCast(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& characterController, MWMechanics::AiState& state, float duration)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr target;
|
||||||
|
if (actor.getCellRef().getRefId() == mTargetId)
|
||||||
|
{
|
||||||
|
// If the target has the same ID as caster, consider that actor casts spell with Self range.
|
||||||
|
target = actor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target = getTarget();
|
||||||
|
if (!target)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!mManual && !pathTo(actor, target.getRefData().getPosition().pos, duration, mDistance))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec3f dir = target.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3();
|
||||||
|
bool turned = smoothTurn(actor, getZAngleToDir(dir), 2, osg::DegreesToRadians(3.f));
|
||||||
|
turned &= smoothTurn(actor, getXAngleToDir(dir), 0, osg::DegreesToRadians(3.f));
|
||||||
|
|
||||||
|
if (!turned)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the actor is already casting another spell
|
||||||
|
bool isCasting = MWBase::Environment::get().getMechanicsManager()->isCastingSpell(actor);
|
||||||
|
if (isCasting && !mCasting)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mCasting)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->castSpell(actor, mSpellId, mManual);
|
||||||
|
mCasting = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish package, if actor finished spellcasting
|
||||||
|
return !isCasting;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr MWMechanics::AiCast::getTarget() const
|
||||||
|
{
|
||||||
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetId, false);
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MWMechanics::AiCast::getTypeId() const
|
||||||
|
{
|
||||||
|
return AiPackage::TypeIdCast;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int MWMechanics::AiCast::getPriority() const
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
37
apps/openmw/mwmechanics/aicast.hpp
Normal file
37
apps/openmw/mwmechanics/aicast.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef GAME_MWMECHANICS_AICAST_H
|
||||||
|
#define GAME_MWMECHANICS_AICAST_H
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
/// AiPackage which makes an actor to cast given spell.
|
||||||
|
class AiCast : public AiPackage {
|
||||||
|
public:
|
||||||
|
AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false);
|
||||||
|
|
||||||
|
virtual AiPackage *clone() const;
|
||||||
|
|
||||||
|
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||||
|
|
||||||
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
virtual MWWorld::Ptr getTarget() const;
|
||||||
|
|
||||||
|
virtual unsigned int getPriority() const;
|
||||||
|
|
||||||
|
virtual bool canCancel() const { return false; }
|
||||||
|
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mTargetId;
|
||||||
|
std::string mSpellId;
|
||||||
|
bool mCasting;
|
||||||
|
bool mManual;
|
||||||
|
float mDistance;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -48,74 +48,6 @@ namespace
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
/// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive.
|
|
||||||
struct AiCombatStorage : AiTemporaryBase
|
|
||||||
{
|
|
||||||
float mAttackCooldown;
|
|
||||||
float mTimerReact;
|
|
||||||
float mTimerCombatMove;
|
|
||||||
bool mReadyToAttack;
|
|
||||||
bool mAttack;
|
|
||||||
float mAttackRange;
|
|
||||||
bool mCombatMove;
|
|
||||||
osg::Vec3f mLastTargetPos;
|
|
||||||
const MWWorld::CellStore* mCell;
|
|
||||||
std::shared_ptr<Action> mCurrentAction;
|
|
||||||
float mActionCooldown;
|
|
||||||
float mStrength;
|
|
||||||
bool mForceNoShortcut;
|
|
||||||
ESM::Position mShortcutFailPos;
|
|
||||||
MWMechanics::Movement mMovement;
|
|
||||||
|
|
||||||
enum FleeState
|
|
||||||
{
|
|
||||||
FleeState_None,
|
|
||||||
FleeState_Idle,
|
|
||||||
FleeState_RunBlindly,
|
|
||||||
FleeState_RunToDestination
|
|
||||||
};
|
|
||||||
FleeState mFleeState;
|
|
||||||
bool mLOS;
|
|
||||||
float mUpdateLOSTimer;
|
|
||||||
float mFleeBlindRunTimer;
|
|
||||||
ESM::Pathgrid::Point mFleeDest;
|
|
||||||
|
|
||||||
AiCombatStorage():
|
|
||||||
mAttackCooldown(0.0f),
|
|
||||||
mTimerReact(AI_REACTION_TIME),
|
|
||||||
mTimerCombatMove(0.0f),
|
|
||||||
mReadyToAttack(false),
|
|
||||||
mAttack(false),
|
|
||||||
mAttackRange(0.0f),
|
|
||||||
mCombatMove(false),
|
|
||||||
mLastTargetPos(0,0,0),
|
|
||||||
mCell(NULL),
|
|
||||||
mCurrentAction(),
|
|
||||||
mActionCooldown(0.0f),
|
|
||||||
mStrength(),
|
|
||||||
mForceNoShortcut(false),
|
|
||||||
mShortcutFailPos(),
|
|
||||||
mMovement(),
|
|
||||||
mFleeState(FleeState_None),
|
|
||||||
mLOS(false),
|
|
||||||
mUpdateLOSTimer(0.0f),
|
|
||||||
mFleeBlindRunTimer(0.0f)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
|
||||||
void updateCombatMove(float duration);
|
|
||||||
void stopCombatMove();
|
|
||||||
void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController,
|
|
||||||
const ESM::Weapon* weapon, bool distantCombat);
|
|
||||||
void updateAttack(CharacterController& characterController);
|
|
||||||
void stopAttack();
|
|
||||||
|
|
||||||
void startFleeing();
|
|
||||||
void stopFleeing();
|
|
||||||
bool isFleeing();
|
|
||||||
};
|
|
||||||
|
|
||||||
AiCombat::AiCombat(const MWWorld::Ptr& actor)
|
AiCombat::AiCombat(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||||
|
@ -128,7 +60,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiCombat::init()
|
void AiCombat::init()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -23,7 +23,72 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
class Action;
|
class Action;
|
||||||
|
|
||||||
struct AiCombatStorage;
|
/// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive.
|
||||||
|
struct AiCombatStorage : AiTemporaryBase
|
||||||
|
{
|
||||||
|
float mAttackCooldown;
|
||||||
|
float mTimerReact;
|
||||||
|
float mTimerCombatMove;
|
||||||
|
bool mReadyToAttack;
|
||||||
|
bool mAttack;
|
||||||
|
float mAttackRange;
|
||||||
|
bool mCombatMove;
|
||||||
|
osg::Vec3f mLastTargetPos;
|
||||||
|
const MWWorld::CellStore* mCell;
|
||||||
|
std::shared_ptr<Action> mCurrentAction;
|
||||||
|
float mActionCooldown;
|
||||||
|
float mStrength;
|
||||||
|
bool mForceNoShortcut;
|
||||||
|
ESM::Position mShortcutFailPos;
|
||||||
|
MWMechanics::Movement mMovement;
|
||||||
|
|
||||||
|
enum FleeState
|
||||||
|
{
|
||||||
|
FleeState_None,
|
||||||
|
FleeState_Idle,
|
||||||
|
FleeState_RunBlindly,
|
||||||
|
FleeState_RunToDestination
|
||||||
|
};
|
||||||
|
FleeState mFleeState;
|
||||||
|
bool mLOS;
|
||||||
|
float mUpdateLOSTimer;
|
||||||
|
float mFleeBlindRunTimer;
|
||||||
|
ESM::Pathgrid::Point mFleeDest;
|
||||||
|
|
||||||
|
AiCombatStorage():
|
||||||
|
mAttackCooldown(0.0f),
|
||||||
|
mTimerReact(AI_REACTION_TIME),
|
||||||
|
mTimerCombatMove(0.0f),
|
||||||
|
mReadyToAttack(false),
|
||||||
|
mAttack(false),
|
||||||
|
mAttackRange(0.0f),
|
||||||
|
mCombatMove(false),
|
||||||
|
mLastTargetPos(0,0,0),
|
||||||
|
mCell(NULL),
|
||||||
|
mCurrentAction(),
|
||||||
|
mActionCooldown(0.0f),
|
||||||
|
mStrength(),
|
||||||
|
mForceNoShortcut(false),
|
||||||
|
mShortcutFailPos(),
|
||||||
|
mMovement(),
|
||||||
|
mFleeState(FleeState_None),
|
||||||
|
mLOS(false),
|
||||||
|
mUpdateLOSTimer(0.0f),
|
||||||
|
mFleeBlindRunTimer(0.0f)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
||||||
|
void updateCombatMove(float duration);
|
||||||
|
void stopCombatMove();
|
||||||
|
void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController,
|
||||||
|
const ESM::Weapon* weapon, bool distantCombat);
|
||||||
|
void updateAttack(CharacterController& characterController);
|
||||||
|
void stopAttack();
|
||||||
|
|
||||||
|
void startFleeing();
|
||||||
|
void stopFleeing();
|
||||||
|
bool isFleeing();
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Causes the actor to fight another actor
|
/// \brief Causes the actor to fight another actor
|
||||||
class AiCombat : public AiPackage
|
class AiCombat : public AiPackage
|
||||||
|
|
|
@ -17,22 +17,6 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
struct AiFollowStorage : AiTemporaryBase
|
|
||||||
{
|
|
||||||
float mTimer;
|
|
||||||
bool mMoving;
|
|
||||||
float mTargetAngleRadians;
|
|
||||||
bool mTurnActorToTarget;
|
|
||||||
|
|
||||||
AiFollowStorage() :
|
|
||||||
mTimer(0.f),
|
|
||||||
mMoving(false),
|
|
||||||
mTargetAngleRadians(0.f),
|
|
||||||
mTurnActorToTarget(false)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
int AiFollow::mFollowIndexCounter = 0;
|
int AiFollow::mFollowIndexCounter = 0;
|
||||||
|
|
||||||
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
||||||
|
|
|
@ -19,6 +19,21 @@ namespace AiSequence
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
struct AiFollowStorage : AiTemporaryBase
|
||||||
|
{
|
||||||
|
float mTimer;
|
||||||
|
bool mMoving;
|
||||||
|
float mTargetAngleRadians;
|
||||||
|
bool mTurnActorToTarget;
|
||||||
|
|
||||||
|
AiFollowStorage() :
|
||||||
|
mTimer(0.f),
|
||||||
|
mMoving(false),
|
||||||
|
mTargetAngleRadians(0.f),
|
||||||
|
mTurnActorToTarget(false)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief AiPackage for an actor to follow another actor/the PC
|
/// \brief AiPackage for an actor to follow another actor/the PC
|
||||||
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
||||||
**/
|
**/
|
||||||
|
|
|
@ -49,7 +49,8 @@ namespace MWMechanics
|
||||||
TypeIdAvoidDoor = 7,
|
TypeIdAvoidDoor = 7,
|
||||||
TypeIdFace = 8,
|
TypeIdFace = 8,
|
||||||
TypeIdBreathe = 9,
|
TypeIdBreathe = 9,
|
||||||
TypeIdInternalTravel = 10
|
TypeIdInternalTravel = 10,
|
||||||
|
TypeIdCast = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
///Default constructor
|
///Default constructor
|
||||||
|
|
|
@ -180,15 +180,11 @@ bool AiSequence::isPackageDone() const
|
||||||
|
|
||||||
bool isActualAiPackage(int packageTypeId)
|
bool isActualAiPackage(int packageTypeId)
|
||||||
{
|
{
|
||||||
return (packageTypeId != AiPackage::TypeIdCombat
|
return (packageTypeId >= AiPackage::TypeIdWander &&
|
||||||
&& packageTypeId != AiPackage::TypeIdPursue
|
packageTypeId <= AiPackage::TypeIdActivate);
|
||||||
&& packageTypeId != AiPackage::TypeIdAvoidDoor
|
|
||||||
&& packageTypeId != AiPackage::TypeIdFace
|
|
||||||
&& packageTypeId != AiPackage::TypeIdBreathe
|
|
||||||
&& packageTypeId != AiPackage::TypeIdInternalTravel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration)
|
||||||
{
|
{
|
||||||
if(actor != getPlayer())
|
if(actor != getPlayer())
|
||||||
{
|
{
|
||||||
|
@ -262,7 +258,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (package->execute (actor,characterController,state,duration))
|
if (package->execute (actor, characterController, mAiState, duration))
|
||||||
{
|
{
|
||||||
// Put repeating noncombat AI packages on the end of the stack so they can be used again
|
// Put repeating noncombat AI packages on the end of the stack so they can be used again
|
||||||
if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat()))
|
if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat()))
|
||||||
|
@ -308,7 +304,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
||||||
if (isActualAiPackage(package.getTypeId()))
|
if (isActualAiPackage(package.getTypeId()))
|
||||||
stopCombat();
|
stopCombat();
|
||||||
|
|
||||||
// We should return a wandering actor back after combat or pursuit.
|
// We should return a wandering actor back after combat, casting or pursuit.
|
||||||
// The same thing for actors without AI packages.
|
// The same thing for actors without AI packages.
|
||||||
// Also there is no point to stack return packages.
|
// Also there is no point to stack return packages.
|
||||||
int currentTypeId = getTypeId();
|
int currentTypeId = getTypeId();
|
||||||
|
@ -316,7 +312,8 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
||||||
if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander
|
if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander
|
||||||
&& !hasPackage(MWMechanics::AiPackage::TypeIdInternalTravel)
|
&& !hasPackage(MWMechanics::AiPackage::TypeIdInternalTravel)
|
||||||
&& (newTypeId <= MWMechanics::AiPackage::TypeIdCombat
|
&& (newTypeId <= MWMechanics::AiPackage::TypeIdCombat
|
||||||
|| newTypeId == MWMechanics::AiPackage::TypeIdPursue))
|
|| newTypeId == MWMechanics::AiPackage::TypeIdPursue
|
||||||
|
|| newTypeId == MWMechanics::AiPackage::TypeIdCast))
|
||||||
{
|
{
|
||||||
osg::Vec3f dest;
|
osg::Vec3f dest;
|
||||||
if (currentTypeId == MWMechanics::AiPackage::TypeIdWander)
|
if (currentTypeId == MWMechanics::AiPackage::TypeIdWander)
|
||||||
|
@ -352,6 +349,13 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
||||||
// insert new package in correct place depending on priority
|
// insert new package in correct place depending on priority
|
||||||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
|
// We should keep current AiCast package, if we try to add a new one.
|
||||||
|
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCast &&
|
||||||
|
package.getTypeId() == MWMechanics::AiPackage::TypeIdCast)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if((*it)->getPriority() <= package.getPriority())
|
if((*it)->getPriority() <= package.getPriority())
|
||||||
{
|
{
|
||||||
mPackages.insert(it,package.clone());
|
mPackages.insert(it,package.clone());
|
||||||
|
@ -360,6 +364,14 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
mPackages.push_back (package.clone());
|
mPackages.push_back (package.clone());
|
||||||
|
|
||||||
|
// Make sure that temporary storage is empty
|
||||||
|
if (cancelOther)
|
||||||
|
{
|
||||||
|
mAiState.moveIn(new AiCombatStorage());
|
||||||
|
mAiState.moveIn(new AiFollowStorage());
|
||||||
|
mAiState.moveIn(new AiWanderStorage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AiPackage* MWMechanics::AiSequence::getActivePackage()
|
AiPackage* MWMechanics::AiSequence::getActivePackage()
|
||||||
|
@ -494,12 +506,12 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
mLastAiPackage = sequence.mLastAiPackage;
|
mLastAiPackage = sequence.mLastAiPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
void AiSequence::fastForward(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
if (!mPackages.empty())
|
if (!mPackages.empty())
|
||||||
{
|
{
|
||||||
MWMechanics::AiPackage* package = mPackages.front();
|
MWMechanics::AiPackage* package = mPackages.front();
|
||||||
package->fastForward(actor, state);
|
package->fastForward(actor, mAiState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#include "aistate.hpp"
|
||||||
|
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -47,6 +49,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
/// The type of AI package that ran last
|
/// The type of AI package that ran last
|
||||||
int mLastAiPackage;
|
int mLastAiPackage;
|
||||||
|
AiState mAiState;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
///Default constructor
|
///Default constructor
|
||||||
|
@ -104,10 +107,10 @@ namespace MWMechanics
|
||||||
void stopPursuit();
|
void stopPursuit();
|
||||||
|
|
||||||
/// Execute current package, switching if needed.
|
/// Execute current package, switching if needed.
|
||||||
void execute (const MWWorld::Ptr& actor, CharacterController& characterController, MWMechanics::AiState& state, float duration);
|
void execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration);
|
||||||
|
|
||||||
/// Simulate the passing of time using the currently active AI package
|
/// Simulate the passing of time using the currently active AI package
|
||||||
void fastForward(const MWWorld::Ptr &actor, AiState &state);
|
void fastForward(const MWWorld::Ptr &actor);
|
||||||
|
|
||||||
/// Remove all packages.
|
/// Remove all packages.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -51,67 +51,6 @@ namespace MWMechanics
|
||||||
std::string("idle9"),
|
std::string("idle9"),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
|
||||||
struct AiWanderStorage : AiTemporaryBase
|
|
||||||
{
|
|
||||||
// the z rotation angle to reach
|
|
||||||
// when mTurnActorGivingGreetingToFacePlayer is true
|
|
||||||
float mTargetAngleRadians;
|
|
||||||
bool mTurnActorGivingGreetingToFacePlayer;
|
|
||||||
float mReaction; // update some actions infrequently
|
|
||||||
|
|
||||||
AiWander::GreetingState mSaidGreeting;
|
|
||||||
int mGreetingTimer;
|
|
||||||
|
|
||||||
const MWWorld::CellStore* mCell; // for detecting cell change
|
|
||||||
|
|
||||||
// AiWander states
|
|
||||||
AiWander::WanderState mState;
|
|
||||||
|
|
||||||
bool mIsWanderingManually;
|
|
||||||
bool mCanWanderAlongPathGrid;
|
|
||||||
|
|
||||||
unsigned short mIdleAnimation;
|
|
||||||
std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
|
|
||||||
|
|
||||||
// do we need to calculate allowed nodes based on mDistance
|
|
||||||
bool mPopulateAvailableNodes;
|
|
||||||
|
|
||||||
// allowed pathgrid nodes based on mDistance from the spawn point
|
|
||||||
// in local coordinates of mCell
|
|
||||||
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point mCurrentNode;
|
|
||||||
bool mTrimCurrentNode;
|
|
||||||
|
|
||||||
float mDoorCheckDuration;
|
|
||||||
int mStuckCount;
|
|
||||||
|
|
||||||
AiWanderStorage():
|
|
||||||
mTargetAngleRadians(0),
|
|
||||||
mTurnActorGivingGreetingToFacePlayer(false),
|
|
||||||
mReaction(0),
|
|
||||||
mSaidGreeting(AiWander::Greet_None),
|
|
||||||
mGreetingTimer(0),
|
|
||||||
mCell(NULL),
|
|
||||||
mState(AiWander::Wander_ChooseAction),
|
|
||||||
mIsWanderingManually(false),
|
|
||||||
mCanWanderAlongPathGrid(true),
|
|
||||||
mIdleAnimation(0),
|
|
||||||
mBadIdles(),
|
|
||||||
mPopulateAvailableNodes(true),
|
|
||||||
mAllowedNodes(),
|
|
||||||
mTrimCurrentNode(false),
|
|
||||||
mDoorCheckDuration(0), // TODO: maybe no longer needed
|
|
||||||
mStuckCount(0)
|
|
||||||
{};
|
|
||||||
|
|
||||||
void setState(const AiWander::WanderState wanderState, const bool isManualWander = false) {
|
|
||||||
mState = wanderState;
|
|
||||||
mIsWanderingManually = isManualWander;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||||
mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle),
|
mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle),
|
||||||
mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0))
|
mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0))
|
||||||
|
@ -221,7 +160,7 @@ namespace MWMechanics
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
storage.setState(Wander_Walking);
|
storage.setState(AiWanderStorage::Wander_Walking);
|
||||||
}
|
}
|
||||||
|
|
||||||
doPerFrameActionsForState(actor, duration, storage, pos);
|
doPerFrameActionsForState(actor, duration, storage, pos);
|
||||||
|
@ -270,7 +209,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if(actorCanMoveByZ && mDistance > 0) {
|
if(actorCanMoveByZ && mDistance > 0) {
|
||||||
// Typically want to idle for a short time before the next wander
|
// Typically want to idle for a short time before the next wander
|
||||||
if (Misc::Rng::rollDice(100) >= 92 && storage.mState != Wander_Walking) {
|
if (Misc::Rng::rollDice(100) >= 92 && storage.mState != AiWanderStorage::Wander_Walking) {
|
||||||
wanderNearStart(actor, storage, mDistance);
|
wanderNearStart(actor, storage, mDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +222,7 @@ namespace MWMechanics
|
||||||
if (Misc::Rng::rollDice(100) >= 96) {
|
if (Misc::Rng::rollDice(100) >= 96) {
|
||||||
wanderNearStart(actor, storage, mDistance);
|
wanderNearStart(actor, storage, mDistance);
|
||||||
} else {
|
} else {
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||||
}
|
}
|
||||||
} else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) {
|
} else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) {
|
||||||
storage.mCanWanderAlongPathGrid = false;
|
storage.mCanWanderAlongPathGrid = false;
|
||||||
|
@ -299,13 +238,13 @@ namespace MWMechanics
|
||||||
mDistance = 0;
|
mDistance = 0;
|
||||||
|
|
||||||
// Allow interrupting a walking actor to trigger a greeting
|
// Allow interrupting a walking actor to trigger a greeting
|
||||||
WanderState& wanderState = storage.mState;
|
AiWanderStorage::WanderState& wanderState = storage.mState;
|
||||||
if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking))
|
if ((wanderState == AiWanderStorage::Wander_IdleNow) || (wanderState == AiWanderStorage::Wander_Walking))
|
||||||
{
|
{
|
||||||
playGreetingIfPlayerGetsTooClose(actor, storage);
|
playGreetingIfPlayerGetsTooClose(actor, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((wanderState == Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
|
if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
|
||||||
{
|
{
|
||||||
// Construct a new path if there isn't one
|
// Construct a new path if there isn't one
|
||||||
if(!mPathFinder.isPathConstructed())
|
if(!mPathFinder.isPathConstructed())
|
||||||
|
@ -381,7 +320,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
storage.setState(Wander_Walking, true);
|
storage.setState(AiWanderStorage::Wander_Walking, true);
|
||||||
mHasDestination = true;
|
mHasDestination = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -410,26 +349,26 @@ namespace MWMechanics
|
||||||
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
|
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
mObstacleCheck.clear();
|
mObstacleCheck.clear();
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos)
|
void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos)
|
||||||
{
|
{
|
||||||
switch (storage.mState)
|
switch (storage.mState)
|
||||||
{
|
{
|
||||||
case Wander_IdleNow:
|
case AiWanderStorage::Wander_IdleNow:
|
||||||
onIdleStatePerFrameActions(actor, duration, storage);
|
onIdleStatePerFrameActions(actor, duration, storage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Wander_Walking:
|
case AiWanderStorage::Wander_Walking:
|
||||||
onWalkingStatePerFrameActions(actor, duration, storage, pos);
|
onWalkingStatePerFrameActions(actor, duration, storage, pos);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Wander_ChooseAction:
|
case AiWanderStorage::Wander_ChooseAction:
|
||||||
onChooseActionStatePerFrameActions(actor, storage);
|
onChooseActionStatePerFrameActions(actor, storage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Wander_MoveNow:
|
case AiWanderStorage::Wander_MoveNow:
|
||||||
break; // nothing to do
|
break; // nothing to do
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -451,7 +390,7 @@ namespace MWMechanics
|
||||||
if (mDistance && // actor is not intended to be stationary
|
if (mDistance && // actor is not intended to be stationary
|
||||||
proximityToDoor(actor, distance*1.6f))
|
proximityToDoor(actor, distance*1.6f))
|
||||||
{
|
{
|
||||||
storage.setState(Wander_MoveNow);
|
storage.setState(AiWanderStorage::Wander_MoveNow);
|
||||||
storage.mTrimCurrentNode = false; // just in case
|
storage.mTrimCurrentNode = false; // just in case
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -468,13 +407,13 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if idle animation finished
|
// Check if idle animation finished
|
||||||
GreetingState& greetingState = storage.mSaidGreeting;
|
AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting;
|
||||||
if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None))
|
if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == AiWanderStorage::Greet_Done || greetingState == AiWanderStorage::Greet_None))
|
||||||
{
|
{
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
storage.setState(Wander_Walking);
|
storage.setState(AiWanderStorage::Wander_Walking);
|
||||||
else
|
else
|
||||||
storage.setState(Wander_ChooseAction);
|
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +424,7 @@ namespace MWMechanics
|
||||||
if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE))
|
if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE))
|
||||||
{
|
{
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
storage.setState(Wander_ChooseAction);
|
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -502,7 +441,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (!idleAnimation && mDistance)
|
if (!idleAnimation && mDistance)
|
||||||
{
|
{
|
||||||
storage.setState(Wander_MoveNow);
|
storage.setState(AiWanderStorage::Wander_MoveNow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(idleAnimation)
|
if(idleAnimation)
|
||||||
|
@ -512,13 +451,13 @@ namespace MWMechanics
|
||||||
if(!playIdle(actor, idleAnimation))
|
if(!playIdle(actor, idleAnimation))
|
||||||
{
|
{
|
||||||
storage.mBadIdles.push_back(idleAnimation);
|
storage.mBadIdles.push_back(idleAnimation);
|
||||||
storage.setState(Wander_ChooseAction);
|
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
|
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
|
||||||
|
@ -534,7 +473,7 @@ namespace MWMechanics
|
||||||
trimAllowedNodes(storage.mAllowedNodes, mPathFinder);
|
trimAllowedNodes(storage.mAllowedNodes, mPathFinder);
|
||||||
mObstacleCheck.clear();
|
mObstacleCheck.clear();
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
storage.setState(Wander_MoveNow);
|
storage.setState(AiWanderStorage::Wander_MoveNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.mStuckCount++; // TODO: maybe no longer needed
|
storage.mStuckCount++; // TODO: maybe no longer needed
|
||||||
|
@ -545,7 +484,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
mObstacleCheck.clear();
|
mObstacleCheck.clear();
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
storage.setState(Wander_ChooseAction);
|
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||||
storage.mStuckCount = 0;
|
storage.mStuckCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,8 +535,8 @@ namespace MWMechanics
|
||||||
float playerDistSqr = (playerPos - actorPos).length2();
|
float playerDistSqr = (playerPos - actorPos).length2();
|
||||||
|
|
||||||
int& greetingTimer = storage.mGreetingTimer;
|
int& greetingTimer = storage.mGreetingTimer;
|
||||||
GreetingState& greetingState = storage.mSaidGreeting;
|
AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting;
|
||||||
if (greetingState == Greet_None)
|
if (greetingState == AiWanderStorage::Greet_None)
|
||||||
{
|
{
|
||||||
if ((playerDistSqr <= helloDistance*helloDistance) &&
|
if ((playerDistSqr <= helloDistance*helloDistance) &&
|
||||||
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
|
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
|
||||||
|
@ -606,37 +545,37 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (greetingTimer >= GREETING_SHOULD_START)
|
if (greetingTimer >= GREETING_SHOULD_START)
|
||||||
{
|
{
|
||||||
greetingState = Greet_InProgress;
|
greetingState = AiWanderStorage::Greet_InProgress;
|
||||||
MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
|
MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
|
||||||
greetingTimer = 0;
|
greetingTimer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (greetingState == Greet_InProgress)
|
if (greetingState == AiWanderStorage::Greet_InProgress)
|
||||||
{
|
{
|
||||||
greetingTimer++;
|
greetingTimer++;
|
||||||
|
|
||||||
if (storage.mState == Wander_Walking)
|
if (storage.mState == AiWanderStorage::Wander_Walking)
|
||||||
{
|
{
|
||||||
stopWalking(actor, storage, false);
|
stopWalking(actor, storage, false);
|
||||||
mObstacleCheck.clear();
|
mObstacleCheck.clear();
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
turnActorToFacePlayer(actorPos, playerPos, storage);
|
turnActorToFacePlayer(actorPos, playerPos, storage);
|
||||||
|
|
||||||
if (greetingTimer >= GREETING_SHOULD_END)
|
if (greetingTimer >= GREETING_SHOULD_END)
|
||||||
{
|
{
|
||||||
greetingState = Greet_Done;
|
greetingState = AiWanderStorage::Greet_Done;
|
||||||
greetingTimer = 0;
|
greetingTimer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (greetingState == MWMechanics::AiWander::Greet_Done)
|
if (greetingState == AiWanderStorage::Greet_Done)
|
||||||
{
|
{
|
||||||
float resetDist = 2 * helloDistance;
|
float resetDist = 2 * helloDistance;
|
||||||
if (playerDistSqr >= resetDist*resetDist)
|
if (playerDistSqr >= resetDist*resetDist)
|
||||||
greetingState = Greet_None;
|
greetingState = AiWanderStorage::Greet_None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +615,7 @@ namespace MWMechanics
|
||||||
storage.mAllowedNodes.push_back(storage.mCurrentNode);
|
storage.mAllowedNodes.push_back(storage.mCurrentNode);
|
||||||
storage.mCurrentNode = temp;
|
storage.mCurrentNode = temp;
|
||||||
|
|
||||||
storage.setState(Wander_Walking);
|
storage.setState(AiWanderStorage::Wander_Walking);
|
||||||
}
|
}
|
||||||
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||||
else
|
else
|
||||||
|
|
|
@ -21,8 +21,81 @@ namespace ESM
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
struct AiWanderStorage;
|
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
||||||
|
struct AiWanderStorage : AiTemporaryBase
|
||||||
|
{
|
||||||
|
// the z rotation angle to reach
|
||||||
|
// when mTurnActorGivingGreetingToFacePlayer is true
|
||||||
|
float mTargetAngleRadians;
|
||||||
|
bool mTurnActorGivingGreetingToFacePlayer;
|
||||||
|
float mReaction; // update some actions infrequently
|
||||||
|
|
||||||
|
enum GreetingState
|
||||||
|
{
|
||||||
|
Greet_None,
|
||||||
|
Greet_InProgress,
|
||||||
|
Greet_Done
|
||||||
|
};
|
||||||
|
GreetingState mSaidGreeting;
|
||||||
|
int mGreetingTimer;
|
||||||
|
|
||||||
|
const MWWorld::CellStore* mCell; // for detecting cell change
|
||||||
|
|
||||||
|
// AiWander states
|
||||||
|
enum WanderState
|
||||||
|
{
|
||||||
|
Wander_ChooseAction,
|
||||||
|
Wander_IdleNow,
|
||||||
|
Wander_MoveNow,
|
||||||
|
Wander_Walking
|
||||||
|
};
|
||||||
|
WanderState mState;
|
||||||
|
|
||||||
|
bool mIsWanderingManually;
|
||||||
|
bool mCanWanderAlongPathGrid;
|
||||||
|
|
||||||
|
unsigned short mIdleAnimation;
|
||||||
|
std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
|
||||||
|
|
||||||
|
// do we need to calculate allowed nodes based on mDistance
|
||||||
|
bool mPopulateAvailableNodes;
|
||||||
|
|
||||||
|
// allowed pathgrid nodes based on mDistance from the spawn point
|
||||||
|
// in local coordinates of mCell
|
||||||
|
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point mCurrentNode;
|
||||||
|
bool mTrimCurrentNode;
|
||||||
|
|
||||||
|
float mDoorCheckDuration;
|
||||||
|
int mStuckCount;
|
||||||
|
|
||||||
|
AiWanderStorage():
|
||||||
|
mTargetAngleRadians(0),
|
||||||
|
mTurnActorGivingGreetingToFacePlayer(false),
|
||||||
|
mReaction(0),
|
||||||
|
mSaidGreeting(Greet_None),
|
||||||
|
mGreetingTimer(0),
|
||||||
|
mCell(NULL),
|
||||||
|
mState(Wander_ChooseAction),
|
||||||
|
mIsWanderingManually(false),
|
||||||
|
mCanWanderAlongPathGrid(true),
|
||||||
|
mIdleAnimation(0),
|
||||||
|
mBadIdles(),
|
||||||
|
mPopulateAvailableNodes(true),
|
||||||
|
mAllowedNodes(),
|
||||||
|
mTrimCurrentNode(false),
|
||||||
|
mDoorCheckDuration(0), // TODO: maybe no longer needed
|
||||||
|
mStuckCount(0)
|
||||||
|
{};
|
||||||
|
|
||||||
|
void setState(const WanderState wanderState, const bool isManualWander = false)
|
||||||
|
{
|
||||||
|
mState = wanderState;
|
||||||
|
mIsWanderingManually = isManualWander;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Causes the Actor to wander within a specified range
|
/// \brief Causes the Actor to wander within a specified range
|
||||||
class AiWander : public AiPackage
|
class AiWander : public AiPackage
|
||||||
|
@ -52,19 +125,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const;
|
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const;
|
||||||
|
|
||||||
enum GreetingState {
|
|
||||||
Greet_None,
|
|
||||||
Greet_InProgress,
|
|
||||||
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();
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "aicombataction.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
|
@ -386,6 +387,10 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
|
||||||
{
|
{
|
||||||
jumpmask = MWRender::Animation::BlendMask_LowerBody;
|
jumpmask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
jumpAnimName = "jump";
|
jumpAnimName = "jump";
|
||||||
|
|
||||||
|
// For crossbow animations use 1h ones as fallback
|
||||||
|
if (mWeaponType == WeapType_Crossbow)
|
||||||
|
jumpAnimName += "1h";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,11 +439,18 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
movementAnimName = movestate->groupname;
|
movementAnimName = movestate->groupname;
|
||||||
if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos)
|
if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos)
|
||||||
{
|
{
|
||||||
movementAnimName += weap->shortgroup;
|
if (mWeaponType == WeapType_Spell && (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)) // Spellcasting stance turning is a special case
|
||||||
|
movementAnimName = weap->shortgroup + movementAnimName;
|
||||||
|
else
|
||||||
|
movementAnimName += weap->shortgroup;
|
||||||
if(!mAnimation->hasAnimation(movementAnimName))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
{
|
{
|
||||||
movemask = MWRender::Animation::BlendMask_LowerBody;
|
movemask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
movementAnimName = movestate->groupname;
|
movementAnimName = movestate->groupname;
|
||||||
|
|
||||||
|
// For crossbow animations use 1h ones as fallback
|
||||||
|
if (mWeaponType == WeapType_Crossbow)
|
||||||
|
movementAnimName += "1h";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,9 +487,11 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're playing the same animation, restart from the loop start instead of the
|
// If we're playing the same animation, start it from the point it ended
|
||||||
* beginning. */
|
bool sameAnim = (movementAnimName == mCurrentMovement);
|
||||||
int mode = ((movementAnimName == mCurrentMovement) ? 2 : 1);
|
float startPoint = 0.f;
|
||||||
|
if (sameAnim)
|
||||||
|
mAnimation->getInfo(mCurrentMovement, &startPoint);
|
||||||
|
|
||||||
mMovementAnimationControlled = true;
|
mMovementAnimationControlled = true;
|
||||||
|
|
||||||
|
@ -526,7 +540,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false,
|
mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false,
|
||||||
1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul, true);
|
1.f, (!sameAnim ? "start" : "loop start"), "stop", startPoint, ~0ul, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -676,16 +690,19 @@ MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::I
|
||||||
|
|
||||||
void CharacterController::playDeath(float startpoint, CharacterState death)
|
void CharacterController::playDeath(float startpoint, CharacterState death)
|
||||||
{
|
{
|
||||||
|
// Make sure the character was swimming upon death for forward-compatibility
|
||||||
|
const bool wasSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
|
||||||
|
|
||||||
switch (death)
|
switch (death)
|
||||||
{
|
{
|
||||||
case CharState_SwimDeath:
|
case CharState_SwimDeath:
|
||||||
mCurrentDeath = "swimdeath";
|
mCurrentDeath = "swimdeath";
|
||||||
break;
|
break;
|
||||||
case CharState_SwimDeathKnockDown:
|
case CharState_SwimDeathKnockDown:
|
||||||
mCurrentDeath = "swimdeathknockdown";
|
mCurrentDeath = (wasSwimming ? "swimdeathknockdown" : "deathknockdown");
|
||||||
break;
|
break;
|
||||||
case CharState_SwimDeathKnockOut:
|
case CharState_SwimDeathKnockOut:
|
||||||
mCurrentDeath = "swimdeathknockout";
|
mCurrentDeath = (wasSwimming ? "swimdeathknockout" : "deathknockout");
|
||||||
break;
|
break;
|
||||||
case CharState_DeathKnockDown:
|
case CharState_DeathKnockDown:
|
||||||
mCurrentDeath = "deathknockdown";
|
mCurrentDeath = "deathknockdown";
|
||||||
|
@ -808,6 +825,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
, mSecondsOfRunning(0)
|
, mSecondsOfRunning(0)
|
||||||
, mTurnAnimationThreshold(0)
|
, mTurnAnimationThreshold(0)
|
||||||
, mAttackingOrSpell(false)
|
, mAttackingOrSpell(false)
|
||||||
|
, mCastingManualSpell(false)
|
||||||
, mTimeUntilWake(0.f)
|
, mTimeUntilWake(0.f)
|
||||||
{
|
{
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
|
@ -1021,7 +1039,8 @@ void CharacterController::handleTextKey(const std::string &groupname, const std:
|
||||||
// the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type.
|
// the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type.
|
||||||
&& evt.compare(off, len, mAttackType + " release") == 0)
|
&& evt.compare(off, len, mAttackType + " release") == 0)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell);
|
||||||
|
mCastingManualSpell = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0)
|
else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0)
|
||||||
|
@ -1102,7 +1121,9 @@ bool CharacterController::updateCreatureState()
|
||||||
if (weapType == WeapType_Spell)
|
if (weapType == WeapType_Spell)
|
||||||
{
|
{
|
||||||
const std::string spellid = stats.getSpells().getSelectedSpell();
|
const std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
|
||||||
|
|
||||||
|
if (!spellid.empty() && canCast)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
@ -1123,7 +1144,7 @@ bool CharacterController::updateCreatureState()
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(mPtr, NULL);
|
MWMechanics::CastSpell cast(mPtr, NULL, false, mCastingManualSpell);
|
||||||
cast.playSpellCastingEffects(spellid);
|
cast.playSpellCastingEffects(spellid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1138,7 +1159,10 @@ bool CharacterController::updateCreatureState()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!mAnimation->hasAnimation("spellcast"))
|
if (!mAnimation->hasAnimation("spellcast"))
|
||||||
MWBase::Environment::get().getWorld()->castSpell(mPtr); // No "release" text key to use, so cast immediately
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
|
||||||
|
mCastingManualSpell = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellid);
|
const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellid);
|
||||||
|
@ -1411,8 +1435,9 @@ bool CharacterController::updateWeaponState()
|
||||||
stats.getSpells().setSelectedSpell(selectedSpell);
|
stats.getSpells().setSelectedSpell(selectedSpell);
|
||||||
}
|
}
|
||||||
std::string spellid = stats.getSpells().getSelectedSpell();
|
std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
|
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
|
||||||
|
|
||||||
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
if(!spellid.empty() && canCast)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
@ -1433,7 +1458,7 @@ bool CharacterController::updateWeaponState()
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(mPtr, NULL);
|
MWMechanics::CastSpell cast(mPtr, NULL, false, mCastingManualSpell);
|
||||||
cast.playSpellCastingEffects(spellid);
|
cast.playSpellCastingEffects(spellid);
|
||||||
|
|
||||||
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
||||||
|
@ -1711,16 +1736,18 @@ bool CharacterController::updateWeaponState()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: apply reload animations only for upper body since blending with movement animations can give weird result.
|
||||||
|
// Especially noticable with crossbow reload animation.
|
||||||
if(!start.empty())
|
if(!start.empty())
|
||||||
{
|
{
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
||||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_All, true,
|
MWRender::Animation::BlendMask_UpperBody, true,
|
||||||
weapSpeed, start, stop, 0.0f, 0);
|
weapSpeed, start, stop, 0.0f, 0);
|
||||||
else
|
else
|
||||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_All, false,
|
MWRender::Animation::BlendMask_UpperBody, false,
|
||||||
weapSpeed, start, stop, 0.0f, 0);
|
weapSpeed, start, stop, 0.0f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2498,6 +2525,11 @@ bool CharacterController::isAttackPrepairing() const
|
||||||
mUpperBodyState == UpperCharState_MinAttackToMaxAttack;
|
mUpperBodyState == UpperCharState_MinAttackToMaxAttack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CharacterController::isCastingSpell() const
|
||||||
|
{
|
||||||
|
return mCastingManualSpell || mUpperBodyState == UpperCharState_CastingSpell;
|
||||||
|
}
|
||||||
|
|
||||||
bool CharacterController::isReadyToBlock() const
|
bool CharacterController::isReadyToBlock() const
|
||||||
{
|
{
|
||||||
return updateCarriedLeftVisible(mWeaponType);
|
return updateCarriedLeftVisible(mWeaponType);
|
||||||
|
@ -2561,6 +2593,14 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell)
|
||||||
mAttackingOrSpell = attackingOrSpell;
|
mAttackingOrSpell = attackingOrSpell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::castSpell(const std::string spellId, bool manualSpell)
|
||||||
|
{
|
||||||
|
mAttackingOrSpell = true;
|
||||||
|
mCastingManualSpell = manualSpell;
|
||||||
|
ActionSpell action = ActionSpell(spellId);
|
||||||
|
action.prepare(mPtr);
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::setAIAttackType(const std::string& attackType)
|
void CharacterController::setAIAttackType(const std::string& attackType)
|
||||||
{
|
{
|
||||||
mAttackType = attackType;
|
mAttackType = attackType;
|
||||||
|
|
|
@ -204,6 +204,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
std::string mAttackType; // slash, chop or thrust
|
std::string mAttackType; // slash, chop or thrust
|
||||||
|
|
||||||
bool mAttackingOrSpell;
|
bool mAttackingOrSpell;
|
||||||
|
bool mCastingManualSpell;
|
||||||
|
|
||||||
float mTimeUntilWake;
|
float mTimeUntilWake;
|
||||||
|
|
||||||
|
@ -276,6 +277,7 @@ public:
|
||||||
void forceStateUpdate();
|
void forceStateUpdate();
|
||||||
|
|
||||||
bool isAttackPrepairing() const;
|
bool isAttackPrepairing() const;
|
||||||
|
bool isCastingSpell() const;
|
||||||
bool isReadyToBlock() const;
|
bool isReadyToBlock() const;
|
||||||
bool isKnockedDown() const;
|
bool isKnockedDown() const;
|
||||||
bool isKnockedOut() const;
|
bool isKnockedOut() const;
|
||||||
|
@ -286,6 +288,7 @@ public:
|
||||||
bool isAttackingOrSpell() const;
|
bool isAttackingOrSpell() const;
|
||||||
|
|
||||||
void setAttackingOrSpell(bool attackingOrSpell);
|
void setAttackingOrSpell(bool attackingOrSpell);
|
||||||
|
void castSpell(const std::string spellId, bool manualSpell=false);
|
||||||
void setAIAttackType(const std::string& attackType);
|
void setAIAttackType(const std::string& attackType);
|
||||||
static void setAttackTypeRandomly(std::string& attackType);
|
static void setAttackTypeRandomly(std::string& attackType);
|
||||||
|
|
||||||
|
|
|
@ -266,6 +266,12 @@ namespace MWMechanics
|
||||||
mObjects.addObject(ptr);
|
mObjects.addObject(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell)
|
||||||
|
{
|
||||||
|
if(ptr.getClass().isActor())
|
||||||
|
mActors.castSpell(ptr, spellId, manualSpell);
|
||||||
|
}
|
||||||
|
|
||||||
void MechanicsManager::remove(const MWWorld::Ptr& ptr)
|
void MechanicsManager::remove(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
if(ptr == mWatched)
|
if(ptr == mWatched)
|
||||||
|
@ -1824,6 +1830,11 @@ namespace MWMechanics
|
||||||
stats.resurrect();
|
stats.resurrect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MechanicsManager::isCastingSpell(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
return mActors.isCastingSpell(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
||||||
{
|
{
|
||||||
return mActors.isReadyToBlock(ptr);
|
return mActors.isReadyToBlock(ptr);
|
||||||
|
|
|
@ -200,10 +200,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual void keepPlayerAlive();
|
virtual void keepPlayerAlive();
|
||||||
|
|
||||||
|
virtual bool isCastingSpell (const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
|
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
|
||||||
/// Is \a ptr casting spell or using weapon now?
|
/// Is \a ptr casting spell or using weapon now?
|
||||||
virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const;
|
virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const;
|
||||||
|
|
||||||
|
virtual void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell=false);
|
||||||
|
|
||||||
/// Check if the target actor was detected by an observer
|
/// Check if the target actor was detected by an observer
|
||||||
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);
|
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);
|
||||||
|
|
|
@ -332,13 +332,14 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target, const bool fromProjectile)
|
CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target, const bool fromProjectile, const bool isScripted)
|
||||||
: mCaster(caster)
|
: mCaster(caster)
|
||||||
, mTarget(target)
|
, mTarget(target)
|
||||||
, mStack(false)
|
, mStack(false)
|
||||||
, mHitPosition(0,0,0)
|
, mHitPosition(0,0,0)
|
||||||
, mAlwaysSucceed(false)
|
, mAlwaysSucceed(false)
|
||||||
, mFromProjectile(fromProjectile)
|
, mFromProjectile(fromProjectile)
|
||||||
|
, mIsScripted(isScripted)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -961,7 +962,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool godmode = mCaster == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
bool godmode = mCaster == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
||||||
|
|
||||||
if (mCaster.getClass().isActor() && !mAlwaysSucceed)
|
if (mCaster.getClass().isActor() && !mAlwaysSucceed && !mIsScripted)
|
||||||
{
|
{
|
||||||
school = getSpellSchool(spell, mCaster);
|
school = getSpellSchool(spell, mCaster);
|
||||||
|
|
||||||
|
@ -1025,7 +1026,7 @@ namespace MWMechanics
|
||||||
stats.getSpells().usePower(spell);
|
stats.getSpells().usePower(spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCaster == getPlayer() && spellIncreasesSkill(spell))
|
if (mCaster == getPlayer() && spellIncreasesSkill())
|
||||||
mCaster.getClass().skillUsageSucceeded(mCaster,
|
mCaster.getClass().skillUsageSucceeded(mCaster,
|
||||||
spellSchoolToSkill(school), 0);
|
spellSchoolToSkill(school), 0);
|
||||||
|
|
||||||
|
@ -1149,6 +1150,14 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CastSpell::spellIncreasesSkill()
|
||||||
|
{
|
||||||
|
if (mIsScripted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return MWMechanics::spellIncreasesSkill(mId);
|
||||||
|
}
|
||||||
|
|
||||||
int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor)
|
int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -88,9 +88,10 @@ namespace MWMechanics
|
||||||
osg::Vec3f mHitPosition; // Used for spawning area orb
|
osg::Vec3f mHitPosition; // Used for spawning area orb
|
||||||
bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false)
|
bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false)
|
||||||
bool mFromProjectile; // True if spell is cast by enchantment of some projectile (arrow, bolt or thrown weapon)
|
bool mFromProjectile; // True if spell is cast by enchantment of some projectile (arrow, bolt or thrown weapon)
|
||||||
|
bool mIsScripted; // True if spell is casted from script and ignores some checks (mana level, success chance, etc.)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target, const bool fromProjectile=false);
|
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target, const bool fromProjectile=false, const bool isScripted=false);
|
||||||
|
|
||||||
bool cast (const ESM::Spell* spell);
|
bool cast (const ESM::Spell* spell);
|
||||||
|
|
||||||
|
@ -108,6 +109,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void playSpellCastingEffects(const std::string &spellid);
|
void playSpellCastingEffects(const std::string &spellid);
|
||||||
|
|
||||||
|
bool spellIncreasesSkill();
|
||||||
|
|
||||||
/// Launch a bolt with the given effects.
|
/// Launch a bolt with the given effects.
|
||||||
void launchMagicBolt ();
|
void launchMagicBolt ();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/actionequip.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/containerstore.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
@ -215,12 +216,11 @@ namespace MWScript
|
||||||
"to fulfil requirements of Equip instruction" << std::endl;
|
"to fulfil requirements of Equip instruction" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
if (ptr == MWMechanics::getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->useItem(*it);
|
MWBase::Environment::get().getWindowManager()->useItem(*it, true);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::shared_ptr<MWWorld::Action> action = it->getClass().use(*it);
|
std::shared_ptr<MWWorld::Action> action = it->getClass().use(*it, true);
|
||||||
// No equip sound for actors other than the player
|
|
||||||
action->execute(ptr, true);
|
action->execute(ptr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/aicast.hpp"
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
@ -1153,15 +1154,31 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
std::string spell = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string spellId = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
std::string targetId = ::Misc::StringUtils::lowerCase(runtime.getStringLiteral (runtime[0].mInteger));
|
std::string targetId = ::Misc::StringUtils::lowerCase(runtime.getStringLiteral (runtime[0].mInteger));
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (spellId);
|
||||||
|
if (spell && spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power)
|
||||||
|
{
|
||||||
|
runtime.getContext().report("spellcasting failed: you can cast only spells and powers.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obviously we can not use casting animation for player here
|
||||||
|
if (ptr.getClass().isActor() && ptr != MWMechanics::getPlayer())
|
||||||
|
{
|
||||||
|
MWMechanics::AiCast castPackage(targetId, spellId, true);
|
||||||
|
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(castPackage, ptr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(ptr, target);
|
MWMechanics::CastSpell cast(ptr, target, false, true);
|
||||||
cast.mHitPosition = target.getRefData().getPosition().asVec3();
|
cast.mHitPosition = target.getRefData().getPosition().asVec3();
|
||||||
cast.mAlwaysSucceed = true;
|
cast.mAlwaysSucceed = true;
|
||||||
cast.cast(spell);
|
cast.cast(spell);
|
||||||
|
@ -1179,7 +1196,7 @@ namespace MWScript
|
||||||
std::string spell = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string spell = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(ptr, ptr);
|
MWMechanics::CastSpell cast(ptr, ptr, false, true);
|
||||||
cast.mHitPosition = ptr.getRefData().getPosition().asVec3();
|
cast.mHitPosition = ptr.getRefData().getPosition().asVec3();
|
||||||
cast.mAlwaysSucceed = true;
|
cast.mAlwaysSucceed = true;
|
||||||
cast.cast(spell);
|
cast.cast(spell);
|
||||||
|
|
|
@ -9,12 +9,19 @@
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
ActionAlchemy::ActionAlchemy(bool force)
|
||||||
|
: Action (false)
|
||||||
|
, mForce(force)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void ActionAlchemy::executeImp (const Ptr& actor)
|
void ActionAlchemy::executeImp (const Ptr& actor)
|
||||||
{
|
{
|
||||||
if (actor != MWMechanics::getPlayer())
|
if (actor != MWMechanics::getPlayer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat
|
if(!mForce && MWMechanics::isPlayerInCombat())
|
||||||
|
{ //Ensure we're not in combat
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,11 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
class ActionAlchemy : public Action
|
class ActionAlchemy : public Action
|
||||||
{
|
{
|
||||||
virtual void executeImp (const Ptr& actor);
|
bool mForce;
|
||||||
|
virtual void executeImp (const Ptr& actor);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ActionAlchemy(bool force=false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
ActionEquip::ActionEquip (const MWWorld::Ptr& object) : Action (false, object)
|
ActionEquip::ActionEquip (const MWWorld::Ptr& object, bool force)
|
||||||
|
: Action (false, object)
|
||||||
|
, mForce(force)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,18 +25,29 @@ namespace MWWorld
|
||||||
MWWorld::Ptr object = getTarget();
|
MWWorld::Ptr object = getTarget();
|
||||||
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
|
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
|
||||||
|
|
||||||
std::pair <int, std::string> result = object.getClass().canBeEquipped (object, actor);
|
if (object.getClass().hasItemHealth(object) && object.getCellRef().getCharge() == 0)
|
||||||
|
|
||||||
// display error message if the player tried to equip something
|
|
||||||
if (!result.second.empty() && actor == MWMechanics::getPlayer())
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(result.second);
|
|
||||||
|
|
||||||
switch(result.first)
|
|
||||||
{
|
{
|
||||||
case 0:
|
if (actor == MWMechanics::getPlayer())
|
||||||
return;
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}");
|
||||||
default:
|
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mForce)
|
||||||
|
{
|
||||||
|
std::pair <int, std::string> result = object.getClass().canBeEquipped (object, actor);
|
||||||
|
|
||||||
|
// display error message if the player tried to equip something
|
||||||
|
if (!result.second.empty() && actor == MWMechanics::getPlayer())
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(result.second);
|
||||||
|
|
||||||
|
switch(result.first)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// slots that this item can be equipped in
|
// slots that this item can be equipped in
|
||||||
|
|
|
@ -2,17 +2,18 @@
|
||||||
#define GAME_MWWORLD_ACTIONEQUIP_H
|
#define GAME_MWWORLD_ACTIONEQUIP_H
|
||||||
|
|
||||||
#include "action.hpp"
|
#include "action.hpp"
|
||||||
#include "ptr.hpp"
|
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class ActionEquip : public Action
|
class ActionEquip : public Action
|
||||||
{
|
{
|
||||||
virtual void executeImp (const Ptr& actor);
|
bool mForce;
|
||||||
|
|
||||||
public:
|
virtual void executeImp (const Ptr& actor);
|
||||||
/// @param item to equip
|
|
||||||
ActionEquip (const Ptr& object);
|
public:
|
||||||
|
/// @param item to equip
|
||||||
|
ActionEquip (const Ptr& object, bool force=false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
ActionRepair::ActionRepair(const Ptr &item)
|
ActionRepair::ActionRepair(const Ptr& item, bool force)
|
||||||
: Action(false, item)
|
: Action (false, item)
|
||||||
|
, mForce(force)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +19,8 @@ namespace MWWorld
|
||||||
if (actor != MWMechanics::getPlayer())
|
if (actor != MWMechanics::getPlayer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(MWMechanics::isPlayerInCombat()) {
|
if(!mForce && MWMechanics::isPlayerInCombat())
|
||||||
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
class ActionRepair : public Action
|
class ActionRepair : public Action
|
||||||
{
|
{
|
||||||
virtual void executeImp (const Ptr& actor);
|
bool mForce;
|
||||||
|
|
||||||
|
virtual void executeImp (const Ptr& actor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ActionRepair(const MWWorld::Ptr& item);
|
/// @param item repair hammer
|
||||||
|
ActionRepair(const Ptr& item, bool force=false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace MWWorld
|
||||||
return std::shared_ptr<Action> (new NullAction);
|
return std::shared_ptr<Action> (new NullAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Action> Class::use (const Ptr& ptr) const
|
std::shared_ptr<Action> Class::use (const Ptr& ptr, bool force) const
|
||||||
{
|
{
|
||||||
return std::shared_ptr<Action> (new NullAction);
|
return std::shared_ptr<Action> (new NullAction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace MWWorld
|
||||||
virtual std::shared_ptr<Action> activate (const Ptr& ptr, const Ptr& actor) const;
|
virtual std::shared_ptr<Action> activate (const Ptr& ptr, const Ptr& actor) const;
|
||||||
///< Generate action for activation (default implementation: return a null action).
|
///< Generate action for activation (default implementation: return a null action).
|
||||||
|
|
||||||
virtual std::shared_ptr<Action> use (const Ptr& ptr)
|
virtual std::shared_ptr<Action> use (const Ptr& ptr, bool force=false)
|
||||||
const;
|
const;
|
||||||
///< Generate action for using via inventory menu (default implementation: return a
|
///< Generate action for using via inventory menu (default implementation: return a
|
||||||
/// null action).
|
/// null action).
|
||||||
|
|
|
@ -1299,7 +1299,10 @@ namespace MWWorld
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
{
|
{
|
||||||
if (!newCell->isExterior())
|
if (!newCell->isExterior())
|
||||||
|
{
|
||||||
changeToInteriorCell(Misc::StringUtils::lowerCase(newCell->getCell()->mName), pos, false);
|
changeToInteriorCell(Misc::StringUtils::lowerCase(newCell->getCell()->mName), pos, false);
|
||||||
|
removeContainerScripts(getPlayerPtr());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mWorldScene->isCellActive(*newCell))
|
if (mWorldScene->isCellActive(*newCell))
|
||||||
|
@ -1320,7 +1323,8 @@ namespace MWWorld
|
||||||
mWorldScene->addObjectToScene(newPtr);
|
mWorldScene->addObjectToScene(newPtr);
|
||||||
|
|
||||||
std::string script = newPtr.getClass().getScript(newPtr);
|
std::string script = newPtr.getClass().getScript(newPtr);
|
||||||
if (!script.empty()) {
|
if (!script.empty())
|
||||||
|
{
|
||||||
mLocalScripts.add(script, newPtr);
|
mLocalScripts.add(script, newPtr);
|
||||||
}
|
}
|
||||||
addContainerScripts(newPtr, newCell);
|
addContainerScripts(newPtr, newCell);
|
||||||
|
@ -3032,13 +3036,13 @@ namespace MWWorld
|
||||||
return !fail;
|
return !fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::castSpell(const Ptr &actor)
|
void World::castSpell(const Ptr &actor, bool manualSpell)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
|
||||||
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
|
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
|
||||||
std::vector<MWWorld::Ptr> targetActors;
|
std::vector<MWWorld::Ptr> targetActors;
|
||||||
if (!actor.isEmpty() && actor != MWMechanics::getPlayer())
|
if (!actor.isEmpty() && actor != MWMechanics::getPlayer() && !manualSpell)
|
||||||
actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors);
|
actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors);
|
||||||
|
|
||||||
const float fCombatDistance = getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
|
const float fCombatDistance = getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
|
||||||
|
@ -3056,51 +3060,71 @@ namespace MWWorld
|
||||||
|
|
||||||
if (target.isEmpty())
|
if (target.isEmpty())
|
||||||
{
|
{
|
||||||
// For actor targets, we want to use hit contact with bounding boxes.
|
// For scripted spells we should not use hit contact
|
||||||
// This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise.
|
if (manualSpell)
|
||||||
// For object targets, we want the detailed shapes (rendering raycast).
|
|
||||||
// If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf.
|
|
||||||
std::pair<MWWorld::Ptr,osg::Vec3f> result1 = getHitContact(actor, fCombatDistance, targetActors);
|
|
||||||
|
|
||||||
// Get the target to use for "on touch" effects, using the facing direction from Head node
|
|
||||||
osg::Vec3f origin = getActorHeadTransform(actor).getTrans();
|
|
||||||
|
|
||||||
osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))
|
|
||||||
* osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1));
|
|
||||||
|
|
||||||
osg::Vec3f direction = orient * osg::Vec3f(0,1,0);
|
|
||||||
float distance = getMaxActivationDistance();
|
|
||||||
osg::Vec3f dest = origin + direction * distance;
|
|
||||||
|
|
||||||
MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true);
|
|
||||||
|
|
||||||
float dist1 = std::numeric_limits<float>::max();
|
|
||||||
float dist2 = std::numeric_limits<float>::max();
|
|
||||||
|
|
||||||
if (!result1.first.isEmpty() && result1.first.getClass().isActor())
|
|
||||||
dist1 = (origin - result1.second).length();
|
|
||||||
if (result2.mHit)
|
|
||||||
dist2 = (origin - result2.mHitPointWorld).length();
|
|
||||||
|
|
||||||
if (!result1.first.isEmpty() && result1.first.getClass().isActor())
|
|
||||||
{
|
{
|
||||||
target = result1.first;
|
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
||||||
hitPosition = result1.second;
|
if (actor != MWMechanics::getPlayer())
|
||||||
if (dist1 > getMaxActivationDistance())
|
{
|
||||||
target = NULL;
|
const MWMechanics::CreatureStats &stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
||||||
|
{
|
||||||
|
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCast)
|
||||||
|
{
|
||||||
|
target = (*it)->getTarget();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (result2.mHit)
|
else
|
||||||
{
|
{
|
||||||
target = result2.mHitObject;
|
// For actor targets, we want to use hit contact with bounding boxes.
|
||||||
hitPosition = result2.mHitPointWorld;
|
// This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise.
|
||||||
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target))
|
// For object targets, we want the detailed shapes (rendering raycast).
|
||||||
target = NULL;
|
// If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf.
|
||||||
|
std::pair<MWWorld::Ptr,osg::Vec3f> result1 = getHitContact(actor, fCombatDistance, targetActors);
|
||||||
|
|
||||||
|
// Get the target to use for "on touch" effects, using the facing direction from Head node
|
||||||
|
osg::Vec3f origin = getActorHeadTransform(actor).getTrans();
|
||||||
|
|
||||||
|
osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))
|
||||||
|
* osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1));
|
||||||
|
|
||||||
|
osg::Vec3f direction = orient * osg::Vec3f(0,1,0);
|
||||||
|
float distance = getMaxActivationDistance();
|
||||||
|
osg::Vec3f dest = origin + direction * distance;
|
||||||
|
|
||||||
|
MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true);
|
||||||
|
|
||||||
|
float dist1 = std::numeric_limits<float>::max();
|
||||||
|
float dist2 = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
|
if (!result1.first.isEmpty() && result1.first.getClass().isActor())
|
||||||
|
dist1 = (origin - result1.second).length();
|
||||||
|
if (result2.mHit)
|
||||||
|
dist2 = (origin - result2.mHitPointWorld).length();
|
||||||
|
|
||||||
|
if (!result1.first.isEmpty() && result1.first.getClass().isActor())
|
||||||
|
{
|
||||||
|
target = result1.first;
|
||||||
|
hitPosition = result1.second;
|
||||||
|
if (dist1 > getMaxActivationDistance())
|
||||||
|
target = NULL;
|
||||||
|
}
|
||||||
|
else if (result2.mHit)
|
||||||
|
{
|
||||||
|
target = result2.mHitObject;
|
||||||
|
hitPosition = result2.mHitPointWorld;
|
||||||
|
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target))
|
||||||
|
target = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(actor, target);
|
MWMechanics::CastSpell cast(actor, target, false, manualSpell);
|
||||||
cast.mHitPosition = hitPosition;
|
cast.mHitPosition = hitPosition;
|
||||||
|
|
||||||
if (!selectedSpell.empty())
|
if (!selectedSpell.empty())
|
||||||
|
|
|
@ -696,7 +696,7 @@ namespace MWWorld
|
||||||
* @brief Cast the actual spell, should be called mid-animation
|
* @brief Cast the actual spell, should be called mid-animation
|
||||||
* @param actor
|
* @param actor
|
||||||
*/
|
*/
|
||||||
void castSpell (const MWWorld::Ptr& actor) override;
|
void castSpell (const MWWorld::Ptr& actor, bool manualSpell=false) override;
|
||||||
|
|
||||||
void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override;
|
void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override;
|
||||||
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
|
|
|
@ -207,4 +207,4 @@ macro (copy_all_resource_files source_dir destination_dir_base destination_dir_r
|
||||||
get_filename_component(filename ${f} NAME)
|
get_filename_component(filename ${f} NAME)
|
||||||
copy_resource_file("${source_dir}/${f}" "${destination_dir_base}" "${destination_dir_relative}/${filename}")
|
copy_resource_file("${source_dir}/${f}" "${destination_dir_base}" "${destination_dir_relative}/${filename}")
|
||||||
endforeach (f)
|
endforeach (f)
|
||||||
endmacro (copy_all_resource_files)
|
endmacro (copy_all_resource_files)
|
||||||
|
|
|
@ -210,6 +210,11 @@ add_component_dir (fallback
|
||||||
fallback validate
|
fallback validate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(NOT WIN32 AND NOT ANDROID)
|
||||||
|
add_component_dir (crashcatcher
|
||||||
|
crashcatcher
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,11 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
|
|
||||||
#include <string>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
namespace bfs = boost::filesystem;
|
||||||
|
|
||||||
#include <SDL_messagebox.h>
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
|
@ -402,7 +406,7 @@ static void crash_handler(const char *logfile)
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
|
int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
stack_t altss;
|
stack_t altss;
|
||||||
|
@ -454,19 +458,31 @@ int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, co
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_debugger_present()
|
||||||
// gdb apparently opens FD(s) 3,4,5 (whereas a typical prog uses only stdin=0, stdout=1,stderr=2)
|
|
||||||
bool
|
|
||||||
is_debugger_attached(void)
|
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bfs::ifstream file((bfs::path("/proc/self/status")));
|
||||||
FILE *fd = fopen("/tmp", "r");
|
while (!file.eof())
|
||||||
|
|
||||||
if (fileno(fd) > 5)
|
|
||||||
{
|
{
|
||||||
rc = true;
|
std::string word;
|
||||||
|
file >> word;
|
||||||
|
if (word == "TracerPid:")
|
||||||
|
{
|
||||||
|
file >> word;
|
||||||
|
return word != "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath)
|
||||||
|
{
|
||||||
|
if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_present())
|
||||||
|
{
|
||||||
|
int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT };
|
||||||
|
if (crashCatcherInstallHandlers(argc, argv, 5, s, crashLogPath.c_str(), NULL) == -1)
|
||||||
|
{
|
||||||
|
std::cerr << "Installing crash handler failed" << std::endl;
|
||||||
|
} else
|
||||||
|
std::cout << "Crash handler installed" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fd);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
20
components/crashcatcher/crashcatcher.hpp
Normal file
20
components/crashcatcher/crashcatcher.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef CRASHCATCHER_H
|
||||||
|
#define CRASHCATCHER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix))
|
||||||
|
#define USE_CRASH_CATCHER 1
|
||||||
|
#else
|
||||||
|
#define USE_CRASH_CATCHER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_CRASH_CATCHER
|
||||||
|
extern void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath);
|
||||||
|
#else
|
||||||
|
inline void crashCatcherInstall(int, char **, const std::string &crashLogPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,10 +4,24 @@
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
osg::Quat NIFStream::getQuaternion()
|
||||||
|
{
|
||||||
|
float f[4];
|
||||||
|
readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&f);
|
||||||
|
osg::Quat quat;
|
||||||
|
quat.w() = f[0];
|
||||||
|
quat.x() = f[1];
|
||||||
|
quat.y() = f[2];
|
||||||
|
quat.z() = f[3];
|
||||||
|
return quat;
|
||||||
|
}
|
||||||
|
|
||||||
//Private functions
|
Transformation NIFStream::getTrafo()
|
||||||
|
{
|
||||||
|
Transformation t;
|
||||||
//Public functions
|
t.pos = getVector3();
|
||||||
|
t.rotation = getMatrix3();
|
||||||
|
t.scale = getFloat();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,8 @@ template<typename type, typename IntegerT> type inline readLittleEndianType(File
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NIFStream {
|
class NIFStream
|
||||||
|
{
|
||||||
/// Input stream
|
/// Input stream
|
||||||
Files::IStreamPtr inp;
|
Files::IStreamPtr inp;
|
||||||
|
|
||||||
|
@ -93,71 +93,71 @@ public:
|
||||||
|
|
||||||
void skip(size_t size) { inp->ignore(size); }
|
void skip(size_t size) { inp->ignore(size); }
|
||||||
|
|
||||||
char getChar()
|
char getChar()
|
||||||
{
|
{
|
||||||
return readLittleEndianType<char,char>(inp);
|
return readLittleEndianType<char,char>(inp);
|
||||||
}
|
}
|
||||||
short getShort()
|
|
||||||
{
|
short getShort()
|
||||||
|
{
|
||||||
return readLittleEndianType<short,short>(inp);
|
return readLittleEndianType<short,short>(inp);
|
||||||
}
|
}
|
||||||
unsigned short getUShort()
|
|
||||||
{
|
unsigned short getUShort()
|
||||||
|
{
|
||||||
return readLittleEndianType<unsigned short,unsigned short>(inp);
|
return readLittleEndianType<unsigned short,unsigned short>(inp);
|
||||||
}
|
}
|
||||||
int getInt()
|
|
||||||
|
int getInt()
|
||||||
{
|
{
|
||||||
return readLittleEndianType<int,int>(inp);
|
return readLittleEndianType<int,int>(inp);
|
||||||
}
|
}
|
||||||
unsigned int getUInt()
|
|
||||||
{
|
unsigned int getUInt()
|
||||||
|
{
|
||||||
return readLittleEndianType<unsigned int,unsigned int>(inp);
|
return readLittleEndianType<unsigned int,unsigned int>(inp);
|
||||||
}
|
}
|
||||||
float getFloat()
|
|
||||||
{
|
float getFloat()
|
||||||
|
{
|
||||||
return readLittleEndianType<float,uint32_t>(inp);
|
return readLittleEndianType<float,uint32_t>(inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec2f getVector2() {
|
osg::Vec2f getVector2()
|
||||||
|
{
|
||||||
osg::Vec2f vec;
|
osg::Vec2f vec;
|
||||||
readLittleEndianBufferOfType<2,float,uint32_t>(inp, (float*)&vec._v[0]);
|
readLittleEndianBufferOfType<2,float,uint32_t>(inp, (float*)&vec._v[0]);
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
osg::Vec3f getVector3() {
|
|
||||||
|
osg::Vec3f getVector3()
|
||||||
|
{
|
||||||
osg::Vec3f vec;
|
osg::Vec3f vec;
|
||||||
readLittleEndianBufferOfType<3, float,uint32_t>(inp, (float*)&vec._v[0]);
|
readLittleEndianBufferOfType<3, float,uint32_t>(inp, (float*)&vec._v[0]);
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
osg::Vec4f getVector4() {
|
|
||||||
|
osg::Vec4f getVector4()
|
||||||
|
{
|
||||||
osg::Vec4f vec;
|
osg::Vec4f vec;
|
||||||
readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&vec._v[0]);
|
readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&vec._v[0]);
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
Matrix3 getMatrix3() {
|
|
||||||
|
Matrix3 getMatrix3()
|
||||||
|
{
|
||||||
Matrix3 mat;
|
Matrix3 mat;
|
||||||
readLittleEndianBufferOfType<9, float,uint32_t>(inp, (float*)&mat.mValues);
|
readLittleEndianBufferOfType<9, float,uint32_t>(inp, (float*)&mat.mValues);
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
osg::Quat getQuaternion() {
|
|
||||||
float f[4];
|
osg::Quat getQuaternion();
|
||||||
readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&f);
|
|
||||||
osg::Quat quat;
|
Transformation getTrafo();
|
||||||
quat.w() = f[0];
|
|
||||||
quat.x() = f[1];
|
|
||||||
quat.y() = f[2];
|
|
||||||
quat.z() = f[3];
|
|
||||||
return quat;
|
|
||||||
}
|
|
||||||
Transformation getTrafo() {
|
|
||||||
Transformation t;
|
|
||||||
t.pos = getVector3();
|
|
||||||
t.rotation = getMatrix3();
|
|
||||||
t.scale = getFloat();
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
///Read in a string of the given length
|
///Read in a string of the given length
|
||||||
std::string getString(size_t length) {
|
std::string getString(size_t length)
|
||||||
|
{
|
||||||
std::vector<char> str(length + 1, 0);
|
std::vector<char> str(length + 1, 0);
|
||||||
|
|
||||||
inp->read(&str[0], length);
|
inp->read(&str[0], length);
|
||||||
|
@ -165,41 +165,54 @@ public:
|
||||||
return &str[0];
|
return &str[0];
|
||||||
}
|
}
|
||||||
///Read in a string of the length specified in the file
|
///Read in a string of the length specified in the file
|
||||||
std::string getString() {
|
std::string getString()
|
||||||
|
{
|
||||||
size_t size = readLittleEndianType<uint32_t,uint32_t>(inp);
|
size_t size = readLittleEndianType<uint32_t,uint32_t>(inp);
|
||||||
return getString(size);
|
return getString(size);
|
||||||
}
|
}
|
||||||
///This is special since the version string doesn't start with a number, and ends with "\n"
|
///This is special since the version string doesn't start with a number, and ends with "\n"
|
||||||
std::string getVersionString() {
|
std::string getVersionString()
|
||||||
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
std::getline(*inp, result);
|
std::getline(*inp, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getUShorts(std::vector<unsigned short> &vec, size_t size) {
|
void getUShorts(std::vector<unsigned short> &vec, size_t size)
|
||||||
|
{
|
||||||
vec.resize(size);
|
vec.resize(size);
|
||||||
readLittleEndianDynamicBufferOfType<unsigned short,unsigned short>(inp, &vec.front(), size);
|
readLittleEndianDynamicBufferOfType<unsigned short,unsigned short>(inp, &vec.front(), size);
|
||||||
}
|
}
|
||||||
void getFloats(std::vector<float> &vec, size_t size) {
|
|
||||||
|
void getFloats(std::vector<float> &vec, size_t size)
|
||||||
|
{
|
||||||
vec.resize(size);
|
vec.resize(size);
|
||||||
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, &vec.front(), size);
|
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, &vec.front(), size);
|
||||||
}
|
}
|
||||||
void getVector2s(std::vector<osg::Vec2f> &vec, size_t size) {
|
|
||||||
|
void getVector2s(std::vector<osg::Vec2f> &vec, size_t size)
|
||||||
|
{
|
||||||
vec.resize(size);
|
vec.resize(size);
|
||||||
/* The packed storage of each Vec2f is 2 floats exactly */
|
/* The packed storage of each Vec2f is 2 floats exactly */
|
||||||
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp,(float*) &vec.front(), size*2);
|
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp,(float*) &vec.front(), size*2);
|
||||||
}
|
}
|
||||||
void getVector3s(std::vector<osg::Vec3f> &vec, size_t size) {
|
|
||||||
|
void getVector3s(std::vector<osg::Vec3f> &vec, size_t size)
|
||||||
|
{
|
||||||
vec.resize(size);
|
vec.resize(size);
|
||||||
/* The packed storage of each Vec3f is 3 floats exactly */
|
/* The packed storage of each Vec3f is 3 floats exactly */
|
||||||
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, (float*) &vec.front(), size*3);
|
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, (float*) &vec.front(), size*3);
|
||||||
}
|
}
|
||||||
void getVector4s(std::vector<osg::Vec4f> &vec, size_t size) {
|
|
||||||
|
void getVector4s(std::vector<osg::Vec4f> &vec, size_t size)
|
||||||
|
{
|
||||||
vec.resize(size);
|
vec.resize(size);
|
||||||
/* The packed storage of each Vec4f is 4 floats exactly */
|
/* The packed storage of each Vec4f is 4 floats exactly */
|
||||||
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, (float*) &vec.front(), size*4);
|
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, (float*) &vec.front(), size*4);
|
||||||
}
|
}
|
||||||
void getQuaternions(std::vector<osg::Quat> &quat, size_t size) {
|
|
||||||
|
void getQuaternions(std::vector<osg::Quat> &quat, size_t size)
|
||||||
|
{
|
||||||
quat.resize(size);
|
quat.resize(size);
|
||||||
for (size_t i = 0;i < quat.size();i++)
|
for (size_t i = 0;i < quat.size();i++)
|
||||||
quat[i] = getQuaternion();
|
quat[i] = getQuaternion();
|
||||||
|
|
|
@ -34,6 +34,13 @@ btVector3 getbtVector(const osg::Vec3f &v)
|
||||||
return btVector3(v.x(), v.y(), v.z());
|
return btVector3(v.x(), v.y(), v.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pathFileNameStartsWithX(const std::string& path)
|
||||||
|
{
|
||||||
|
const std::size_t slashpos = path.find_last_of("/\\");
|
||||||
|
const std::size_t letterPos = slashpos == std::string::npos ? 0 : slashpos + 1;
|
||||||
|
return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NifBullet
|
namespace NifBullet
|
||||||
|
@ -88,18 +95,10 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr&
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool autogenerated = hasAutoGeneratedCollision(node);
|
bool autogenerated = hasAutoGeneratedCollision(node);
|
||||||
bool isAnimated = false;
|
|
||||||
|
|
||||||
// files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource).
|
// files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource).
|
||||||
// assume all nodes in the file will be animated
|
// assume all nodes in the file will be animated
|
||||||
std::string filename = nif->getFilename();
|
const bool isAnimated = pathFileNameStartsWithX(nif->getFilename());
|
||||||
size_t slashpos = filename.find_last_of("/\\");
|
|
||||||
if (slashpos == std::string::npos)
|
|
||||||
slashpos = 0;
|
|
||||||
if (slashpos+1 < filename.size() && (filename[slashpos+1] == 'x' || filename[slashpos+1] == 'X'))
|
|
||||||
{
|
|
||||||
isAnimated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleNode(node, 0, autogenerated, isAnimated, autogenerated);
|
handleNode(node, 0, autogenerated, isAnimated, autogenerated);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <osgViewer/Viewer>
|
#include <osgViewer/Viewer>
|
||||||
#include <osgViewer/Renderer>
|
#include <osgViewer/Renderer>
|
||||||
|
|
||||||
|
#include <components/myguiplatform/myguidatamanager.hpp>
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -19,7 +21,7 @@ StatsHandler::StatsHandler():
|
||||||
_statsType(false),
|
_statsType(false),
|
||||||
_statsWidth(1280.0f),
|
_statsWidth(1280.0f),
|
||||||
_statsHeight(1024.0f),
|
_statsHeight(1024.0f),
|
||||||
_font("fonts/arial.ttf"),
|
_font(""),
|
||||||
_characterSize(20.0f)
|
_characterSize(20.0f)
|
||||||
{
|
{
|
||||||
_camera = new osg::Camera;
|
_camera = new osg::Camera;
|
||||||
|
@ -28,6 +30,15 @@ StatsHandler::StatsHandler():
|
||||||
_camera->setProjectionResizePolicy(osg::Camera::FIXED);
|
_camera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||||
|
|
||||||
_resourceStatsChildNum = 0;
|
_resourceStatsChildNum = 0;
|
||||||
|
|
||||||
|
_font = osgMyGUI::DataManager::getInstance().getDataPath("DejaVuLGCSansMono.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler::Profiler()
|
||||||
|
{
|
||||||
|
_font = osgMyGUI::DataManager::getInstance().getDataPath("DejaVuLGCSansMono.ttf");
|
||||||
|
|
||||||
|
setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StatsHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
|
bool StatsHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
|
||||||
|
@ -77,7 +88,6 @@ void StatsHandler::setWindowSize(int width, int height)
|
||||||
{
|
{
|
||||||
_camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,_statsHeight-height*_statsWidth/width,_statsHeight));
|
_camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,_statsHeight-height*_statsWidth/width,_statsHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsHandler::toggle(osgViewer::ViewerBase *viewer)
|
void StatsHandler::toggle(osgViewer::ViewerBase *viewer)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef OPENMW_COMPONENTS_RESOURCE_STATS_H
|
#ifndef OPENMW_COMPONENTS_RESOURCE_STATS_H
|
||||||
#define OPENMW_COMPONENTS_RESOURCE_STATS_H
|
#define OPENMW_COMPONENTS_RESOURCE_STATS_H
|
||||||
|
|
||||||
#include <osgGA/GUIEventHandler>
|
#include <osgViewer/ViewerEventHandlers>
|
||||||
|
|
||||||
namespace osgViewer
|
namespace osgViewer
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,11 @@ namespace osg
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
|
class Profiler : public osgViewer::StatsHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Profiler();
|
||||||
|
};
|
||||||
|
|
||||||
class StatsHandler : public osgGA::GUIEventHandler
|
class StatsHandler : public osgGA::GUIEventHandler
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
parse_cmake
|
parse_cmake
|
||||||
sphinx
|
sphinx>=1.7.0
|
||||||
|
|
|
@ -23,7 +23,7 @@ sys.path.insert(0, project_root)
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
#needs_sphinx = '1.0'
|
needs_sphinx = '1.7'
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
@ -34,8 +34,11 @@ extensions = [
|
||||||
'sphinx.ext.todo',
|
'sphinx.ext.todo',
|
||||||
'sphinx.ext.coverage',
|
'sphinx.ext.coverage',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
|
'sphinx.ext.autosectionlabel',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
#autosectionlabel_prefix_document = True
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue