mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 16:45:33 +00:00
Add OpenMW commits up to 30 May 2020
# Conflicts: # CMakeLists.txt # apps/openmw/mwbase/windowmanager.hpp # apps/openmw/mwgui/windowmanagerimp.hpp # apps/openmw/mwmechanics/actors.cpp # apps/openmw/mwmechanics/actors.hpp # apps/openmw/mwscript/interpretercontext.cpp
This commit is contained in:
commit
36a2308acd
109 changed files with 1620 additions and 1778 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -32,6 +32,7 @@ cmake-build-*
|
|||
## qt-creator
|
||||
CMakeLists.txt.user*
|
||||
.vs
|
||||
.vscode
|
||||
|
||||
## resources
|
||||
data
|
||||
|
|
|
@ -6,15 +6,22 @@
|
|||
Bug #3676: NiParticleColorModifier isn't applied properly
|
||||
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||
Bug #5108: Savegame bloating due to inefficient fog textures format
|
||||
Bug #5165: Active spells should use real time intead of timestamps
|
||||
Bug #5358: ForceGreeting always resets the dialogue window completely
|
||||
Bug #5363: Enchantment autocalc not always 0/1
|
||||
Bug #5364: Script fails/stops if trying to startscript an unknown script
|
||||
Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound
|
||||
Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
|
||||
Bug #5370: Opening an unlocked but trapped door uses the key
|
||||
Bug #5397: NPC greeting does not reset if you leave + reenter area
|
||||
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
||||
Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work
|
||||
Bug #5416: Junk non-node records before the root node are not handled gracefully
|
||||
Bug #5424: Creatures do not headtrack player
|
||||
Bug #5425: Poison effect only appears for one frame
|
||||
Bug #5427: GetDistance unknown ID error is misleading
|
||||
Bug #5435: Enemies can't hurt the player when collision is off
|
||||
Bug #5441: Enemies can't push a player character when in critical strike stance
|
||||
Feature #5362: Show the soul gems' trapped soul in count dialog
|
||||
|
||||
0.46.0
|
||||
|
@ -188,8 +195,8 @@
|
|||
Bug #5158: Objects without a name don't fallback to their ID
|
||||
Bug #5159: NiMaterialColorController can only control the diffuse color
|
||||
Bug #5161: Creature companions can't be activated when they are knocked down
|
||||
Bug #5164: Faction owned items handling is incorrect
|
||||
Bug #5163: UserData is not copied during node cloning
|
||||
Bug #5164: Faction owned items handling is incorrect
|
||||
Bug #5166: Scripts still should be executed after player's death
|
||||
Bug #5167: Player can select and cast spells before magic menu is enabled
|
||||
Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
||||
|
|
26
CI/ActivateMSVC.ps1
Normal file
26
CI/ActivateMSVC.ps1
Normal file
|
@ -0,0 +1,26 @@
|
|||
& "${env:COMSPEC}" /c ActivateMSVC.bat "&&" set | ForEach-Object {
|
||||
$name, $value = $_ -split '=', 2
|
||||
Set-Content env:\"$name" $value
|
||||
}
|
||||
|
||||
$MissingTools = $false
|
||||
$tools = "cl", "link", "rc", "mt", "awooga"
|
||||
$descriptions = "MSVC Compiler", "MSVC Linker", "MS Windows Resource Compiler", "MS Windows Manifest Tool", "A made up command"
|
||||
for ($i = 0; $i -lt $tools.Length; $i++) {
|
||||
$present = $true
|
||||
try {
|
||||
Get-Command $tools[$i] *>&1 | Out-Null
|
||||
$present = $present -and $?
|
||||
} catch {
|
||||
$present = $false
|
||||
}
|
||||
if (!$present) {
|
||||
Write-Warning "$($tools[$i]) ($($descriptions[$i])) missing."
|
||||
$MissingTools = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($MissingTools) {
|
||||
Write-Error "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing."
|
||||
exit 1
|
||||
}
|
76
CI/activate_msvc.sh
Normal file
76
CI/activate_msvc.sh
Normal file
|
@ -0,0 +1,76 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
echo "Error: Script not sourced."
|
||||
echo "You must source this script for it to work, i.e. "
|
||||
echo "source ./activate_msvc.sh"
|
||||
echo "or"
|
||||
echo ". ./activate_msvc.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
command -v unixPathAsWindows >/dev/null 2>&1 || function unixPathAsWindows {
|
||||
if command -v cygpath >/dev/null 2>&1; then
|
||||
cygpath -w $1
|
||||
else
|
||||
echo "$1" | sed "s,^/\([^/]\)/,\\1:/," | sed "s,/,\\\\,g"
|
||||
fi
|
||||
}
|
||||
|
||||
function windowsSystemPathAsUnix {
|
||||
if command -v cygpath >/dev/null 2>&1; then
|
||||
cygpath -u -p $1
|
||||
else
|
||||
IFS=';' read -r -a paths <<< "$1"
|
||||
declare -a convertedPaths
|
||||
for entry in paths; do
|
||||
convertedPaths+=(windowsPathAsUnix $entry)
|
||||
done
|
||||
convertedPath=printf ":%s" ${convertedPaths[@]}
|
||||
echo ${convertedPath:1}
|
||||
fi
|
||||
}
|
||||
|
||||
# capture CMD environment so we know what's been changed
|
||||
declare -A originalCmdEnv
|
||||
originalIFS="$IFS"
|
||||
IFS=$'\n\r'
|
||||
for pair in $(cmd //c "set"); do
|
||||
IFS='=' read -r -a separatedPair <<< "${pair}"
|
||||
originalCmdEnv["${separatedPair[0]}"]="${separatedPair[1]}"
|
||||
done
|
||||
|
||||
# capture CMD environment in a shell with MSVC activated
|
||||
cmdEnv="$(cmd //c "$(unixPathAsWindows "$(dirname "${BASH_SOURCE[0]}")")\ActivateMSVC.bat" "&&" set)"
|
||||
|
||||
declare -A cmdEnvChanges
|
||||
for pair in $cmdEnv; do
|
||||
if [ -n "$pair" ]; then
|
||||
IFS='=' read -r -a separatedPair <<< "${pair}"
|
||||
key="${separatedPair[0]}"
|
||||
value="${separatedPair[1]}"
|
||||
if ! [ ${originalCmdEnv[$key]+_} ] || [ "${originalCmdEnv[$key]}" != "$value" ]; then
|
||||
if [ $key != 'PATH' ] && [ $key != 'path' ] && [ $key != 'Path' ]; then
|
||||
export "$key=$value"
|
||||
else
|
||||
export PATH=$(windowsSystemPathAsUnix $value)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
MISSINGTOOLS=0
|
||||
|
||||
command -v cl >/dev/null 2>&1 || { echo "Error: cl (MSVC Compiler) missing."; MISSINGTOOLS=1; }
|
||||
command -v link >/dev/null 2>&1 || { echo "Error: link (MSVC Linker) missing."; MISSINGTOOLS=1; }
|
||||
command -v rc >/dev/null 2>&1 || { echo "Error: rc (MS Windows Resource Compiler) missing."; MISSINGTOOLS=1; }
|
||||
command -v mt >/dev/null 2>&1 || { echo "Error: mt (MS Windows Manifest Tool) missing."; MISSINGTOOLS=1; }
|
||||
|
||||
if [ $MISSINGTOOLS -ne 0 ]; then
|
||||
echo "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing."
|
||||
return 1
|
||||
fi
|
||||
|
||||
IFS="$originalIFS"
|
|
@ -1,25 +1,50 @@
|
|||
#!/bin/bash
|
||||
# set -x # turn-on for debugging
|
||||
|
||||
function wrappedExit {
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
exit $1
|
||||
else
|
||||
return $1
|
||||
fi
|
||||
}
|
||||
|
||||
MISSINGTOOLS=0
|
||||
|
||||
command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; }
|
||||
command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; }
|
||||
command -v python >/dev/null 2>&1 || { echo "Warning: Python is not on the path, automatic Qt installation impossible."; }
|
||||
|
||||
if [ $MISSINGTOOLS -ne 0 ]; then
|
||||
exit 1
|
||||
wrappedExit 1
|
||||
fi
|
||||
|
||||
WORKINGDIR="$(pwd)"
|
||||
case "$WORKINGDIR" in
|
||||
*[[:space:]]*)
|
||||
echo "Error: Working directory contains spaces."
|
||||
exit 1
|
||||
wrappedExit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function windowsPathAsUnix {
|
||||
if command -v cygpath >/dev/null 2>&1; then
|
||||
cygpath -u $1
|
||||
else
|
||||
echo "$1" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,"
|
||||
fi
|
||||
}
|
||||
|
||||
function unixPathAsWindows {
|
||||
if command -v cygpath >/dev/null 2>&1; then
|
||||
cygpath -w $1
|
||||
else
|
||||
echo "$1" | sed "s,^/\([^/]\)/,\\1:/," | sed "s,/,\\\\,g"
|
||||
fi
|
||||
}
|
||||
|
||||
APPVEYOR=${APPVEYOR:-}
|
||||
CI=${CI:-}
|
||||
STEP=${STEP:-}
|
||||
|
@ -32,11 +57,19 @@ KEEP=""
|
|||
UNITY_BUILD=""
|
||||
VS_VERSION=""
|
||||
NMAKE=""
|
||||
NINJA=""
|
||||
PDBS=""
|
||||
PLATFORM=""
|
||||
CONFIGURATION=""
|
||||
TEST_FRAMEWORK=""
|
||||
GOOGLE_INSTALL_ROOT=""
|
||||
INSTALL_PREFIX="."
|
||||
BULLET_DOUBLE=""
|
||||
BULLET_DBL=""
|
||||
BULLET_DBL_DISPLAY="Single precision"
|
||||
|
||||
ACTIVATE_MSVC=""
|
||||
SINGLE_CONFIG=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
ARGSTR=$1
|
||||
|
@ -45,7 +78,7 @@ while [ $# -gt 0 ]; do
|
|||
if [ ${ARGSTR:0:1} != "-" ]; then
|
||||
echo "Unknown argument $ARGSTR"
|
||||
echo "Try '$0 -h'"
|
||||
exit 1
|
||||
wrappedExit 1
|
||||
fi
|
||||
|
||||
for (( i=1; i<${#ARGSTR}; i++ )); do
|
||||
|
@ -57,6 +90,9 @@ while [ $# -gt 0 ]; do
|
|||
d )
|
||||
SKIP_DOWNLOAD=true ;;
|
||||
|
||||
D )
|
||||
BULLET_DOUBLE=true ;;
|
||||
|
||||
e )
|
||||
SKIP_EXTRACT=true ;;
|
||||
|
||||
|
@ -73,10 +109,16 @@ while [ $# -gt 0 ]; do
|
|||
n )
|
||||
NMAKE=true ;;
|
||||
|
||||
N )
|
||||
NINJA=true ;;
|
||||
|
||||
p )
|
||||
PLATFORM=$1
|
||||
shift ;;
|
||||
|
||||
P )
|
||||
PDBS=true ;;
|
||||
|
||||
c )
|
||||
CONFIGURATION=$1
|
||||
shift ;;
|
||||
|
@ -96,6 +138,8 @@ Options:
|
|||
Set the configuration, can also be set with environment variable CONFIGURATION.
|
||||
-d
|
||||
Skip checking the downloads.
|
||||
-D
|
||||
Use double-precision Bullet
|
||||
-e
|
||||
Skip extracting dependencies.
|
||||
-h
|
||||
|
@ -111,25 +155,33 @@ Options:
|
|||
-v <2013/2015/2017/2019>
|
||||
Choose the Visual Studio version to use.
|
||||
-n
|
||||
Produce NMake makefiles instead of a Visual Studio solution.
|
||||
Produce NMake makefiles instead of a Visual Studio solution. Cannout be used with -N.
|
||||
-N
|
||||
Produce Ninja (multi-config if CMake is new enough to support it) files instead of a Visual Studio solution. Cannot be used with -n..
|
||||
-P
|
||||
Download debug symbols where available
|
||||
-V
|
||||
Run verbosely
|
||||
-i
|
||||
CMake install prefix
|
||||
EOF
|
||||
exit 0
|
||||
wrappedExit 0
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "Unknown argument $ARG."
|
||||
echo "Try '$0 -h'"
|
||||
exit 1 ;;
|
||||
wrappedExit 1 ;;
|
||||
esac
|
||||
done
|
||||
done
|
||||
|
||||
if [ -n "$NMAKE" ]; then
|
||||
command -v nmake -? >/dev/null 2>&1 || { echo "Error: nmake (NMake) is not on the path. Make sure you have the necessary environment variables set for command-line C++ development (for example, by starting from a Developer Command Prompt)."; exit 1; }
|
||||
if [ -n "$NMAKE" ] || [ -n "$NINJA" ]; then
|
||||
if [ -n "$NMAKE" ] && [ -n "$NINJA" ]; then
|
||||
echo "Cannout run in NMake and Ninja mode at the same time."
|
||||
wrappedExit 1
|
||||
fi
|
||||
ACTIVATE_MSVC=true
|
||||
fi
|
||||
|
||||
if [ -z $VERBOSE ]; then
|
||||
|
@ -139,7 +191,7 @@ fi
|
|||
if [ -z $APPVEYOR ]; then
|
||||
echo "Running prebuild outside of Appveyor."
|
||||
|
||||
DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
|
||||
DIR=$(windowsPathAsUnix "${BASH_SOURCE[0]}")
|
||||
cd $(dirname "$DIR")/..
|
||||
else
|
||||
echo "Running prebuild in Appveyor."
|
||||
|
@ -264,6 +316,7 @@ case $VS_VERSION in
|
|||
MSVC_REAL_VER="16"
|
||||
MSVC_VER="14.2"
|
||||
MSVC_YEAR="2015"
|
||||
MSVC_REAL_YEAR="2019"
|
||||
MSVC_DISPLAY_YEAR="2019"
|
||||
BOOST_VER="1.71.0"
|
||||
BOOST_VER_URL="1_71_0"
|
||||
|
@ -276,6 +329,7 @@ case $VS_VERSION in
|
|||
MSVC_REAL_VER="15"
|
||||
MSVC_VER="14.1"
|
||||
MSVC_YEAR="2015"
|
||||
MSVC_REAL_YEAR="2017"
|
||||
MSVC_DISPLAY_YEAR="2017"
|
||||
BOOST_VER="1.67.0"
|
||||
BOOST_VER_URL="1_67_0"
|
||||
|
@ -288,6 +342,7 @@ case $VS_VERSION in
|
|||
MSVC_REAL_VER="14"
|
||||
MSVC_VER="14.0"
|
||||
MSVC_YEAR="2015"
|
||||
MSVC_REAL_YEAR="2015"
|
||||
MSVC_DISPLAY_YEAR="2015"
|
||||
BOOST_VER="1.67.0"
|
||||
BOOST_VER_URL="1_67_0"
|
||||
|
@ -295,15 +350,8 @@ case $VS_VERSION in
|
|||
;;
|
||||
|
||||
12|12.0|2013 )
|
||||
GENERATOR="Visual Studio 12 2013"
|
||||
TOOLSET="vc120"
|
||||
MSVC_REAL_VER="12"
|
||||
MSVC_VER="12.0"
|
||||
MSVC_YEAR="2013"
|
||||
MSVC_DISPLAY_YEAR="2013"
|
||||
BOOST_VER="1.58.0"
|
||||
BOOST_VER_URL="1_58_0"
|
||||
BOOST_VER_SDK="105800"
|
||||
echo "Visual Studio 2013 is no longer supported"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -322,7 +370,7 @@ case $PLATFORM in
|
|||
|
||||
* )
|
||||
echo "Unknown platform $PLATFORM."
|
||||
exit 1
|
||||
wrappedExit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -349,9 +397,18 @@ fi
|
|||
|
||||
if [ -n "$NMAKE" ]; then
|
||||
GENERATOR="NMake Makefiles"
|
||||
SINGLE_CONFIG=true
|
||||
fi
|
||||
|
||||
if [ $MSVC_REAL_VER -ge 16 ]; then
|
||||
if [ -n "$NINJA" ]; then
|
||||
GENERATOR="Ninja Multi-Config"
|
||||
if ! cmake -E capabilities | grep -F "$GENERATOR" > /dev/null; then
|
||||
SINGLE_CONFIG=true
|
||||
GENERATOR="Ninja"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $MSVC_REAL_VER -ge 16 ] && [ -z "$NMAKE" ] && [ -z "$NINJA" ]; then
|
||||
if [ $BITS -eq 64 ]; then
|
||||
add_cmake_opts "-G\"$GENERATOR\" -A x64"
|
||||
else
|
||||
|
@ -361,7 +418,7 @@ else
|
|||
add_cmake_opts "-G\"$GENERATOR\""
|
||||
fi
|
||||
|
||||
if [ -n "$NMAKE" ]; then
|
||||
if [ -n "$SINGLE_CONFIG" ]; then
|
||||
add_cmake_opts "-DCMAKE_BUILD_TYPE=${BUILD_CONFIG}"
|
||||
fi
|
||||
|
||||
|
@ -369,6 +426,12 @@ if ! [ -z $UNITY_BUILD ]; then
|
|||
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
|
||||
fi
|
||||
|
||||
if [ -n "$BULLET_DOUBLE" ]; then
|
||||
BULLET_DBL="-double"
|
||||
BULLET_DBL_DISPLAY="Double precision"
|
||||
add_cmake_opts "-DBULLET_USE_DOUBLES=True"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "==================================="
|
||||
echo "Starting prebuild on MSVC${MSVC_DISPLAY_YEAR} WIN${BITS}"
|
||||
|
@ -393,45 +456,54 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
|||
fi
|
||||
|
||||
# Bullet
|
||||
download "Bullet 2.87" \
|
||||
"https://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||
"Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||
download "Bullet 2.89 (${BULLET_DBL_DISPLAY})" \
|
||||
"https://rgw.ctrl-c.liu.se/openmw/Deps/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" \
|
||||
"Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z"
|
||||
|
||||
# FFmpeg
|
||||
download "FFmpeg 3.2.4" \
|
||||
"https://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.2.4-win${BITS}-shared.zip" \
|
||||
"ffmpeg-3.2.4-win${BITS}.zip" \
|
||||
"https://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.2.4-win${BITS}-dev.zip" \
|
||||
"ffmpeg-3.2.4-dev-win${BITS}.zip"
|
||||
download "FFmpeg 4.2.2" \
|
||||
"https://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-4.2.2-win${BITS}-shared.zip" \
|
||||
"ffmpeg-4.2.2-win${BITS}.zip" \
|
||||
"https://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-4.2.2-win${BITS}-dev.zip" \
|
||||
"ffmpeg-4.2.2-dev-win${BITS}.zip"
|
||||
|
||||
# MyGUI
|
||||
download "MyGUI 3.2.2" \
|
||||
"https://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||
"MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||
download "MyGUI 3.4.0" \
|
||||
"https://rgw.ctrl-c.liu.se/openmw/Deps/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" \
|
||||
"MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}.7z"
|
||||
|
||||
if [ -n "$PDBS" ]; then
|
||||
download "MyGUI symbols" \
|
||||
"https://rgw.ctrl-c.liu.se/openmw/Deps/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" \
|
||||
"MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z"
|
||||
fi
|
||||
|
||||
# OpenAL
|
||||
download "OpenAL-Soft 1.19.1" \
|
||||
"http://openal-soft.org/openal-binaries/openal-soft-1.19.1-bin.zip" \
|
||||
"OpenAL-Soft-1.19.1.zip"
|
||||
download "OpenAL-Soft 1.20.1" \
|
||||
"http://openal-soft.org/openal-binaries/openal-soft-1.20.1-bin.zip" \
|
||||
"OpenAL-Soft-1.20.1.zip"
|
||||
|
||||
# OSG
|
||||
download "OpenSceneGraph 3.4.1-scrawl" \
|
||||
"https://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||
"OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||
download "OpenSceneGraph 3.6.5" \
|
||||
"https://rgw.ctrl-c.liu.se/openmw/Deps/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" \
|
||||
"OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}.7z"
|
||||
|
||||
if [ -n "$PDBS" ]; then
|
||||
download "OpenSceneGraph symbols" \
|
||||
"https://rgw.ctrl-c.liu.se/openmw/Deps/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" \
|
||||
"OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z"
|
||||
fi
|
||||
|
||||
# Qt
|
||||
if [ -z $APPVEYOR ]; then
|
||||
if [ $BITS == "64" ]; then
|
||||
QT_SUFFIX="_64"
|
||||
else
|
||||
QT_SUFFIX=""
|
||||
if [ "${MSVC_REAL_YEAR}" = "2015" ] && [ "${BITS}" = "32" ]; then
|
||||
echo "Qt no longer provides MSVC2015 Win32 packages, switch to 64-bit or a newer Visual Studio. Sorry."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
download "Qt 5.7.0" \
|
||||
"https://download.qt.io/new_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" \
|
||||
"https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \
|
||||
"qt-5-install.qs"
|
||||
download "AQt installer" \
|
||||
"https://files.pythonhosted.org/packages/f3/bb/aee972f08deecca31bfc46b5aedfad1ce6c7f3aaf1288d685e4a914b53ac/aqtinstall-0.8-py2.py3-none-any.whl" \
|
||||
"aqtinstall-0.8-py2.py3-none-any.whl"
|
||||
fi
|
||||
|
||||
# SDL2
|
||||
|
@ -456,7 +528,13 @@ cd .. #/..
|
|||
BUILD_DIR="MSVC${MSVC_DISPLAY_YEAR}_${BITS}"
|
||||
|
||||
if [ -n "$NMAKE" ]; then
|
||||
BUILD_DIR="${BUILD_DIR}_NMake_${BUILD_CONFIG}"
|
||||
BUILD_DIR="${BUILD_DIR}_NMake"
|
||||
elif [ -n "$NINJA" ]; then
|
||||
BUILD_DIR="${BUILD_DIR}_Ninja"
|
||||
fi
|
||||
|
||||
if [ -n "$SINGLE_CONFIG" ]; then
|
||||
BUILD_DIR="${BUILD_DIR}_${BUILD_CONFIG}"
|
||||
fi
|
||||
|
||||
if [ -z $KEEP ]; then
|
||||
|
@ -494,10 +572,10 @@ fi
|
|||
# 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,")
|
||||
CWD_DRIVE_ROOT_BASH=$(windowsPathAsUnix "$CWD_DRIVE_ROOT")
|
||||
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;
|
||||
wrappedExit 1;
|
||||
fi
|
||||
|
||||
if [ -d ${BOOST_SDK} ] && grep "BOOST_VERSION ${BOOST_VER_SDK}" Boost/boost/version.hpp > /dev/null; then
|
||||
|
@ -533,15 +611,15 @@ fi
|
|||
cd $DEPS
|
||||
echo
|
||||
# Bullet
|
||||
printf "Bullet 2.87... "
|
||||
printf "Bullet 2.89 (${BULLET_DBL_DISPLAY})... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
if [ -d Bullet ]; then
|
||||
printf -- "Exists. (No version checking) "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf Bullet
|
||||
eval 7z x -y "${DEPS}/Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||
mv "Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}" Bullet
|
||||
eval 7z x -y "${DEPS}/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" $STRIP
|
||||
mv "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}" Bullet
|
||||
fi
|
||||
export BULLET_ROOT="$(real_pwd)/Bullet"
|
||||
echo Done.
|
||||
|
@ -549,21 +627,21 @@ printf "Bullet 2.87... "
|
|||
cd $DEPS
|
||||
echo
|
||||
# FFmpeg
|
||||
printf "FFmpeg 3.2.4... "
|
||||
printf "FFmpeg 4.2.2... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
if [ -d FFmpeg ] && grep "FFmpeg version: 3.2.4" FFmpeg/README.txt > /dev/null; then
|
||||
if [ -d FFmpeg ] && grep "4.2.2" FFmpeg/README.txt > /dev/null; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
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-dev-win${BITS}.zip" $STRIP
|
||||
mv "ffmpeg-3.2.4-win${BITS}-shared" FFmpeg
|
||||
cp -r "ffmpeg-3.2.4-win${BITS}-dev/"* FFmpeg/
|
||||
rm -rf "ffmpeg-3.2.4-win${BITS}-dev"
|
||||
eval 7z x -y "${DEPS}/ffmpeg-4.2.2-win${BITS}.zip" $STRIP
|
||||
eval 7z x -y "${DEPS}/ffmpeg-4.2.2-dev-win${BITS}.zip" $STRIP
|
||||
mv "ffmpeg-4.2.2-win${BITS}-shared" FFmpeg
|
||||
cp -r "ffmpeg-4.2.2-win${BITS}-dev/"* FFmpeg/
|
||||
rm -rf "ffmpeg-4.2.2-win${BITS}-dev"
|
||||
fi
|
||||
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-58,avformat-58,avutil-56,swresample-3,swscale-5}.dll
|
||||
if [ $BITS -eq 32 ]; then
|
||||
add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\""
|
||||
fi
|
||||
|
@ -572,62 +650,66 @@ printf "FFmpeg 3.2.4... "
|
|||
cd $DEPS
|
||||
echo
|
||||
# MyGUI
|
||||
printf "MyGUI 3.2.2... "
|
||||
printf "MyGUI 3.4.0... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
if [ -d MyGUI ] && \
|
||||
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||
grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null
|
||||
grep "MYGUI_VERSION_MINOR 4" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||
grep "MYGUI_VERSION_PATCH 0" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null
|
||||
then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf MyGUI
|
||||
eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||
mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI
|
||||
eval 7z x -y "${DEPS}/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" $STRIP
|
||||
[ -n "$PDBS" ] && eval 7z x -y "${DEPS}/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" $STRIP
|
||||
mv "MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}" MyGUI
|
||||
fi
|
||||
export MYGUI_HOME="$(real_pwd)/MyGUI"
|
||||
if [ $CONFIGURATION == "Debug" ]; then
|
||||
SUFFIX="_d"
|
||||
MYGUI_CONFIGURATION="Debug"
|
||||
else
|
||||
SUFFIX=""
|
||||
MYGUI_CONFIGURATION="RelWithDebInfo"
|
||||
fi
|
||||
add_runtime_dlls "$(pwd)/MyGUI/bin/${CONFIGURATION}/MyGUIEngine${SUFFIX}.dll"
|
||||
add_runtime_dlls "$(pwd)/MyGUI/bin/${MYGUI_CONFIGURATION}/MyGUIEngine${SUFFIX}.dll"
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
# OpenAL
|
||||
printf "OpenAL-Soft 1.19.1... "
|
||||
printf "OpenAL-Soft 1.20.1... "
|
||||
{
|
||||
if [ -d openal-soft-1.19.1-bin ]; then
|
||||
if [ -d openal-soft-1.20.1-bin ]; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf openal-soft-1.19.1-bin
|
||||
eval 7z x -y OpenAL-Soft-1.19.1.zip $STRIP
|
||||
rm -rf openal-soft-1.20.1-bin
|
||||
eval 7z x -y OpenAL-Soft-1.20.1.zip $STRIP
|
||||
fi
|
||||
OPENAL_SDK="$(real_pwd)/openal-soft-1.19.1-bin"
|
||||
OPENAL_SDK="$(real_pwd)/openal-soft-1.20.1-bin"
|
||||
add_cmake_opts -DOPENAL_INCLUDE_DIR="${OPENAL_SDK}/include/AL" \
|
||||
-DOPENAL_LIBRARY="${OPENAL_SDK}/libs/Win${BITS}/OpenAL32.lib"
|
||||
add_runtime_dlls "$(pwd)/openal-soft-1.19.1-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll"
|
||||
add_runtime_dlls "$(pwd)/openal-soft-1.20.1-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll"
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
# OSG
|
||||
printf "OSG 3.4.1-scrawl... "
|
||||
printf "OSG 3.6.5... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
if [ -d OSG ] && \
|
||||
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
||||
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
|
||||
grep "OPENSCENEGRAPH_PATCH_VERSION 1" OSG/include/osg/Version > /dev/null
|
||||
grep "OPENSCENEGRAPH_MINOR_VERSION 6" OSG/include/osg/Version > /dev/null && \
|
||||
grep "OPENSCENEGRAPH_PATCH_VERSION 5" OSG/include/osg/Version > /dev/null
|
||||
then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf OSG
|
||||
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
|
||||
eval 7z x -y "${DEPS}/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" $STRIP
|
||||
[ -n "$PDBS" ] && eval 7z x -y "${DEPS}/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" $STRIP
|
||||
mv "OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}" OSG
|
||||
fi
|
||||
OSG_SDK="$(real_pwd)/OSG"
|
||||
add_cmake_opts -DOSG_DIR="$OSG_SDK"
|
||||
|
@ -636,17 +718,17 @@ printf "OSG 3.4.1-scrawl... "
|
|||
else
|
||||
SUFFIX=""
|
||||
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,Shadow}${SUFFIX}.dll
|
||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,freetype,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,shadow}${SUFFIX}.dll
|
||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.6.5/osgdb_"{bmp,dds,freetype,jpeg,osg,png,tga}${SUFFIX}.dll
|
||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.6.5/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
# Qt
|
||||
if [ -z $APPVEYOR ]; then
|
||||
printf "Qt 5.7.0... "
|
||||
printf "Qt 5.15.0... "
|
||||
else
|
||||
printf "Qt 5.13 AppVeyor... "
|
||||
fi
|
||||
|
@ -658,21 +740,44 @@ fi
|
|||
fi
|
||||
if [ -z $APPVEYOR ]; then
|
||||
cd $DEPS_INSTALL
|
||||
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
|
||||
QT_SDK="$(real_pwd)/Qt/5.15.0/msvc${MSVC_REAL_YEAR}${SUFFIX}"
|
||||
|
||||
if [ -d 'Qt/5.15.0' ]; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf Qt
|
||||
cp "${DEPS}/qt-5-install.qs" 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
|
||||
printf -- "(Installation might take a while) "
|
||||
"${DEPS}/qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" --script qt-install.qs --silent
|
||||
mv qt-install.qs Qt/
|
||||
echo Done.
|
||||
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}
|
||||
pushd "$DEPS" > /dev/null
|
||||
if ! [ -d 'aqt-venv' ]; then
|
||||
echo " Creating Virtualenv for aqt..."
|
||||
eval python -m venv aqt-venv $STRIP
|
||||
fi
|
||||
if [ -d 'aqt-venv/bin' ]; then
|
||||
VENV_BIN_DIR='bin'
|
||||
elif [ -d 'aqt-venv/Scripts' ]; then
|
||||
VENV_BIN_DIR='Scripts'
|
||||
else
|
||||
echo "Error: Failed to create virtualenv."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -e "aqt-venv/${VENV_BIN_DIR}/aqt" ]; then
|
||||
echo " Installing aqt wheel into virtualenv..."
|
||||
eval "aqt-venv/${VENV_BIN_DIR}/pip" install aqtinstall-0.8-py2.py3-none-any.whl $STRIP
|
||||
fi
|
||||
popd > /dev/null
|
||||
|
||||
rm -rf Qt
|
||||
|
||||
mkdir Qt
|
||||
cd Qt
|
||||
|
||||
eval "${DEPS}/aqt-venv/${VENV_BIN_DIR}/aqt" install 5.15.0 windows desktop "win${BITS}_msvc${MSVC_REAL_YEAR}${SUFFIX}" $STRIP
|
||||
|
||||
printf " Cleaning up extraneous data... "
|
||||
rm -rf Qt/{aqtinstall.log,Tools}
|
||||
|
||||
echo Done.
|
||||
fi
|
||||
|
||||
cd $QT_SDK
|
||||
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
||||
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
||||
|
@ -695,7 +800,7 @@ fi
|
|||
else
|
||||
SUFFIX=""
|
||||
fi
|
||||
DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
|
||||
DIR=$(windowsPathAsUnix "${QT_SDK}")
|
||||
add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
||||
add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll"
|
||||
echo Done.
|
||||
|
@ -806,14 +911,15 @@ fi
|
|||
#if [ -z $CI ]; then
|
||||
echo "- Copying Runtime DLLs..."
|
||||
DLL_PREFIX=""
|
||||
if [ -z $NMAKE ]; then
|
||||
if [ -z $SINGLE_CONFIG ]; then
|
||||
mkdir -p $BUILD_CONFIG
|
||||
DLL_PREFIX="$BUILD_CONFIG/"
|
||||
fi
|
||||
for DLL in $RUNTIME_DLLS; do
|
||||
TARGET="$(basename "$DLL")"
|
||||
if [[ "$DLL" == *":"* ]]; then
|
||||
IFS=':'; SPLIT=( ${DLL} ); unset IFS
|
||||
originalIFS="$IFS"
|
||||
IFS=':'; SPLIT=( ${DLL} ); IFS=$originalIFS
|
||||
DLL=${SPLIT[0]}
|
||||
TARGET=${SPLIT[1]}
|
||||
fi
|
||||
|
@ -822,10 +928,10 @@ fi
|
|||
done
|
||||
echo
|
||||
echo "- OSG Plugin DLLs..."
|
||||
mkdir -p ${DLL_PREFIX}osgPlugins-3.4.1
|
||||
mkdir -p ${DLL_PREFIX}osgPlugins-3.6.5
|
||||
for DLL in $OSG_PLUGINS; do
|
||||
echo " $(basename $DLL)."
|
||||
cp "$DLL" ${DLL_PREFIX}osgPlugins-3.4.1
|
||||
cp "$DLL" ${DLL_PREFIX}osgPlugins-3.6.5
|
||||
done
|
||||
echo
|
||||
echo "- Qt Platform DLLs..."
|
||||
|
@ -836,6 +942,42 @@ fi
|
|||
done
|
||||
echo
|
||||
#fi
|
||||
|
||||
if ! [ -z $ACTIVATE_MSVC ]; then
|
||||
echo -n "- Activating MSVC in the current shell... "
|
||||
command -v vswhere >/dev/null 2>&1 || { echo "Error: vswhere is not on the path."; wrappedExit 1; }
|
||||
|
||||
MSVC_INSTALLATION_PATH=$(vswhere -legacy -version "[$MSVC_VER,$(awk "BEGIN { print $MSVC_REAL_VER + 1; exit }"))" -property installationPath)
|
||||
if [ $MSVC_REAL_VER -ge 15 ]; then
|
||||
echo "@\"${MSVC_INSTALLATION_PATH}\Common7\Tools\VsDevCmd.bat\" -no_logo -arch=$([ $BITS -eq 64 ] && echo "amd64" || echo "x86") -host_arch=$([ $(uname -m) == 'x86_64' ] && echo "amd64" || echo "x86")" > ActivateMSVC.bat
|
||||
else
|
||||
if [ $(uname -m) == 'x86_64' ]; then
|
||||
if [ $BITS -eq 64 ]; then
|
||||
compiler=amd64
|
||||
else
|
||||
compiler=amd64_x86
|
||||
fi
|
||||
else
|
||||
if [ $BITS -eq 64 ]; then
|
||||
compiler=x86_amd64
|
||||
else
|
||||
compiler=x86
|
||||
fi
|
||||
fi
|
||||
echo "@\"${MSVC_INSTALLATION_PATH}\VC\vcvarsall.bat\" $compiler" > ActivateMSVC.bat
|
||||
fi
|
||||
|
||||
cp "../CI/activate_msvc.sh" .
|
||||
sed -i "s/\$MSVC_DISPLAY_YEAR/$MSVC_DISPLAY_YEAR/g" activate_msvc.sh
|
||||
source ./activate_msvc.sh
|
||||
|
||||
cp "../CI/ActivateMSVC.ps1" .
|
||||
sed -i "s/\$MSVC_DISPLAY_YEAR/$MSVC_DISPLAY_YEAR/g" ActivateMSVC.ps1
|
||||
|
||||
echo "done."
|
||||
echo
|
||||
fi
|
||||
|
||||
if [ -z $VERBOSE ]; then
|
||||
printf -- "- Configuring... "
|
||||
else
|
||||
|
@ -846,8 +988,34 @@ RET=$?
|
|||
if [ -z $VERBOSE ]; then
|
||||
if [ $RET -eq 0 ]; then
|
||||
echo Done.
|
||||
if [ -n $ACTIVATE_MSVC ]; then
|
||||
echo
|
||||
echo "Note: you must manually activate MSVC for the shell in which you want to do the build."
|
||||
echo
|
||||
echo "Some scripts have been created in the build directory to do so in an existing shell."
|
||||
echo "Bash: source activate_msvc.sh"
|
||||
echo "CMD: ActivateMSVC.bat"
|
||||
echo "PowerShell: ActivateMSVC.ps1"
|
||||
echo
|
||||
echo "You may find options to launch a Development/Native Tools/Cross Tools shell in your start menu or Visual Studio."
|
||||
echo
|
||||
if [ $(uname -m) == 'x86_64' ]; then
|
||||
if [ $BITS -eq 64 ]; then
|
||||
inheritEnvironments=msvc_x64_x64
|
||||
else
|
||||
inheritEnvironments=msvc_x64
|
||||
fi
|
||||
else
|
||||
if [ $BITS -eq 64 ]; then
|
||||
inheritEnvironments=msvc_x86_x64
|
||||
else
|
||||
inheritEnvironments=msvc_x86
|
||||
fi
|
||||
fi
|
||||
echo "In Visual Studio 15.3 (2017 Update 3) or later, try setting '\"inheritEnvironments\": [ \"$inheritEnvironments\" ]' in CMakeSettings.json to build in the IDE."
|
||||
fi
|
||||
else
|
||||
echo Failed.
|
||||
fi
|
||||
fi
|
||||
exit $RET
|
||||
wrappedExit $RET
|
||||
|
|
|
@ -11,6 +11,7 @@ option(BUILD_NIFTEST "Build nif file tester" ON)
|
|||
option(BUILD_DOCS "Build documentation." OFF )
|
||||
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
||||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
||||
option(BULLET_USE_DOUBLES "Use double precision for Bullet" OFF)
|
||||
option(BUILD_OPENMW_MP "Build OpenMW-MP" ON)
|
||||
option(BUILD_BROWSER "Build tes3mp Server Browser" ON)
|
||||
option(BUILD_MASTER "Build tes3mp Master Server" OFF)
|
||||
|
|
|
@ -15,6 +15,10 @@ set(GAME_HEADER
|
|||
engine.hpp
|
||||
)
|
||||
|
||||
if (BULLET_USE_DOUBLES)
|
||||
add_definitions(-DBT_USE_DOUBLE_PRECISION)
|
||||
endif()
|
||||
|
||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
|
@ -41,7 +45,7 @@ add_openmw_dir (mwgui
|
|||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
||||
draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation
|
||||
draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "engine.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
|
@ -270,7 +271,7 @@ bool OMW::Engine::frame(float frametime)
|
|||
osg::Timer_t afterWorldTick = osg::Timer::instance()->tick();
|
||||
|
||||
// update GUI
|
||||
mEnvironment.getWindowManager()->onFrame(frametime);
|
||||
mEnvironment.getWindowManager()->update(frametime);
|
||||
|
||||
unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
||||
osg::Stats* stats = mViewer->getViewerStats();
|
||||
|
@ -292,12 +293,14 @@ bool OMW::Engine::frame(float frametime)
|
|||
|
||||
if (stats->collectStats("resource"))
|
||||
{
|
||||
stats->setAttribute(frameNumber, "FrameNumber", frameNumber);
|
||||
|
||||
mResourceSystem->reportStats(frameNumber, stats);
|
||||
|
||||
stats->setAttribute(frameNumber, "WorkQueue", mWorkQueue->getNumItems());
|
||||
stats->setAttribute(frameNumber, "WorkThread", mWorkQueue->getNumActiveThreads());
|
||||
|
||||
mEnvironment.getWorld()->getNavigator()->reportStats(frameNumber, *stats);
|
||||
mEnvironment.reportStats(frameNumber, *stats);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -891,6 +894,14 @@ void OMW::Engine::go()
|
|||
mEnvironment.getWindowManager()->executeInConsole(mStartupScript);
|
||||
}
|
||||
|
||||
std::ofstream stats;
|
||||
if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE"))
|
||||
{
|
||||
stats.open(path, std::ios_base::out);
|
||||
if (!stats)
|
||||
Log(Debug::Warning) << "Failed to open file for stats: " << path;
|
||||
}
|
||||
|
||||
// Start the main rendering loop
|
||||
osg::Timer frameTimer;
|
||||
double simulationTime = 0.0;
|
||||
|
@ -933,6 +944,12 @@ void OMW::Engine::go()
|
|||
simulationTime += dt;
|
||||
}
|
||||
|
||||
if (stats)
|
||||
{
|
||||
const auto frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
||||
mViewer->getViewerStats()->report(stats, frameNumber);
|
||||
}
|
||||
|
||||
mEnvironment.limitFrameRate(frameTimer.time_s());
|
||||
}
|
||||
|
||||
|
|
|
@ -198,3 +198,9 @@ const MWBase::Environment& MWBase::Environment::get()
|
|||
assert (sThis);
|
||||
return *sThis;
|
||||
}
|
||||
|
||||
void MWBase::Environment::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||
{
|
||||
mMechanicsManager->reportStats(frameNumber, stats);
|
||||
mWorld->reportStats(frameNumber, stats);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
#ifndef GAME_BASE_ENVIRONMENT_H
|
||||
#define GAME_BASE_ENVIRONMENT_H
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Stats;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
class World;
|
||||
|
@ -97,6 +102,8 @@ namespace MWBase
|
|||
|
||||
static const Environment& get();
|
||||
///< Return instance of this class.
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,8 @@ namespace MWBase
|
|||
virtual void resetIdleTime() = 0;
|
||||
|
||||
virtual void executeAction(int action) = 0;
|
||||
|
||||
virtual bool controlsDisabled() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
#include <set>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
// For MWMechanics::GreetingState
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Stats;
|
||||
class Vec3f;
|
||||
}
|
||||
|
||||
|
@ -300,6 +304,13 @@ namespace MWBase
|
|||
virtual bool isAttackPreparing(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual bool isRunning(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;
|
||||
|
||||
virtual int getGreetingTimer(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -327,13 +327,7 @@ namespace MWBase
|
|||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
virtual void onFrame (float frameDuration) = 0;
|
||||
|
||||
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
|
||||
virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues() = 0;
|
||||
virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues() = 0;
|
||||
virtual SkillList getPlayerMinorSkills() = 0;
|
||||
virtual SkillList getPlayerMajorSkills() = 0;
|
||||
virtual void update (float duration) = 0;
|
||||
|
||||
/**
|
||||
* Fetches a GMST string from the store, if there is no setting with the given
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace osg
|
|||
class Matrixf;
|
||||
class Quat;
|
||||
class Image;
|
||||
class Stats;
|
||||
}
|
||||
|
||||
namespace Loading
|
||||
|
@ -831,6 +832,8 @@ namespace MWBase
|
|||
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
|
||||
|
||||
virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const = 0;
|
||||
|
||||
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -105,23 +105,32 @@ namespace MWGui
|
|||
mGenerateClassSpecializations[0] = 0;
|
||||
mGenerateClassSpecializations[1] = 0;
|
||||
mGenerateClassSpecializations[2] = 0;
|
||||
|
||||
// Setup player stats
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
mPlayerAttributes.emplace(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue());
|
||||
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
mPlayerSkillValues.emplace(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue());
|
||||
}
|
||||
|
||||
void CharacterCreation::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
|
||||
{
|
||||
if (mReviewDialog)
|
||||
{
|
||||
static const char *ids[] =
|
||||
{
|
||||
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5",
|
||||
"AttribVal6", "AttribVal7", "AttribVal8",
|
||||
0
|
||||
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4",
|
||||
"AttribVal5", "AttribVal6", "AttribVal7", "AttribVal8", 0
|
||||
};
|
||||
|
||||
for (int i=0; ids[i]; ++i)
|
||||
{
|
||||
if (ids[i]==id)
|
||||
mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value);
|
||||
{
|
||||
mPlayerAttributes[static_cast<ESM::Attribute::AttributeID>(i)] = value;
|
||||
if (mReviewDialog)
|
||||
mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID>(i), value);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +156,7 @@ namespace MWGui
|
|||
|
||||
void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
||||
{
|
||||
mPlayerSkillValues[parSkill] = value;
|
||||
if (mReviewDialog)
|
||||
mReviewDialog->setSkillValue(parSkill, value);
|
||||
}
|
||||
|
@ -155,6 +165,9 @@ namespace MWGui
|
|||
{
|
||||
if (mReviewDialog)
|
||||
mReviewDialog->configureSkills(major, minor);
|
||||
|
||||
mPlayerMajorSkills = major;
|
||||
mPlayerMinorSkills = minor;
|
||||
}
|
||||
|
||||
void CharacterCreation::onFrame(float duration)
|
||||
|
@ -269,31 +282,21 @@ namespace MWGui
|
|||
mReviewDialog->setClass(*playerClass);
|
||||
mReviewDialog->setBirthSign(player.getBirthSign());
|
||||
|
||||
{
|
||||
MWWorld::Ptr playerPtr = MWMechanics::getPlayer();
|
||||
const MWMechanics::CreatureStats& stats = playerPtr.getClass().getCreatureStats(playerPtr);
|
||||
|
||||
mReviewDialog->setHealth(stats.getHealth());
|
||||
mReviewDialog->setMagicka(stats.getMagicka());
|
||||
mReviewDialog->setFatigue(stats.getFatigue());
|
||||
}
|
||||
|
||||
{
|
||||
std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
|
||||
for (auto& attributePair : attributes)
|
||||
for (auto& attributePair : mPlayerAttributes)
|
||||
{
|
||||
mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (attributePair.first), attributePair.second);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
|
||||
for (auto& skillPair : skills)
|
||||
for (auto& skillPair : mPlayerSkillValues)
|
||||
{
|
||||
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (skillPair.first), skillPair.second);
|
||||
}
|
||||
mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills());
|
||||
}
|
||||
mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills);
|
||||
|
||||
mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
|
||||
mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/loadclas.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
|
@ -56,6 +57,10 @@ namespace MWGui
|
|||
osg::Group* mParent;
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
|
||||
SkillList mPlayerMajorSkills, mPlayerMinorSkills;
|
||||
std::map<int, MWMechanics::AttributeValue> mPlayerAttributes;
|
||||
std::map<int, MWMechanics::SkillValue> mPlayerSkillValues;
|
||||
|
||||
//Dialogs
|
||||
TextInputDialog* mNameDialog;
|
||||
RaceDialog* mRaceDialog;
|
||||
|
|
36
apps/openmw/mwgui/textcolours.cpp
Normal file
36
apps/openmw/mwgui/textcolours.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "textcolours.hpp"
|
||||
|
||||
#include <MyGUI_LanguageManager.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
MyGUI::Colour getTextColour(const std::string& type)
|
||||
{
|
||||
return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}"));
|
||||
}
|
||||
|
||||
void TextColours::loadColours()
|
||||
{
|
||||
header = getTextColour("header");
|
||||
normal = getTextColour("normal");
|
||||
notify = getTextColour("notify");
|
||||
|
||||
link = getTextColour("link");
|
||||
linkOver = getTextColour("link_over");
|
||||
linkPressed = getTextColour("link_pressed");
|
||||
|
||||
answer = getTextColour("answer");
|
||||
answerOver = getTextColour("answer_over");
|
||||
answerPressed = getTextColour("answer_pressed");
|
||||
|
||||
journalLink = getTextColour("journal_link");
|
||||
journalLinkOver = getTextColour("journal_link_over");
|
||||
journalLinkPressed = getTextColour("journal_link_pressed");
|
||||
|
||||
journalTopic = getTextColour("journal_topic");
|
||||
journalTopicOver = getTextColour("journal_topic_over");
|
||||
journalTopicPressed = getTextColour("journal_topic_pressed");
|
||||
}
|
||||
}
|
|
@ -5,14 +5,12 @@
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
struct TextColours
|
||||
{
|
||||
MyGUI::Colour header;
|
||||
MyGUI::Colour normal;
|
||||
MyGUI::Colour notify;
|
||||
|
||||
|
||||
MyGUI::Colour link;
|
||||
MyGUI::Colour linkOver;
|
||||
MyGUI::Colour linkPressed;
|
||||
|
@ -28,6 +26,9 @@ namespace MWGui
|
|||
MyGUI::Colour journalTopic;
|
||||
MyGUI::Colour journalTopicOver;
|
||||
MyGUI::Colour journalTopicPressed;
|
||||
|
||||
public:
|
||||
void loadColours();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -443,6 +443,9 @@ namespace MWGui
|
|||
// constant effects have no duration and no target
|
||||
if (!mEffectParams.mIsConstant)
|
||||
{
|
||||
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce))
|
||||
mEffectParams.mDuration = std::max(1, mEffectParams.mDuration);
|
||||
|
||||
if (mEffectParams.mDuration > 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
{
|
||||
spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + MyGUI::utility::toString(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs);
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include <MyGUI_ClipboardManager.h>
|
||||
#include <MyGUI_WidgetManager.h>
|
||||
|
||||
// For BT_NO_PROFILE
|
||||
#include <LinearMath/btQuickprof.h>
|
||||
|
||||
#include <SDL_keyboard.h>
|
||||
#include <SDL_clipboard.h>
|
||||
|
||||
|
@ -126,19 +129,8 @@
|
|||
#include "keyboardnavigation.hpp"
|
||||
#include "resourceskin.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
MyGUI::Colour getTextColour(const std::string& type)
|
||||
{
|
||||
return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
WindowManager::WindowManager(
|
||||
SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
|
||||
|
@ -191,12 +183,6 @@ namespace MWGui
|
|||
, mCursorVisible(true)
|
||||
, mCursorActive(false)
|
||||
, mPlayerBounty(-1)
|
||||
, mPlayerName()
|
||||
, mPlayerRaceId()
|
||||
, mPlayerAttributes()
|
||||
, mPlayerMajorSkills()
|
||||
, mPlayerMinorSkills()
|
||||
, mPlayerSkillValues()
|
||||
, mGui(nullptr)
|
||||
, mGuiModes()
|
||||
, mCursorManager(nullptr)
|
||||
|
@ -207,7 +193,6 @@ namespace MWGui
|
|||
, mRestAllowed(true)
|
||||
, mShowOwned(0)
|
||||
, mEncoding(encoding)
|
||||
, mFontHeight(16)
|
||||
, mVersionDescription(versionDescription)
|
||||
, mWindowVisible(true)
|
||||
{
|
||||
|
@ -245,13 +230,6 @@ namespace MWGui
|
|||
SpellView::registerComponents();
|
||||
Gui::registerAllWidgets();
|
||||
|
||||
int fontSize = Settings::Manager::getInt("font size", "GUI");
|
||||
fontSize = std::min(std::max(12, fontSize), 20);
|
||||
mFontHeight = fontSize;
|
||||
|
||||
MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource");
|
||||
MyGUI::ResourceManager::getInstance().registerLoadXmlDelegate("Resource") = newDelegate(this, &WindowManager::loadFontDelegate);
|
||||
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Controllers::ControllerFollowMouse>("Controller");
|
||||
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
|
||||
|
@ -308,94 +286,6 @@ namespace MWGui
|
|||
Settings::Manager::getFloat("contrast", "Video"));
|
||||
}
|
||||
|
||||
void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version)
|
||||
{
|
||||
MyGUI::xml::ElementEnumerator resourceNode = _node->getElementEnumerator();
|
||||
bool createCopy = false;
|
||||
while (resourceNode.next("Resource"))
|
||||
{
|
||||
std::string type, name;
|
||||
resourceNode->findAttribute("type", type);
|
||||
resourceNode->findAttribute("name", name);
|
||||
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont"))
|
||||
{
|
||||
createCopy = true;
|
||||
|
||||
// For TrueType fonts we should override Size and Resolution properties
|
||||
// to allow to configure font size via config file, without need to edit XML files.
|
||||
// Also we should take UI scaling factor in account.
|
||||
int resolution = Settings::Manager::getInt("ttf resolution", "GUI");
|
||||
resolution = std::min(960, std::max(48, resolution));
|
||||
|
||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||
resolution *= uiScale;
|
||||
|
||||
MyGUI::xml::ElementPtr resolutionNode = resourceNode->createChild("Property");
|
||||
resolutionNode->addAttribute("key", "Resolution");
|
||||
resolutionNode->addAttribute("value", std::to_string(resolution));
|
||||
|
||||
MyGUI::xml::ElementPtr sizeNode = resourceNode->createChild("Property");
|
||||
sizeNode->addAttribute("key", "Size");
|
||||
sizeNode->addAttribute("value", std::to_string(mFontHeight));
|
||||
}
|
||||
else if (Misc::StringUtils::ciEqual(type, "ResourceSkin") ||
|
||||
Misc::StringUtils::ciEqual(type, "AutoSizedResourceSkin"))
|
||||
{
|
||||
// We should adjust line height for MyGUI widgets depending on font size
|
||||
MyGUI::xml::ElementPtr heightNode = resourceNode->createChild("Property");
|
||||
heightNode->addAttribute("key", "HeightLine");
|
||||
heightNode->addAttribute("value", std::to_string(mFontHeight+2));
|
||||
}
|
||||
}
|
||||
|
||||
MyGUI::ResourceManager::getInstance().loadFromXmlNode(_node, _file, _version);
|
||||
|
||||
if (createCopy)
|
||||
{
|
||||
MyGUI::xml::ElementPtr copy = _node->createCopy();
|
||||
|
||||
MyGUI::xml::ElementEnumerator copyFont = copy->getElementEnumerator();
|
||||
while (copyFont.next("Resource"))
|
||||
{
|
||||
std::string type, name;
|
||||
copyFont->findAttribute("type", type);
|
||||
copyFont->findAttribute("name", name);
|
||||
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont"))
|
||||
{
|
||||
// Since the journal and books use the custom scaling factor depending on resolution,
|
||||
// setup separate fonts with different Resolution to fit these windows.
|
||||
// These fonts have an internal prefix.
|
||||
int resolution = Settings::Manager::getInt("ttf resolution", "GUI");
|
||||
resolution = std::min(960, std::max(48, resolution));
|
||||
|
||||
float currentX = Settings::Manager::getInt("resolution x", "Video");
|
||||
float currentY = Settings::Manager::getInt("resolution y", "Video");
|
||||
// TODO: read size from openmw_layout.xml
|
||||
float heightScale = (currentY / 520);
|
||||
float widthScale = (currentX / 600);
|
||||
float uiScale = std::min(widthScale, heightScale);
|
||||
resolution *= uiScale;
|
||||
|
||||
MyGUI::xml::ElementPtr resolutionNode = copyFont->createChild("Property");
|
||||
resolutionNode->addAttribute("key", "Resolution");
|
||||
resolutionNode->addAttribute("value", std::to_string(resolution));
|
||||
|
||||
copyFont->setAttribute("name", "Journalbook " + name);
|
||||
}
|
||||
}
|
||||
|
||||
MyGUI::ResourceManager::getInstance().loadFromXmlNode(copy, _file, _version);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::loadUserFonts()
|
||||
{
|
||||
mFontLoader->loadTrueTypeFonts();
|
||||
|
@ -407,26 +297,7 @@ namespace MWGui
|
|||
int w = MyGUI::RenderManager::getInstance().getViewSize().width;
|
||||
int h = MyGUI::RenderManager::getInstance().getViewSize().height;
|
||||
|
||||
mTextColours.header = getTextColour("header");
|
||||
mTextColours.normal = getTextColour("normal");
|
||||
mTextColours.notify = getTextColour("notify");
|
||||
|
||||
mTextColours.link = getTextColour("link");
|
||||
mTextColours.linkOver = getTextColour("link_over");
|
||||
mTextColours.linkPressed = getTextColour("link_pressed");
|
||||
|
||||
mTextColours.answer = getTextColour("answer");
|
||||
mTextColours.answerOver = getTextColour("answer_over");
|
||||
mTextColours.answerPressed = getTextColour("answer_pressed");
|
||||
|
||||
mTextColours.journalLink = getTextColour("journal_link");
|
||||
mTextColours.journalLinkOver = getTextColour("journal_link_over");
|
||||
mTextColours.journalLinkPressed = getTextColour("journal_link_pressed");
|
||||
|
||||
mTextColours.journalTopic = getTextColour("journal_topic");
|
||||
mTextColours.journalTopicOver = getTextColour("journal_topic_over");
|
||||
mTextColours.journalTopicPressed = getTextColour("journal_topic_pressed");
|
||||
|
||||
mTextColours.loadColours();
|
||||
|
||||
mDragAndDrop = new DragAndDrop();
|
||||
|
||||
|
@ -612,17 +483,6 @@ namespace MWGui
|
|||
|
||||
mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem);
|
||||
|
||||
// Setup player stats
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
{
|
||||
mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
{
|
||||
mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue()));
|
||||
}
|
||||
|
||||
updatePinnedWindows();
|
||||
|
||||
// Set up visibility
|
||||
|
@ -631,7 +491,7 @@ namespace MWGui
|
|||
|
||||
int WindowManager::getFontHeight() const
|
||||
{
|
||||
return mFontHeight;
|
||||
return mFontLoader->getFontHeight();
|
||||
}
|
||||
|
||||
void WindowManager::setNewGame(bool newgame)
|
||||
|
@ -652,7 +512,6 @@ namespace MWGui
|
|||
{
|
||||
mKeyboardNavigation.reset();
|
||||
|
||||
MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource");
|
||||
MyGUI::LanguageManager::getInstance().eventRequestTag.clear();
|
||||
MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear();
|
||||
MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear();
|
||||
|
@ -824,32 +683,7 @@ namespace MWGui
|
|||
{
|
||||
mStatsWindow->setValue (id, value);
|
||||
mCharGen->setValue(id, value);
|
||||
|
||||
static const char *ids[] =
|
||||
{
|
||||
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5",
|
||||
"AttribVal6", "AttribVal7", "AttribVal8"
|
||||
};
|
||||
static ESM::Attribute::AttributeID attributes[] =
|
||||
{
|
||||
ESM::Attribute::Strength,
|
||||
ESM::Attribute::Intelligence,
|
||||
ESM::Attribute::Willpower,
|
||||
ESM::Attribute::Agility,
|
||||
ESM::Attribute::Speed,
|
||||
ESM::Attribute::Endurance,
|
||||
ESM::Attribute::Personality,
|
||||
ESM::Attribute::Luck
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i)
|
||||
{
|
||||
if (id != ids[i])
|
||||
continue;
|
||||
mPlayerAttributes[attributes[i]] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WindowManager::setValue (int parSkill, const MWMechanics::SkillValue& value)
|
||||
{
|
||||
|
@ -857,7 +691,6 @@ namespace MWGui
|
|||
/// allow custom skills.
|
||||
mStatsWindow->setValue(static_cast<ESM::Skill::SkillEnum> (parSkill), value);
|
||||
mCharGen->setValue(static_cast<ESM::Skill::SkillEnum> (parSkill), value);
|
||||
mPlayerSkillValues[parSkill] = value;
|
||||
}
|
||||
|
||||
void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value)
|
||||
|
@ -870,10 +703,6 @@ namespace MWGui
|
|||
void WindowManager::setValue (const std::string& id, const std::string& value)
|
||||
{
|
||||
mStatsWindow->setValue (id, value);
|
||||
if (id=="name")
|
||||
mPlayerName = value;
|
||||
else if (id=="race")
|
||||
mPlayerRaceId = value;
|
||||
}
|
||||
|
||||
void WindowManager::setValue (const std::string& id, int value)
|
||||
|
@ -895,8 +724,6 @@ namespace MWGui
|
|||
{
|
||||
mStatsWindow->configureSkills (major, minor);
|
||||
mCharGen->configureSkills(major, minor);
|
||||
mPlayerMajorSkills = major;
|
||||
mPlayerMinorSkills = minor;
|
||||
}
|
||||
|
||||
void WindowManager::updateSkillArea()
|
||||
|
@ -1045,7 +872,7 @@ namespace MWGui
|
|||
mHud->setPlayerPos(x, y, u, v);
|
||||
}
|
||||
|
||||
void WindowManager::onFrame (float frameDuration)
|
||||
void WindowManager::update (float frameDuration)
|
||||
{
|
||||
bool gameRunning = MWBase::Environment::get().getStateManager()->getState()!=
|
||||
MWBase::StateManager::State_NoGame;
|
||||
|
@ -1731,26 +1558,6 @@ namespace MWGui
|
|||
return mGuiModes.back();
|
||||
}
|
||||
|
||||
std::map<int, MWMechanics::SkillValue > WindowManager::getPlayerSkillValues()
|
||||
{
|
||||
return mPlayerSkillValues;
|
||||
}
|
||||
|
||||
std::map<int, MWMechanics::AttributeValue > WindowManager::getPlayerAttributeValues()
|
||||
{
|
||||
return mPlayerAttributes;
|
||||
}
|
||||
|
||||
WindowManager::SkillList WindowManager::getPlayerMinorSkills()
|
||||
{
|
||||
return mPlayerMinorSkills;
|
||||
}
|
||||
|
||||
WindowManager::SkillList WindowManager::getPlayerMajorSkills()
|
||||
{
|
||||
return mPlayerMajorSkills;
|
||||
}
|
||||
|
||||
void WindowManager::disallowMouse()
|
||||
{
|
||||
mInputBlocker->setVisible (true);
|
||||
|
@ -2331,7 +2138,9 @@ namespace MWGui
|
|||
|
||||
void WindowManager::toggleDebugWindow()
|
||||
{
|
||||
#ifndef BT_NO_PROFILE
|
||||
mDebugWindow->setVisible(!mDebugWindow->isVisible());
|
||||
#endif
|
||||
}
|
||||
|
||||
void WindowManager::cycleSpell(bool next)
|
||||
|
|
|
@ -356,13 +356,7 @@ namespace MWGui
|
|||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
virtual void onFrame (float frameDuration);
|
||||
|
||||
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
|
||||
virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues();
|
||||
virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues();
|
||||
virtual SkillList getPlayerMinorSkills();
|
||||
virtual SkillList getPlayerMajorSkills();
|
||||
virtual void update (float duration);
|
||||
|
||||
/**
|
||||
* Fetches a GMST string from the store, if there is no setting with the given
|
||||
|
@ -503,8 +497,6 @@ namespace MWGui
|
|||
MWWorld::Ptr mSelectedEnchantItem;
|
||||
MWWorld::Ptr mSelectedWeapon;
|
||||
|
||||
void loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version);
|
||||
|
||||
std::vector<WindowModal*> mCurrentModals;
|
||||
|
||||
// Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window).
|
||||
|
@ -571,14 +563,6 @@ namespace MWGui
|
|||
|
||||
void setCursorVisible(bool visible);
|
||||
|
||||
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
|
||||
// Various stats about player as needed by window manager
|
||||
std::string mPlayerName;
|
||||
std::string mPlayerRaceId;
|
||||
std::map<int, MWMechanics::AttributeValue > mPlayerAttributes;
|
||||
SkillList mPlayerMajorSkills, mPlayerMinorSkills;
|
||||
std::map<int, MWMechanics::SkillValue > mPlayerSkillValues;
|
||||
|
||||
MyGUI::Gui *mGui; // Gui
|
||||
|
||||
struct GuiModeState
|
||||
|
@ -628,8 +612,6 @@ namespace MWGui
|
|||
|
||||
ToUTF8::FromType mEncoding;
|
||||
|
||||
int mFontHeight;
|
||||
|
||||
std::string mVersionDescription;
|
||||
|
||||
bool mWindowVisible;
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace MWInput
|
|||
, mSneakToggleShortcutTimer(0.f)
|
||||
, mGamepadZoom(0)
|
||||
, mGamepadGuiCursorEnabled(true)
|
||||
, mControlsDisabled(false)
|
||||
, mJoystickLastUsed(false)
|
||||
, mSneakGamepadShortcut(false)
|
||||
, mGamepadPreviewMode(false)
|
||||
|
@ -83,9 +82,8 @@ namespace MWInput
|
|||
}
|
||||
}
|
||||
|
||||
bool ControllerManager::update(float dt, bool disableControls)
|
||||
bool ControllerManager::update(float dt)
|
||||
{
|
||||
mControlsDisabled = disableControls;
|
||||
mGamepadPreviewMode = mActionManager->getPreviewDelay() == 1.f;
|
||||
|
||||
if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled))
|
||||
|
@ -232,7 +230,7 @@ namespace MWInput
|
|||
auto kc = sdlKeyToMyGUI(SDLK_ESCAPE);
|
||||
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(kc, 0));
|
||||
|
||||
if (!mControlsDisabled)
|
||||
if (!MWBase::Environment::get().getInputManager()->controlsDisabled())
|
||||
mBindingsManager->controllerButtonPressed(deviceID, arg);
|
||||
}
|
||||
|
||||
|
@ -244,7 +242,7 @@ namespace MWInput
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mJoystickEnabled || mControlsDisabled)
|
||||
if (!mJoystickEnabled || MWBase::Environment::get().getInputManager()->controlsDisabled())
|
||||
return;
|
||||
|
||||
mJoystickLastUsed = true;
|
||||
|
@ -275,7 +273,7 @@ namespace MWInput
|
|||
|
||||
void ControllerManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg)
|
||||
{
|
||||
if (!mJoystickEnabled || mControlsDisabled)
|
||||
if (!mJoystickEnabled || MWBase::Environment::get().getInputManager()->controlsDisabled())
|
||||
return;
|
||||
|
||||
mJoystickLastUsed = true;
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace MWInput
|
|||
|
||||
virtual ~ControllerManager() = default;
|
||||
|
||||
bool update(float dt, bool disableControls);
|
||||
bool update(float dt);
|
||||
|
||||
virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||
virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||
|
@ -56,7 +56,6 @@ namespace MWInput
|
|||
float mSneakToggleShortcutTimer;
|
||||
float mGamepadZoom;
|
||||
bool mGamepadGuiCursorEnabled;
|
||||
bool mControlsDisabled;
|
||||
bool mJoystickLastUsed;
|
||||
bool mGuiCursorEnabled;
|
||||
bool mSneakGamepadShortcut;
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace MWInput
|
|||
osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation,
|
||||
const std::string& userFile, bool userFileExists, const std::string& userControllerBindingsFile,
|
||||
const std::string& controllerBindingsFile, bool grab)
|
||||
: mGrabCursor(Settings::Manager::getBool("grab cursor", "Input"))
|
||||
: mControlsDisabled(false)
|
||||
{
|
||||
mInputWrapper = new SDLUtil::InputWrapper(window, viewer, grab);
|
||||
mInputWrapper->setWindowEventCallback(MWBase::Environment::get().getWindowManager());
|
||||
|
@ -81,47 +81,25 @@ namespace MWInput
|
|||
mActionManager->setAttemptJump(jumping);
|
||||
}
|
||||
|
||||
void InputManager::updateCursorMode()
|
||||
{
|
||||
bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)
|
||||
&& !MWBase::Environment::get().getWindowManager()->isConsoleMode();
|
||||
|
||||
bool wasRelative = mInputWrapper->getMouseRelative();
|
||||
bool isRelative = !MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
||||
// don't keep the pointer away from the window edge in gui mode
|
||||
// stop using raw mouse motions and switch to system cursor movements
|
||||
mInputWrapper->setMouseRelative(isRelative);
|
||||
|
||||
//we let the mouse escape in the main menu
|
||||
mInputWrapper->setGrabPointer(grab && (mGrabCursor || isRelative));
|
||||
|
||||
//we switched to non-relative mode, move our cursor to where the in-game
|
||||
//cursor is
|
||||
if (!isRelative && wasRelative != isRelative)
|
||||
{
|
||||
mMouseManager->warpMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void InputManager::update(float dt, bool disableControls, bool disableEvents)
|
||||
{
|
||||
mControlsDisabled = disableControls;
|
||||
|
||||
mInputWrapper->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible());
|
||||
mInputWrapper->capture(disableEvents);
|
||||
|
||||
mKeyboardManager->setControlsDisabled(disableControls);
|
||||
if (disableControls)
|
||||
{
|
||||
updateCursorMode();
|
||||
mMouseManager->updateCursorMode();
|
||||
return;
|
||||
}
|
||||
|
||||
mBindingsManager->update(dt);
|
||||
|
||||
updateCursorMode();
|
||||
mMouseManager->updateCursorMode();
|
||||
|
||||
bool controllerMove = mControllerManager->update(dt, disableControls);
|
||||
mMouseManager->update(dt, disableControls);
|
||||
bool controllerMove = mControllerManager->update(dt);
|
||||
mMouseManager->update(dt);
|
||||
mSensorManager->update(dt);
|
||||
mActionManager->update(dt, controllerMove);
|
||||
}
|
||||
|
@ -152,12 +130,6 @@ namespace MWInput
|
|||
|
||||
void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||
{
|
||||
for (const auto& setting : changed)
|
||||
{
|
||||
if (setting.first == "Input" && setting.second == "grab cursor")
|
||||
mGrabCursor = Settings::Manager::getBool("grab cursor", "Input");
|
||||
}
|
||||
|
||||
mMouseManager->processChangedSettings(changed);
|
||||
mSensorManager->processChangedSettings(changed);
|
||||
}
|
||||
|
|
|
@ -94,13 +94,13 @@ namespace MWInput
|
|||
|
||||
virtual void executeAction(int action);
|
||||
|
||||
virtual bool controlsDisabled() { return mControlsDisabled; }
|
||||
|
||||
private:
|
||||
void convertMousePosForMyGUI(int& x, int& y);
|
||||
|
||||
void handleGuiArrowKey(int action);
|
||||
|
||||
void updateCursorMode();
|
||||
|
||||
void quickKey(int index);
|
||||
void showQuickKeysMenu();
|
||||
|
||||
|
@ -109,7 +109,7 @@ namespace MWInput
|
|||
|
||||
SDLUtil::InputWrapper* mInputWrapper;
|
||||
|
||||
bool mGrabCursor;
|
||||
bool mControlsDisabled;
|
||||
|
||||
ControlSwitch* mControlSwitch;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ namespace MWInput
|
|||
{
|
||||
KeyboardManager::KeyboardManager(BindingsManager* bindingsManager)
|
||||
: mBindingsManager(bindingsManager)
|
||||
, mControlsDisabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -53,10 +52,11 @@ namespace MWInput
|
|||
if (arg.repeat)
|
||||
return;
|
||||
|
||||
if (!mControlsDisabled && !consumed)
|
||||
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||
if (!input->controlsDisabled() && !consumed)
|
||||
mBindingsManager->keyPressed(arg);
|
||||
|
||||
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||
input->setJoystickLastUsed(false);
|
||||
}
|
||||
|
||||
void KeyboardManager::keyReleased(const SDL_KeyboardEvent &arg)
|
||||
|
|
|
@ -19,12 +19,8 @@ namespace MWInput
|
|||
virtual void keyPressed(const SDL_KeyboardEvent &arg);
|
||||
virtual void keyReleased(const SDL_KeyboardEvent &arg);
|
||||
|
||||
void setControlsDisabled(bool disabled) { mControlsDisabled = disabled; }
|
||||
|
||||
private:
|
||||
BindingsManager* mBindingsManager;
|
||||
|
||||
bool mControlsDisabled;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace MWInput
|
|||
MouseManager::MouseManager(BindingsManager* bindingsManager, SDLUtil::InputWrapper* inputWrapper, SDL_Window* window)
|
||||
: mInvertX(Settings::Manager::getBool("invert x axis", "Input"))
|
||||
, mInvertY(Settings::Manager::getBool("invert y axis", "Input"))
|
||||
, mGrabCursor(Settings::Manager::getBool("grab cursor", "Input"))
|
||||
, mCameraSensitivity(Settings::Manager::getFloat("camera sensitivity", "Input"))
|
||||
, mCameraYMultiplier(Settings::Manager::getFloat("camera y multiplier", "Input"))
|
||||
, mBindingsManager(bindingsManager)
|
||||
|
@ -33,7 +34,6 @@ namespace MWInput
|
|||
, mGuiCursorY(0)
|
||||
, mMouseWheel(0)
|
||||
, mMouseLookEnabled(false)
|
||||
, mControlsDisabled(false)
|
||||
, mGuiCursorEnabled(true)
|
||||
{
|
||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||
|
@ -59,6 +59,9 @@ namespace MWInput
|
|||
|
||||
if (setting.first == "Input" && setting.second == "camera sensitivity")
|
||||
mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input");
|
||||
|
||||
if (setting.first == "Input" && setting.second == "grab cursor")
|
||||
mGrabCursor = Settings::Manager::getBool("grab cursor", "Input");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +91,7 @@ namespace MWInput
|
|||
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||
}
|
||||
|
||||
if (mMouseLookEnabled && !mControlsDisabled)
|
||||
if (mMouseLookEnabled && !input->controlsDisabled())
|
||||
{
|
||||
float x = arg.xrel * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
|
||||
float y = arg.yrel * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||
|
@ -136,10 +139,11 @@ namespace MWInput
|
|||
|
||||
void MouseManager::mouseWheelMoved(const SDL_MouseWheelEvent &arg)
|
||||
{
|
||||
if (mBindingsManager->isDetectingBindingState() || !mControlsDisabled)
|
||||
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||
if (mBindingsManager->isDetectingBindingState() || !input->controlsDisabled())
|
||||
mBindingsManager->mouseWheelMoved(arg);
|
||||
|
||||
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||
input->setJoystickLastUsed(false);
|
||||
}
|
||||
|
||||
void MouseManager::mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id)
|
||||
|
@ -169,10 +173,31 @@ namespace MWInput
|
|||
mBindingsManager->mousePressed(arg, id);
|
||||
}
|
||||
|
||||
void MouseManager::update(float dt, bool disableControls)
|
||||
void MouseManager::updateCursorMode()
|
||||
{
|
||||
mControlsDisabled = disableControls;
|
||||
bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)
|
||||
&& !MWBase::Environment::get().getWindowManager()->isConsoleMode();
|
||||
|
||||
bool wasRelative = mInputWrapper->getMouseRelative();
|
||||
bool isRelative = !MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
||||
// don't keep the pointer away from the window edge in gui mode
|
||||
// stop using raw mouse motions and switch to system cursor movements
|
||||
mInputWrapper->setMouseRelative(isRelative);
|
||||
|
||||
//we let the mouse escape in the main menu
|
||||
mInputWrapper->setGrabPointer(grab && (mGrabCursor || isRelative));
|
||||
|
||||
//we switched to non-relative mode, move our cursor to where the in-game
|
||||
//cursor is
|
||||
if (!isRelative && wasRelative != isRelative)
|
||||
{
|
||||
warpMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void MouseManager::update(float dt)
|
||||
{
|
||||
if (!mMouseLookEnabled)
|
||||
return;
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ namespace MWInput
|
|||
|
||||
virtual ~MouseManager() = default;
|
||||
|
||||
void update(float dt, bool disableControls);
|
||||
void updateCursorMode();
|
||||
void update(float dt);
|
||||
|
||||
virtual void mouseMoved(const SDLUtil::MouseMotionEvent &arg);
|
||||
virtual void mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id);
|
||||
|
@ -40,6 +41,7 @@ namespace MWInput
|
|||
private:
|
||||
bool mInvertX;
|
||||
bool mInvertY;
|
||||
bool mGrabCursor;
|
||||
float mCameraSensitivity;
|
||||
float mCameraYMultiplier;
|
||||
|
||||
|
@ -51,7 +53,6 @@ namespace MWInput
|
|||
float mGuiCursorY;
|
||||
int mMouseWheel;
|
||||
bool mMouseLookEnabled;
|
||||
bool mControlsDisabled;
|
||||
bool mGuiCursorEnabled;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,14 +12,12 @@
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
void ActiveSpells::update() const
|
||||
void ActiveSpells::update(float duration) const
|
||||
{
|
||||
bool rebuild = false;
|
||||
|
||||
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
|
||||
// Erase no longer active spells and effects
|
||||
if (mLastUpdate!=now)
|
||||
if (duration > 0)
|
||||
{
|
||||
TContainer::iterator iter (mSpells.begin());
|
||||
while (iter!=mSpells.end())
|
||||
|
@ -34,21 +32,20 @@ namespace MWMechanics
|
|||
std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||
for (std::vector<ActiveEffect>::iterator effectIt = effects.begin(); effectIt != effects.end();)
|
||||
{
|
||||
MWWorld::TimeStamp start = iter->second.mTimeStamp;
|
||||
MWWorld::TimeStamp end = start + static_cast<double>(effectIt->mDuration)*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
if (end <= now)
|
||||
if (effectIt->mTimeLeft <= 0)
|
||||
{
|
||||
effectIt = effects.erase(effectIt);
|
||||
rebuild = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
effectIt->mTimeLeft -= duration;
|
||||
++effectIt;
|
||||
}
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
mLastUpdate = now;
|
||||
}
|
||||
|
||||
if (mSpellsChanged)
|
||||
|
@ -63,24 +60,15 @@ namespace MWMechanics
|
|||
|
||||
void ActiveSpells::rebuildEffects() const
|
||||
{
|
||||
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
|
||||
mEffects = MagicEffects();
|
||||
|
||||
for (TIterator iter (begin()); iter!=end(); ++iter)
|
||||
{
|
||||
const MWWorld::TimeStamp& start = iter->second.mTimeStamp;
|
||||
|
||||
const std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||
{
|
||||
double duration = effectIt->mDuration;
|
||||
MWWorld::TimeStamp end = start;
|
||||
end += duration *
|
||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
|
||||
if (end>now)
|
||||
if (effectIt->mTimeLeft > 0)
|
||||
mEffects.add(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), MWMechanics::EffectParam(effectIt->mMagnitude));
|
||||
}
|
||||
}
|
||||
|
@ -88,12 +76,11 @@ namespace MWMechanics
|
|||
|
||||
ActiveSpells::ActiveSpells()
|
||||
: mSpellsChanged (false)
|
||||
, mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp())
|
||||
{}
|
||||
|
||||
const MagicEffects& ActiveSpells::getMagicEffects() const
|
||||
{
|
||||
update();
|
||||
update(0.f);
|
||||
return mEffects;
|
||||
}
|
||||
|
||||
|
@ -116,19 +103,14 @@ namespace MWMechanics
|
|||
for (std::vector<ActiveEffect>::const_iterator iter (effects.begin());
|
||||
iter!=effects.end(); ++iter)
|
||||
{
|
||||
if (iter->mDuration > duration)
|
||||
duration = iter->mDuration;
|
||||
if (iter->mTimeLeft > duration)
|
||||
duration = iter->mTimeLeft;
|
||||
}
|
||||
|
||||
double scaledDuration = duration *
|
||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
|
||||
double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp() - iterator->second.mTimeStamp;
|
||||
|
||||
if (usedUp>=scaledDuration)
|
||||
if (duration < 0)
|
||||
return 0;
|
||||
|
||||
return scaledDuration-usedUp;
|
||||
return duration;
|
||||
}
|
||||
|
||||
bool ActiveSpells::isSpellActive(const std::string& id) const
|
||||
|
@ -152,7 +134,6 @@ namespace MWMechanics
|
|||
TContainer::iterator it(mSpells.find(id));
|
||||
|
||||
ActiveSpellParams params;
|
||||
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
params.mEffects = effects;
|
||||
params.mDisplayName = displayName;
|
||||
params.mCasterActorId = casterActorId;
|
||||
|
@ -211,19 +192,15 @@ namespace MWMechanics
|
|||
{
|
||||
for (TContainer::const_iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = it->second.mEffects.begin();
|
||||
effectIt != it->second.mEffects.end(); ++effectIt)
|
||||
{
|
||||
std::string name = it->second.mDisplayName;
|
||||
|
||||
float remainingTime = effectIt->mDuration +
|
||||
static_cast<float>(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
|
||||
float magnitude = effectIt->mMagnitude;
|
||||
|
||||
if (magnitude)
|
||||
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration);
|
||||
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, effectIt->mTimeLeft, effectIt->mDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +342,6 @@ namespace MWMechanics
|
|||
params.mEffects = it->second.mEffects;
|
||||
params.mCasterActorId = it->second.mCasterActorId;
|
||||
params.mDisplayName = it->second.mDisplayName;
|
||||
params.mTimeStamp = it->second.mTimeStamp.toEsm();
|
||||
|
||||
state.mSpells.insert (std::make_pair(it->first, params));
|
||||
}
|
||||
|
@ -380,7 +356,6 @@ namespace MWMechanics
|
|||
params.mEffects = it->second.mEffects;
|
||||
params.mCasterActorId = it->second.mCasterActorId;
|
||||
params.mDisplayName = it->second.mDisplayName;
|
||||
params.mTimeStamp = MWWorld::TimeStamp(it->second.mTimeStamp);
|
||||
|
||||
mSpells.insert (std::make_pair(it->first, params));
|
||||
mSpellsChanged = true;
|
||||
|
|
|
@ -44,14 +44,13 @@ namespace MWMechanics
|
|||
|
||||
TIterator end() const;
|
||||
|
||||
void update(float duration) const;
|
||||
|
||||
private:
|
||||
|
||||
mutable TContainer mSpells;
|
||||
mutable MagicEffects mEffects;
|
||||
mutable bool mSpellsChanged;
|
||||
mutable MWWorld::TimeStamp mLastUpdate;
|
||||
|
||||
void update() const;
|
||||
|
||||
void rebuildEffects() const;
|
||||
|
||||
|
|
|
@ -18,4 +18,44 @@ namespace MWMechanics
|
|||
{
|
||||
return mCharacterController.get();
|
||||
}
|
||||
|
||||
int Actor::getGreetingTimer() const
|
||||
{
|
||||
return mGreetingTimer;
|
||||
}
|
||||
|
||||
void Actor::setGreetingTimer(int timer)
|
||||
{
|
||||
mGreetingTimer = timer;
|
||||
}
|
||||
|
||||
float Actor::getAngleToPlayer() const
|
||||
{
|
||||
return mTargetAngleRadians;
|
||||
}
|
||||
|
||||
void Actor::setAngleToPlayer(float angle)
|
||||
{
|
||||
mTargetAngleRadians = angle;
|
||||
}
|
||||
|
||||
GreetingState Actor::getGreetingState() const
|
||||
{
|
||||
return mGreetingState;
|
||||
}
|
||||
|
||||
void Actor::setGreetingState(GreetingState state)
|
||||
{
|
||||
mGreetingState = state;
|
||||
}
|
||||
|
||||
bool Actor::isTurningToPlayer() const
|
||||
{
|
||||
return mIsTurningToPlayer;
|
||||
}
|
||||
|
||||
void Actor::setTurningToPlayer(bool turning)
|
||||
{
|
||||
mIsTurningToPlayer = turning;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class Animation;
|
||||
|
@ -27,8 +29,24 @@ namespace MWMechanics
|
|||
|
||||
CharacterController* getCharacterController();
|
||||
|
||||
int getGreetingTimer() const;
|
||||
void setGreetingTimer(int timer);
|
||||
|
||||
float getAngleToPlayer() const;
|
||||
void setAngleToPlayer(float angle);
|
||||
|
||||
GreetingState getGreetingState() const;
|
||||
void setGreetingState(GreetingState state);
|
||||
|
||||
bool isTurningToPlayer() const;
|
||||
void setTurningToPlayer(bool turning);
|
||||
|
||||
private:
|
||||
std::unique_ptr<CharacterController> mCharacterController;
|
||||
int mGreetingTimer{0};
|
||||
float mTargetAngleRadians{0.f};
|
||||
GreetingState mGreetingState{Greet_None};
|
||||
bool mIsTurningToPlayer{false};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -480,7 +480,7 @@ namespace MWMechanics
|
|||
actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor;
|
||||
}
|
||||
|
||||
void Actors::updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly)
|
||||
void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly)
|
||||
{
|
||||
if (!actor.getClass().isActor() || actor == getPlayer())
|
||||
return;
|
||||
|
@ -493,9 +493,9 @@ namespace MWMechanics
|
|||
MWBase::Environment::get().getWorld()->isSwimming(actor) ||
|
||||
(packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1))
|
||||
{
|
||||
stats.setTurningToPlayer(false);
|
||||
stats.setGreetingTimer(0);
|
||||
stats.setGreetingState(Greet_None);
|
||||
actorState.setTurningToPlayer(false);
|
||||
actorState.setGreetingTimer(0);
|
||||
actorState.setGreetingState(Greet_None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -504,14 +504,14 @@ namespace MWMechanics
|
|||
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
osg::Vec3f dir = playerPos - actorPos;
|
||||
|
||||
if (stats.isTurningToPlayer())
|
||||
if (actorState.isTurningToPlayer())
|
||||
{
|
||||
// Reduce the turning animation glitch by using a *HUGE* value of
|
||||
// epsilon... TODO: a proper fix might be in either the physics or the
|
||||
// animation subsystem
|
||||
if (zTurn(actor, stats.getAngleToPlayer(), osg::DegreesToRadians(5.f)))
|
||||
if (zTurn(actor, actorState.getAngleToPlayer(), osg::DegreesToRadians(5.f)))
|
||||
{
|
||||
stats.setTurningToPlayer(false);
|
||||
actorState.setTurningToPlayer(false);
|
||||
// An original engine launches an endless idle2 when an actor greets player.
|
||||
playAnimationGroup (actor, "idle2", 0, std::numeric_limits<int>::max(), false);
|
||||
}
|
||||
|
@ -526,8 +526,8 @@ namespace MWMechanics
|
|||
|
||||
float helloDistance = static_cast<float>(stats.getAiSetting(CreatureStats::AI_Hello).getModified() * iGreetDistanceMultiplier);
|
||||
|
||||
int greetingTimer = stats.getGreetingTimer();
|
||||
GreetingState greetingState = stats.getGreetingState();
|
||||
int greetingTimer = actorState.getGreetingTimer();
|
||||
GreetingState greetingState = actorState.getGreetingState();
|
||||
if (greetingState == Greet_None)
|
||||
{
|
||||
if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
|
||||
|
@ -549,7 +549,7 @@ namespace MWMechanics
|
|||
greetingTimer++;
|
||||
|
||||
if (greetingTimer <= GREETING_SHOULD_END || MWBase::Environment::get().getSoundManager()->sayActive(actor))
|
||||
turnActorToFacePlayer(actor, dir);
|
||||
turnActorToFacePlayer(actor, actorState, dir);
|
||||
|
||||
if (greetingTimer >= GREETING_COOLDOWN)
|
||||
{
|
||||
|
@ -565,20 +565,19 @@ namespace MWMechanics
|
|||
greetingState = Greet_None;
|
||||
}
|
||||
|
||||
stats.setGreetingTimer(greetingTimer);
|
||||
stats.setGreetingState(greetingState);
|
||||
actorState.setGreetingTimer(greetingTimer);
|
||||
actorState.setGreetingState(greetingState);
|
||||
}
|
||||
|
||||
void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir)
|
||||
void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor& actorState, const osg::Vec3f& dir)
|
||||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
|
||||
|
||||
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
|
||||
if (!stats.isTurningToPlayer())
|
||||
if (!actorState.isTurningToPlayer())
|
||||
{
|
||||
stats.setAngleToPlayer(std::atan2(dir.x(), dir.y()));
|
||||
stats.setTurningToPlayer(true);
|
||||
actorState.setAngleToPlayer(std::atan2(dir.x(), dir.y()));
|
||||
actorState.setTurningToPlayer(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -819,6 +818,9 @@ namespace MWMechanics
|
|||
if (visitor.mRemainingTime > 0)
|
||||
{
|
||||
double timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
if(timeScale == 0.0)
|
||||
timeScale = 1;
|
||||
|
||||
restoreHours = std::max(0.0, hours - visitor.mRemainingTime * timeScale / 3600.f);
|
||||
}
|
||||
else if (visitor.mRemainingTime == -1)
|
||||
|
@ -1782,6 +1784,8 @@ namespace MWMechanics
|
|||
End of tes3mp change (major)
|
||||
*/
|
||||
|
||||
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
||||
|
||||
// For dead actors we need to remove looping spell particles
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||
ctrl->updateContinuousVfx();
|
||||
|
@ -1862,7 +1866,7 @@ namespace MWMechanics
|
|||
if (isConscious(iter->first))
|
||||
{
|
||||
stats.getAiSequence().execute(iter->first, *ctrl, duration);
|
||||
updateGreetingState(iter->first, timerUpdateHello > 0);
|
||||
updateGreetingState(iter->first, *iter->second, timerUpdateHello > 0);
|
||||
playIdleDialogue(iter->first);
|
||||
updateMovementSpeed(iter->first);
|
||||
}
|
||||
|
@ -2165,7 +2169,11 @@ namespace MWMechanics
|
|||
|
||||
void Actors::rest(double hours, bool sleep)
|
||||
{
|
||||
float duration = hours * 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
float duration = hours * 3600.f;
|
||||
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
if (timeScale != 0.f)
|
||||
duration /= timeScale;
|
||||
|
||||
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
||||
|
||||
|
@ -2675,6 +2683,42 @@ namespace MWMechanics
|
|||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
return 0;
|
||||
|
||||
return it->second->getGreetingTimer();
|
||||
}
|
||||
|
||||
float Actors::getAngleToPlayer(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
return 0.f;
|
||||
|
||||
return it->second->getAngleToPlayer();
|
||||
}
|
||||
|
||||
GreetingState Actors::getGreetingState(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
return Greet_None;
|
||||
|
||||
return it->second->getGreetingState();
|
||||
}
|
||||
|
||||
bool Actors::isTurningToPlayer(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
return false;
|
||||
|
||||
return it->second->isTurningToPlayer();
|
||||
}
|
||||
|
||||
void Actors::fastForwardAi()
|
||||
{
|
||||
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
|
@ -70,6 +72,7 @@ namespace MWMechanics
|
|||
|
||||
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrActorMap::const_iterator end() { return mActors.end(); }
|
||||
std::size_t size() const { return mActors.size(); }
|
||||
|
||||
void notifyDied(const MWWorld::Ptr &actor);
|
||||
|
||||
|
@ -122,8 +125,8 @@ namespace MWMechanics
|
|||
|
||||
void playIdleDialogue(const MWWorld::Ptr& actor);
|
||||
void updateMovementSpeed(const MWWorld::Ptr& actor);
|
||||
void updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly);
|
||||
void turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir);
|
||||
void updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly);
|
||||
void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor& actorState, const osg::Vec3f& dir);
|
||||
|
||||
void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
||||
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
|
||||
|
@ -214,6 +217,11 @@ namespace MWMechanics
|
|||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
int getGreetingTimer(const MWWorld::Ptr& ptr) const;
|
||||
float getAngleToPlayer(const MWWorld::Ptr& ptr) const;
|
||||
GreetingState getGreetingState(const MWWorld::Ptr& ptr) const;
|
||||
bool isTurningToPlayer(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
private:
|
||||
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl);
|
||||
|
||||
|
|
|
@ -8,6 +8,13 @@ namespace MWWorld
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
enum GreetingState
|
||||
{
|
||||
Greet_None,
|
||||
Greet_InProgress,
|
||||
Greet_Done
|
||||
};
|
||||
|
||||
MWWorld::Ptr getPlayer();
|
||||
bool isPlayerInCombat();
|
||||
bool canActorMoveByZAxis(const MWWorld::Ptr& actor);
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace MWMechanics
|
|||
{
|
||||
/// \brief Causes actor to walk to activatable object and activate it
|
||||
/** Will activate when close to object **/
|
||||
class AiActivate : public AiPackage
|
||||
class AiActivate final : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
|
@ -49,11 +49,11 @@ namespace MWMechanics
|
|||
|
||||
AiActivate(const ESM::AiSequence::AiActivate* activate);
|
||||
|
||||
virtual AiActivate *clone() const;
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
virtual int getTypeId() const;
|
||||
AiActivate *clone() const final;
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual void writeState(ESM::AiSequence::AiSequence& sequence) const;
|
||||
void writeState(ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
private:
|
||||
std::string mObjectId;
|
||||
|
|
|
@ -16,22 +16,22 @@ namespace MWMechanics
|
|||
/// \brief AiPackage to have an actor avoid an opening door
|
||||
/** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
|
||||
**/
|
||||
class AiAvoidDoor : public AiPackage
|
||||
class AiAvoidDoor final : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Avoid door until the door is fully open
|
||||
AiAvoidDoor(const MWWorld::ConstPtr& doorPtr);
|
||||
|
||||
virtual AiAvoidDoor *clone() const;
|
||||
AiAvoidDoor *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual unsigned int getPriority() const;
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
|
||||
private:
|
||||
float mDuration;
|
||||
|
|
|
@ -7,21 +7,21 @@ namespace MWMechanics
|
|||
{
|
||||
/// \brief AiPackage to have an actor resurface to breathe
|
||||
// The AI will go up if lesser than half breath left
|
||||
class AiBreathe : public AiPackage
|
||||
class AiBreathe final : public AiPackage
|
||||
{
|
||||
public:
|
||||
AiBreathe();
|
||||
|
||||
virtual AiBreathe *clone() const;
|
||||
AiBreathe *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual unsigned int getPriority() const;
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,22 +11,22 @@ namespace MWWorld
|
|||
namespace MWMechanics
|
||||
{
|
||||
/// AiPackage which makes an actor to cast given spell.
|
||||
class AiCast : public AiPackage {
|
||||
class AiCast final : public AiPackage {
|
||||
public:
|
||||
AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false);
|
||||
|
||||
virtual AiPackage *clone() const;
|
||||
AiPackage *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual MWWorld::Ptr getTarget() const;
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
virtual unsigned int getPriority() const;
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
|
||||
private:
|
||||
std::string mTargetId;
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace MWMechanics
|
|||
};
|
||||
|
||||
/// \brief Causes the actor to fight another actor
|
||||
class AiCombat : public AiPackage
|
||||
class AiCombat final : public AiPackage
|
||||
{
|
||||
public:
|
||||
///Constructor
|
||||
|
@ -102,21 +102,21 @@ namespace MWMechanics
|
|||
|
||||
void init();
|
||||
|
||||
virtual AiCombat *clone() const;
|
||||
AiCombat *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual unsigned int getPriority() const;
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
///Returns target ID
|
||||
MWWorld::Ptr getTarget() const;
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
|
||||
private:
|
||||
/// Returns true if combat should end
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace AiSequence
|
|||
namespace MWMechanics
|
||||
{
|
||||
/// \brief AI Package to have an NPC lead the player to a specific point
|
||||
class AiEscort : public AiPackage
|
||||
class AiEscort final : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Implementation of AiEscort
|
||||
|
@ -30,21 +30,21 @@ namespace MWMechanics
|
|||
|
||||
AiEscort(const ESM::AiSequence::AiEscort* escort);
|
||||
|
||||
virtual AiEscort *clone() const;
|
||||
AiEscort *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual bool useVariableSpeed() const { return true;}
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
virtual bool sideWithTarget() const { return true; }
|
||||
bool sideWithTarget() const final { return true; }
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state);
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||
|
||||
virtual osg::Vec3f getDestination() const { return osg::Vec3f(mX, mY, mZ); }
|
||||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||
|
||||
private:
|
||||
std::string mCellId;
|
||||
|
|
|
@ -6,20 +6,20 @@
|
|||
namespace MWMechanics
|
||||
{
|
||||
/// AiPackage which makes an actor face a certain direction.
|
||||
class AiFace : public AiPackage {
|
||||
class AiFace final : public AiPackage {
|
||||
public:
|
||||
AiFace(float targetX, float targetY);
|
||||
|
||||
virtual AiPackage *clone() const;
|
||||
AiPackage *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual unsigned int getPriority() const;
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
|
||||
private:
|
||||
float mTargetX, mTargetY;
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace MWMechanics
|
|||
/// \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
|
||||
**/
|
||||
class AiFollow : public AiPackage
|
||||
class AiFollow final : public AiPackage
|
||||
{
|
||||
public:
|
||||
AiFollow(const std::string &actorId, float duration, float x, float y, float z);
|
||||
|
@ -53,30 +53,30 @@ namespace MWMechanics
|
|||
|
||||
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
||||
|
||||
virtual bool sideWithTarget() const { return true; }
|
||||
virtual bool followTargetThroughDoors() const { return true; }
|
||||
virtual bool shouldCancelPreviousAi() const { return !mCommanded; }
|
||||
bool sideWithTarget() const final { return true; }
|
||||
bool followTargetThroughDoors() const final { return true; }
|
||||
bool shouldCancelPreviousAi() const final { return !mCommanded; }
|
||||
|
||||
virtual AiFollow *clone() const;
|
||||
AiFollow *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual bool useVariableSpeed() const { return true;}
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
/// Returns the actor being followed
|
||||
std::string getFollowedActor();
|
||||
|
||||
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const;
|
||||
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
bool isCommanded() const;
|
||||
|
||||
int getFollowIndex() const;
|
||||
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state);
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||
|
||||
virtual osg::Vec3f getDestination() const
|
||||
osg::Vec3f getDestination() const final
|
||||
{
|
||||
MWWorld::Ptr target = getTarget();
|
||||
if (target.isEmpty())
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
#include <osg/Quat>
|
||||
|
||||
MWMechanics::AiPackage::~AiPackage() {}
|
||||
|
||||
MWMechanics::AiPackage::AiPackage() :
|
||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||
mTargetActorRefId(""),
|
||||
|
|
|
@ -56,8 +56,7 @@ namespace MWMechanics
|
|||
///Default constructor
|
||||
AiPackage();
|
||||
|
||||
///Default Deconstructor
|
||||
virtual ~AiPackage();
|
||||
virtual ~AiPackage() = default;
|
||||
|
||||
///Clones the package
|
||||
virtual AiPackage *clone() const = 0;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace MWMechanics
|
|||
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them.
|
||||
Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the
|
||||
path is completed). **/
|
||||
class AiPursue : public AiPackage
|
||||
class AiPursue final : public AiPackage
|
||||
{
|
||||
public:
|
||||
///Constructor
|
||||
|
@ -26,16 +26,16 @@ namespace MWMechanics
|
|||
|
||||
AiPursue(const ESM::AiSequence::AiPursue* pursue);
|
||||
|
||||
virtual AiPursue *clone() const;
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
virtual int getTypeId() const;
|
||||
AiPursue *clone() const final;
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
int getTypeId() const final;
|
||||
|
||||
MWWorld::Ptr getTarget() const;
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const;
|
||||
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -212,7 +212,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
|||
return;
|
||||
}
|
||||
|
||||
MWMechanics::AiPackage* package = mPackages.front();
|
||||
auto packageIt = mPackages.begin();
|
||||
MWMechanics::AiPackage* package = *packageIt;
|
||||
if (!package->alwaysActive() && outOfRange)
|
||||
return;
|
||||
|
||||
|
@ -223,7 +224,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
|||
// if active package is combat one, choose nearest target
|
||||
if (packageTypeId == AiPackage::TypeIdCombat)
|
||||
{
|
||||
std::list<AiPackage *>::iterator itActualCombat;
|
||||
auto itActualCombat = mPackages.end();
|
||||
|
||||
float nearestDist = std::numeric_limits<float>::max();
|
||||
osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3();
|
||||
|
@ -265,16 +266,18 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
|||
}
|
||||
}
|
||||
|
||||
if (!mPackages.empty())
|
||||
{
|
||||
assert(!mPackages.empty());
|
||||
|
||||
if (nearestDist < std::numeric_limits<float>::max() && mPackages.begin() != itActualCombat)
|
||||
{
|
||||
assert(itActualCombat != mPackages.end());
|
||||
// move combat package with nearest target to the front
|
||||
mPackages.splice(mPackages.begin(), mPackages, itActualCombat);
|
||||
}
|
||||
|
||||
package = mPackages.front();
|
||||
}
|
||||
packageIt = mPackages.begin();
|
||||
package = *packageIt;
|
||||
packageTypeId = package->getTypeId();
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -289,9 +292,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
|||
}
|
||||
// To account for the rare case where AiPackage::execute() queued another AI package
|
||||
// (e.g. AiPursue executing a dialogue script that uses startCombat)
|
||||
std::list<MWMechanics::AiPackage*>::iterator toRemove =
|
||||
std::find(mPackages.begin(), mPackages.end(), package);
|
||||
mPackages.erase(toRemove);
|
||||
mPackages.erase(packageIt);
|
||||
delete package;
|
||||
if (isActualAiPackage(packageTypeId))
|
||||
mDone = true;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <components/esm/aisequence.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
@ -43,14 +44,15 @@ namespace MWMechanics
|
|||
|
||||
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
{
|
||||
auto& stats = actor.getClass().getCreatureStats(actor);
|
||||
MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager();
|
||||
|
||||
if (stats.isTurningToPlayer() || stats.getGreetingState() == Greet_InProgress)
|
||||
if (mechMgr->isTurningToPlayer(actor) || mechMgr->getGreetingState(actor) == Greet_InProgress)
|
||||
return false;
|
||||
|
||||
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
const osg::Vec3f targetPos(mX, mY, mZ);
|
||||
|
||||
auto& stats = actor.getClass().getCreatureStats(actor);
|
||||
stats.setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
stats.setDrawState(DrawState_Nothing);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace AiSequence
|
|||
namespace MWMechanics
|
||||
{
|
||||
/// \brief Causes the AI to travel to the specified point
|
||||
class AiTravel : public AiPackage
|
||||
class AiTravel final : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
|
@ -22,21 +22,21 @@ namespace MWMechanics
|
|||
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||
|
||||
/// Simulates the passing of time
|
||||
virtual void fastForward(const MWWorld::Ptr& actor, AiState& state);
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
virtual AiTravel *clone() const;
|
||||
AiTravel *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual bool useVariableSpeed() const { return true;}
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
virtual bool alwaysActive() const { return true; }
|
||||
bool alwaysActive() const final { return true; }
|
||||
|
||||
virtual osg::Vec3f getDestination() const { return osg::Vec3f(mX, mY, mZ); }
|
||||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||
|
||||
private:
|
||||
float mX;
|
||||
|
|
|
@ -89,6 +89,11 @@ namespace MWMechanics
|
|||
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
|
||||
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, actor);
|
||||
}
|
||||
|
||||
void stopMovement(const MWWorld::Ptr& actor)
|
||||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||
|
@ -165,7 +170,7 @@ namespace MWMechanics
|
|||
* actors will enter combat (i.e. no longer wandering) and different pathfinding
|
||||
* will kick in.
|
||||
*/
|
||||
bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& /*characterController*/, AiState& state, float duration)
|
||||
{
|
||||
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
|
||||
if (cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
|
||||
|
@ -201,12 +206,12 @@ namespace MWMechanics
|
|||
storage.setState(AiWanderStorage::Wander_Walking);
|
||||
}
|
||||
|
||||
GreetingState greetingState = cStats.getGreetingState();
|
||||
GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor);
|
||||
if (greetingState == Greet_InProgress)
|
||||
{
|
||||
if (storage.mState == AiWanderStorage::Wander_Walking)
|
||||
{
|
||||
stopWalking(actor, storage, false);
|
||||
stopMovement(actor);
|
||||
mObstacleCheck.clear();
|
||||
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||
}
|
||||
|
@ -230,8 +235,9 @@ namespace MWMechanics
|
|||
if (mDistance <= 0)
|
||||
storage.mCanWanderAlongPathGrid = false;
|
||||
|
||||
if (isPackageCompleted(actor, storage))
|
||||
if (isPackageCompleted())
|
||||
{
|
||||
stopWalking(actor);
|
||||
// Reset package so it can be used again
|
||||
mRemainingDuration=mDuration;
|
||||
init();
|
||||
|
@ -315,19 +321,10 @@ namespace MWMechanics
|
|||
return actor.getRefData().getPosition().asVec3();
|
||||
}
|
||||
|
||||
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||
{
|
||||
if (mDuration)
|
||||
bool AiWander::isPackageCompleted() const
|
||||
{
|
||||
// End package if duration is complete
|
||||
if (mRemainingDuration <= 0)
|
||||
{
|
||||
stopWalking(actor, storage);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// if get here, not yet completed
|
||||
return false;
|
||||
return mDuration && mRemainingDuration <= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -395,7 +392,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
|
||||
stopWalking(actor, storage);
|
||||
stopWalking(actor);
|
||||
mObstacleCheck.clear();
|
||||
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||
}
|
||||
|
@ -445,7 +442,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
// Check if idle animation finished
|
||||
GreetingState greetingState = actor.getClass().getCreatureStats(actor).getGreetingState();
|
||||
GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor);
|
||||
if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None))
|
||||
{
|
||||
if (mPathFinder.isPathConstructed())
|
||||
|
@ -460,13 +457,13 @@ namespace MWMechanics
|
|||
// Is there no destination or are we there yet?
|
||||
if ((!mPathFinder.isPathConstructed()) || pathTo(actor, osg::Vec3f(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE))
|
||||
{
|
||||
stopWalking(actor, storage);
|
||||
stopWalking(actor);
|
||||
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// have not yet reached the destination
|
||||
evadeObstacles(actor, duration, storage);
|
||||
evadeObstacles(actor, storage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,15 +494,12 @@ namespace MWMechanics
|
|||
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||
}
|
||||
|
||||
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage)
|
||||
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||
{
|
||||
if (mUsePathgrid)
|
||||
{
|
||||
const auto halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
||||
const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration
|
||||
+ 1.2 * std::max(halfExtents.x(), halfExtents.y());
|
||||
const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance);
|
||||
mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor), pointTolerance);
|
||||
mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor));
|
||||
}
|
||||
|
||||
if (mObstacleCheck.isEvading())
|
||||
|
@ -518,7 +512,7 @@ namespace MWMechanics
|
|||
storage.mTrimCurrentNode = true;
|
||||
trimAllowedNodes(storage.mAllowedNodes, mPathFinder);
|
||||
mObstacleCheck.clear();
|
||||
stopWalking(actor, storage);
|
||||
stopWalking(actor);
|
||||
storage.setState(AiWanderStorage::Wander_MoveNow);
|
||||
}
|
||||
|
||||
|
@ -529,7 +523,7 @@ namespace MWMechanics
|
|||
if (storage.mStuckCount >= getCountBeforeReset(actor)) // something has gone wrong, reset
|
||||
{
|
||||
mObstacleCheck.clear();
|
||||
stopWalking(actor, storage);
|
||||
stopWalking(actor);
|
||||
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||
storage.mStuckCount = 0;
|
||||
}
|
||||
|
@ -609,14 +603,11 @@ namespace MWMechanics
|
|||
return TypeIdWander;
|
||||
}
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool clearPath)
|
||||
{
|
||||
if (clearPath)
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPathFinder.clearPath();
|
||||
mHasDestination = false;
|
||||
}
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
stopMovement(actor);
|
||||
}
|
||||
|
||||
bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace MWMechanics
|
|||
};
|
||||
|
||||
/// \brief Causes the Actor to wander within a specified range
|
||||
class AiWander : public AiPackage
|
||||
class AiWander final : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
|
@ -91,23 +91,23 @@ namespace MWMechanics
|
|||
|
||||
AiWander (const ESM::AiSequence::AiWander* wander);
|
||||
|
||||
virtual AiPackage *clone() const;
|
||||
AiPackage *clone() const final;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
virtual int getTypeId() const;
|
||||
int getTypeId() const final;
|
||||
|
||||
virtual bool useVariableSpeed() const { return true;}
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
virtual void fastForward(const MWWorld::Ptr& actor, AiState& state);
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||
|
||||
bool getRepeat() const;
|
||||
bool getRepeat() const final;
|
||||
|
||||
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const;
|
||||
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final;
|
||||
|
||||
virtual osg::Vec3f getDestination() const
|
||||
osg::Vec3f getDestination() const final
|
||||
{
|
||||
if (!mHasDestination)
|
||||
return osg::Vec3f(0, 0, 0);
|
||||
|
@ -118,7 +118,7 @@ namespace MWMechanics
|
|||
private:
|
||||
// NOTE: mDistance and mDuration must be set already
|
||||
void init();
|
||||
void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool clearPath = true);
|
||||
void stopWalking(const MWWorld::Ptr& actor);
|
||||
|
||||
/// Have the given actor play an idle animation
|
||||
/// @return Success or error
|
||||
|
@ -126,14 +126,14 @@ namespace MWMechanics
|
|||
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||
short unsigned getRandomIdle();
|
||||
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
|
||||
void evadeObstacles(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
||||
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||
void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage);
|
||||
void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
||||
void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
||||
void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
||||
void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
|
||||
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||
inline bool isPackageCompleted() const;
|
||||
void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance);
|
||||
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
|
||||
void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage);
|
||||
|
|
|
@ -262,6 +262,8 @@ namespace MWMechanics
|
|||
int duration = 0;
|
||||
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
duration = effect.mDuration;
|
||||
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce))
|
||||
duration = std::max(1, duration);
|
||||
|
||||
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore()
|
||||
.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat();
|
||||
|
|
|
@ -1013,7 +1013,7 @@ void split(const std::string &s, char delim, std::vector<std::string> &elems) {
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterController::handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key, const std::multimap<float, std::string> &map)
|
||||
void CharacterController::handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map)
|
||||
{
|
||||
const std::string &evt = key->second;
|
||||
|
||||
|
@ -1368,10 +1368,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
}
|
||||
}
|
||||
|
||||
// Use blending only with 3d-person movement animations for bipedal actors
|
||||
bool firstPersonPlayer = (mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson());
|
||||
// For biped actors, blend weapon animations with lower body animations with higher priority
|
||||
MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
|
||||
if (!firstPersonPlayer && mPtr.getClass().isBipedal(mPtr))
|
||||
if (mPtr.getClass().isBipedal(mPtr))
|
||||
priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
|
||||
|
||||
bool forcestateupdate = false;
|
||||
|
|
|
@ -238,8 +238,7 @@ public:
|
|||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||
virtual ~CharacterController();
|
||||
|
||||
virtual void handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
|
||||
const std::multimap<float, std::string>& map);
|
||||
virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map);
|
||||
|
||||
// Be careful when to call this, see comment in Actors
|
||||
void updateContinuousVfx();
|
||||
|
|
|
@ -34,53 +34,12 @@ namespace MWMechanics
|
|||
mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false),
|
||||
mHitRecovery(false), mBlock(false), mMovementFlags(0),
|
||||
mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1),
|
||||
mDeathAnimation(-1), mTimeOfDeath(), mGreetingState(Greet_None),
|
||||
mGreetingTimer(0), mTargetAngleRadians(0), mIsTurningToPlayer(false), mLevel (0)
|
||||
mDeathAnimation(-1), mTimeOfDeath(), mLevel (0)
|
||||
{
|
||||
for (int i=0; i<4; ++i)
|
||||
mAiSettings[i] = 0;
|
||||
}
|
||||
|
||||
int MWMechanics::CreatureStats::getGreetingTimer() const
|
||||
{
|
||||
return mGreetingTimer;
|
||||
}
|
||||
|
||||
void MWMechanics::CreatureStats::setGreetingTimer(int timer)
|
||||
{
|
||||
mGreetingTimer = timer;
|
||||
}
|
||||
|
||||
float MWMechanics::CreatureStats::getAngleToPlayer() const
|
||||
{
|
||||
return mTargetAngleRadians;
|
||||
}
|
||||
|
||||
void MWMechanics::CreatureStats::setAngleToPlayer(float angle)
|
||||
{
|
||||
mTargetAngleRadians = angle;
|
||||
}
|
||||
|
||||
GreetingState MWMechanics::CreatureStats::getGreetingState() const
|
||||
{
|
||||
return mGreetingState;
|
||||
}
|
||||
|
||||
void MWMechanics::CreatureStats::setGreetingState(GreetingState state)
|
||||
{
|
||||
mGreetingState = state;
|
||||
}
|
||||
|
||||
bool MWMechanics::CreatureStats::isTurningToPlayer() const
|
||||
{
|
||||
return mIsTurningToPlayer;
|
||||
}
|
||||
|
||||
void MWMechanics::CreatureStats::setTurningToPlayer(bool turning)
|
||||
{
|
||||
mIsTurningToPlayer = turning;
|
||||
}
|
||||
|
||||
const AiSequence& CreatureStats::getAiSequence() const
|
||||
{
|
||||
return mAiSequence;
|
||||
|
|
|
@ -19,13 +19,6 @@ namespace ESM
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
enum GreetingState
|
||||
{
|
||||
Greet_None,
|
||||
Greet_InProgress,
|
||||
Greet_Done
|
||||
};
|
||||
|
||||
/// \brief Common creature stats
|
||||
///
|
||||
///
|
||||
|
@ -77,11 +70,6 @@ namespace MWMechanics
|
|||
|
||||
MWWorld::TimeStamp mTimeOfDeath;
|
||||
|
||||
GreetingState mGreetingState;
|
||||
int mGreetingTimer;
|
||||
float mTargetAngleRadians;
|
||||
bool mIsTurningToPlayer;
|
||||
|
||||
public:
|
||||
typedef std::pair<int, std::string> SummonKey; // <ESM::MagicEffect index, spell ID>
|
||||
private:
|
||||
|
@ -97,18 +85,6 @@ namespace MWMechanics
|
|||
public:
|
||||
CreatureStats();
|
||||
|
||||
int getGreetingTimer() const;
|
||||
void setGreetingTimer(int timer);
|
||||
|
||||
float getAngleToPlayer() const;
|
||||
void setAngleToPlayer(float angle);
|
||||
|
||||
GreetingState getGreetingState() const;
|
||||
void setGreetingState(GreetingState state);
|
||||
|
||||
bool isTurningToPlayer() const;
|
||||
void setTurningToPlayer(bool turning);
|
||||
|
||||
DrawState_ getDrawState() const;
|
||||
void setDrawState(DrawState_ state);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "mechanicsmanagerimp.hpp"
|
||||
|
||||
#include <osg/Stats>
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
|
@ -2097,4 +2099,29 @@ namespace MWMechanics
|
|||
mActors.cleanupSummonedCreature(caster.getClass().getCreatureStats(caster), creatureActorId);
|
||||
}
|
||||
|
||||
void MechanicsManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||
{
|
||||
stats.setAttribute(frameNumber, "Mechanics Actors", mActors.size());
|
||||
stats.setAttribute(frameNumber, "Mechanics Objects", mObjects.size());
|
||||
}
|
||||
|
||||
int MechanicsManager::getGreetingTimer(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
return mActors.getGreetingTimer(ptr);
|
||||
}
|
||||
|
||||
float MechanicsManager::getAngleToPlayer(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
return mActors.getAngleToPlayer(ptr);
|
||||
}
|
||||
|
||||
GreetingState MechanicsManager::getGreetingState(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
return mActors.getGreetingState(ptr);
|
||||
}
|
||||
|
||||
bool MechanicsManager::isTurningToPlayer(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
return mActors.isTurningToPlayer(ptr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,6 +270,13 @@ namespace MWMechanics
|
|||
virtual bool isRunning(const MWWorld::Ptr& ptr) override;
|
||||
virtual bool isSneaking(const MWWorld::Ptr& ptr) override;
|
||||
|
||||
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;
|
||||
|
||||
virtual int getGreetingTimer(const MWWorld::Ptr& ptr) const override;
|
||||
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const override;
|
||||
virtual GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override;
|
||||
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override;
|
||||
|
||||
private:
|
||||
bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||
bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers);
|
||||
|
|
|
@ -52,6 +52,11 @@ namespace MWMechanics
|
|||
void persistAnimationStates();
|
||||
|
||||
void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out);
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return mObjects.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -361,7 +361,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents,
|
||||
const DetourNavigator::Flags flags, const float pointTolerance)
|
||||
const DetourNavigator::Flags flags)
|
||||
{
|
||||
if (mPath.empty())
|
||||
return;
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace MWMechanics
|
|||
const DetourNavigator::Flags flags);
|
||||
|
||||
void buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents,
|
||||
const DetourNavigator::Flags flags, const float pointTolerance);
|
||||
const DetourNavigator::Flags flags);
|
||||
|
||||
/// Remove front point if exist and within tolerance
|
||||
void update(const osg::Vec3f& position, const float pointTolerance, const float destinationTolerance);
|
||||
|
|
|
@ -200,6 +200,7 @@ namespace MWMechanics
|
|||
effect.mEffectId = effectIt->mEffectID;
|
||||
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
|
||||
effect.mMagnitude = magnitude;
|
||||
effect.mTimeLeft = 0.f;
|
||||
|
||||
// Avoid applying absorb effects if the caster is the target
|
||||
// We still need the spell to be added
|
||||
|
@ -224,10 +225,15 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
|
||||
if (hasDuration && effectIt->mDuration == 0)
|
||||
effect.mDuration = hasDuration ? static_cast<float>(effectIt->mDuration) : 1.f;
|
||||
|
||||
bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce;
|
||||
if (!appliedOnce)
|
||||
effect.mDuration = std::max(1.f, effect.mDuration);
|
||||
|
||||
if (effect.mDuration == 0)
|
||||
{
|
||||
// We still should add effect to list to allow GetSpellEffects to detect this spell
|
||||
effect.mDuration = 0.f;
|
||||
appliedLastingEffects.push_back(effect);
|
||||
|
||||
// duration 0 means apply full magnitude instantly
|
||||
|
@ -264,7 +270,7 @@ namespace MWMechanics
|
|||
}
|
||||
else
|
||||
{
|
||||
effect.mDuration = hasDuration ? static_cast<float>(effectIt->mDuration) : 1.f;
|
||||
effect.mTimeLeft = effect.mDuration;
|
||||
|
||||
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
|
||||
|
||||
|
|
|
@ -394,8 +394,9 @@ namespace MWMechanics
|
|||
priority = 10;
|
||||
const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||
const DynamicStat<float>& current = stats.getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth);
|
||||
// NB: this currently assumes the hardcoded magic effect flags are used
|
||||
const float magnitude = (effect.mMagnMin + effect.mMagnMax)/2.f;
|
||||
const float toHeal = magnitude * effect.mDuration;
|
||||
const float toHeal = magnitude * std::max(1, effect.mDuration);
|
||||
// Effect doesn't heal more than we need, *or* we are below 1/2 health
|
||||
if (current.getModified() - current.getCurrent() > toHeal
|
||||
|| current.getCurrent() < current.getModified()*0.5)
|
||||
|
|
|
@ -31,9 +31,12 @@ namespace MWMechanics
|
|||
magicEffect = store.get<ESM::MagicEffect>().find(effect.mEffectID);
|
||||
bool hasMagnitude = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude);
|
||||
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
|
||||
bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce;
|
||||
int minMagn = hasMagnitude ? effect.mMagnMin : 1;
|
||||
int maxMagn = hasMagnitude ? effect.mMagnMax : 1;
|
||||
int duration = hasDuration ? effect.mDuration : 1;
|
||||
if (!appliedOnce)
|
||||
duration = std::max(1, duration);
|
||||
static const float fEffectCostMult = store.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat();
|
||||
|
||||
float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "physicssystem.hpp"
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Stats>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btConeShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btSphereShape.h>
|
||||
|
@ -669,7 +670,7 @@ namespace MWPhysics
|
|||
bool cmode = found->second->getCollisionMode();
|
||||
cmode = !cmode;
|
||||
found->second->enableCollisionMode(cmode);
|
||||
found->second->enableCollisionBody(cmode);
|
||||
// NB: Collision body isn't disabled for vanilla TCL compatibility
|
||||
return cmode;
|
||||
}
|
||||
|
||||
|
@ -905,4 +906,11 @@ namespace MWPhysics
|
|||
mCollisionWorld->getBroadphase()->aabbTest(aabbMin, aabbMax, callback);
|
||||
return callback.getResult();
|
||||
}
|
||||
|
||||
void PhysicsSystem::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||
{
|
||||
stats.setAttribute(frameNumber, "Physics Actors", mActors.size());
|
||||
stats.setAttribute(frameNumber, "Physics Objects", mObjects.size());
|
||||
stats.setAttribute(frameNumber, "Physics HeightFields", mHeightFields.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace osg
|
|||
{
|
||||
class Group;
|
||||
class Object;
|
||||
class Stats;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -196,6 +197,8 @@ namespace MWPhysics
|
|||
|
||||
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const;
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||
|
||||
private:
|
||||
|
||||
void updateWater();
|
||||
|
|
|
@ -151,20 +151,8 @@ namespace
|
|||
}
|
||||
};
|
||||
|
||||
NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname)
|
||||
{
|
||||
NifOsg::TextKeyMap::const_iterator iter(keys.begin());
|
||||
for(;iter != keys.end();++iter)
|
||||
{
|
||||
if(iter->second.compare(0, groupname.size(), groupname) == 0 &&
|
||||
iter->second.compare(groupname.size(), 2, ": ") == 0)
|
||||
break;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
float calcAnimVelocity(const std::multimap<float, std::string>& keys,
|
||||
NifOsg::KeyframeController *nonaccumctrl, const osg::Vec3f& accum, const std::string &groupname)
|
||||
float calcAnimVelocity(const NifOsg::TextKeyMap& keys, NifOsg::KeyframeController *nonaccumctrl,
|
||||
const osg::Vec3f& accum, const std::string &groupname)
|
||||
{
|
||||
const std::string start = groupname+": start";
|
||||
const std::string loopstart = groupname+": loop start";
|
||||
|
@ -179,7 +167,7 @@ namespace
|
|||
// but the animation velocity calculation uses the second one.
|
||||
// As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated,
|
||||
// because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough.
|
||||
NifOsg::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin());
|
||||
auto keyiter = keys.rbegin();
|
||||
while(keyiter != keys.rend())
|
||||
{
|
||||
if(keyiter->second == start || keyiter->second == loopstart)
|
||||
|
@ -553,7 +541,7 @@ namespace MWRender
|
|||
|
||||
ControllerMap mControllerMap[Animation::sNumBlendMasks];
|
||||
|
||||
const std::multimap<float, std::string>& getTextKeys() const;
|
||||
const NifOsg::TextKeyMap& getTextKeys() const;
|
||||
};
|
||||
|
||||
void UpdateVfxCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
|
@ -702,7 +690,7 @@ namespace MWRender
|
|||
return 0;
|
||||
}
|
||||
|
||||
const std::multimap<float, std::string> &Animation::AnimSource::getTextKeys() const
|
||||
const NifOsg::TextKeyMap &Animation::AnimSource::getTextKeys() const
|
||||
{
|
||||
return mKeyframes->mTextKeys;
|
||||
}
|
||||
|
@ -825,7 +813,7 @@ namespace MWRender
|
|||
for(;iter != mAnimSources.end();++iter)
|
||||
{
|
||||
const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys();
|
||||
if(findGroupStart(keys, anim) != keys.end())
|
||||
if (keys.hasGroupStart(anim))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -838,7 +826,7 @@ namespace MWRender
|
|||
{
|
||||
const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys();
|
||||
|
||||
NifOsg::TextKeyMap::const_iterator found = findGroupStart(keys, groupname);
|
||||
const auto found = keys.findGroupStart(groupname);
|
||||
if(found != keys.end())
|
||||
return found->first;
|
||||
}
|
||||
|
@ -851,7 +839,7 @@ namespace MWRender
|
|||
{
|
||||
const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys();
|
||||
|
||||
for(NifOsg::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey)
|
||||
for(auto iterKey = keys.begin(); iterKey != keys.end(); ++iterKey)
|
||||
{
|
||||
if(iterKey->second.compare(0, textKey.size(), textKey) == 0)
|
||||
return iterKey->first;
|
||||
|
@ -861,8 +849,8 @@ namespace MWRender
|
|||
return -1.f;
|
||||
}
|
||||
|
||||
void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
|
||||
const std::multimap<float, std::string>& map)
|
||||
void Animation::handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key,
|
||||
const NifOsg::TextKeyMap& map)
|
||||
{
|
||||
const std::string &evt = key->second;
|
||||
|
||||
|
@ -939,7 +927,7 @@ namespace MWRender
|
|||
|
||||
if (state.mPlaying)
|
||||
{
|
||||
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
|
||||
auto textkey = textkeys.lowerBound(state.getTime());
|
||||
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
||||
{
|
||||
handleTextKey(state, groupname, textkey, textkeys);
|
||||
|
@ -955,7 +943,7 @@ namespace MWRender
|
|||
if(state.getTime() >= state.mLoopStopTime)
|
||||
break;
|
||||
|
||||
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
|
||||
auto textkey = textkeys.lowerBound(state.getTime());
|
||||
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
||||
{
|
||||
handleTextKey(state, groupname, textkey, textkeys);
|
||||
|
@ -974,7 +962,7 @@ namespace MWRender
|
|||
{
|
||||
// Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two
|
||||
// separate walkforward keys, and the last one is supposed to be used.
|
||||
NifOsg::TextKeyMap::const_reverse_iterator groupend(keys.rbegin());
|
||||
auto groupend = keys.rbegin();
|
||||
for(;groupend != keys.rend();++groupend)
|
||||
{
|
||||
if(groupend->second.compare(0, groupname.size(), groupname) == 0 &&
|
||||
|
@ -983,7 +971,7 @@ namespace MWRender
|
|||
}
|
||||
|
||||
std::string starttag = groupname+": "+start;
|
||||
NifOsg::TextKeyMap::const_reverse_iterator startkey(groupend);
|
||||
auto startkey = groupend;
|
||||
while(startkey != keys.rend() && startkey->second != starttag)
|
||||
++startkey;
|
||||
if(startkey == keys.rend() && start == "loop start")
|
||||
|
@ -997,7 +985,7 @@ namespace MWRender
|
|||
return false;
|
||||
|
||||
const std::string stoptag = groupname+": "+stop;
|
||||
NifOsg::TextKeyMap::const_reverse_iterator stopkey(groupend);
|
||||
auto stopkey = groupend;
|
||||
while(stopkey != keys.rend()
|
||||
// We have to ignore extra garbage at the end.
|
||||
// The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop".
|
||||
|
@ -1030,7 +1018,7 @@ namespace MWRender
|
|||
const std::string loopstarttag = groupname+": loop start";
|
||||
const std::string loopstoptag = groupname+": loop stop";
|
||||
|
||||
NifOsg::TextKeyMap::const_reverse_iterator key(groupend);
|
||||
auto key = groupend;
|
||||
for (; key != startkey && key != keys.rend(); ++key)
|
||||
{
|
||||
if (key->first > state.getTime())
|
||||
|
@ -1064,7 +1052,7 @@ namespace MWRender
|
|||
void Animation::resetActiveGroups()
|
||||
{
|
||||
// remove all previous external controllers from the scene graph
|
||||
for (ControllerMap::iterator it = mActiveControllers.begin(); it != mActiveControllers.end(); ++it)
|
||||
for (auto it = mActiveControllers.begin(); it != mActiveControllers.end(); ++it)
|
||||
{
|
||||
osg::Node* node = it->first;
|
||||
node->removeUpdateCallback(it->second);
|
||||
|
@ -1103,7 +1091,7 @@ namespace MWRender
|
|||
osg::ref_ptr<osg::Node> node = getNodeMap().at(it->first); // this should not throw, we already checked for the node existing in addAnimSource
|
||||
|
||||
node->addUpdateCallback(it->second);
|
||||
mActiveControllers.insert(std::make_pair(node, it->second));
|
||||
mActiveControllers.emplace_back(node, it->second);
|
||||
|
||||
if (blendMask == 0 && node == mAccumRoot)
|
||||
{
|
||||
|
@ -1116,7 +1104,7 @@ namespace MWRender
|
|||
mResetAccumRootCallback->setAccumulate(mAccumulate);
|
||||
}
|
||||
mAccumRoot->addUpdateCallback(mResetAccumRootCallback);
|
||||
mActiveControllers.insert(std::make_pair(mAccumRoot, mResetAccumRootCallback));
|
||||
mActiveControllers.emplace_back(mAccumRoot, mResetAccumRootCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1201,7 +1189,7 @@ namespace MWRender
|
|||
for(;animsrc != mAnimSources.rend();++animsrc)
|
||||
{
|
||||
const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys();
|
||||
if(findGroupStart(keys, groupname) != keys.end())
|
||||
if (keys.hasGroupStart(groupname))
|
||||
break;
|
||||
}
|
||||
if(animsrc == mAnimSources.rend())
|
||||
|
@ -1280,7 +1268,7 @@ namespace MWRender
|
|||
}
|
||||
|
||||
const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys();
|
||||
NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.getTime()));
|
||||
auto textkey = textkeys.upperBound(state.getTime());
|
||||
|
||||
float timepassed = duration * state.mSpeedMult;
|
||||
while(state.mPlaying)
|
||||
|
@ -1316,7 +1304,7 @@ namespace MWRender
|
|||
state.setTime(state.mLoopStartTime);
|
||||
state.mPlaying = true;
|
||||
|
||||
textkey = textkeys.lower_bound(state.getTime());
|
||||
textkey = textkeys.lowerBound(state.getTime());
|
||||
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
||||
{
|
||||
handleTextKey(state, stateiter->first, textkey, textkeys);
|
||||
|
@ -1827,11 +1815,10 @@ namespace MWRender
|
|||
{
|
||||
mHeadController = nullptr;
|
||||
|
||||
if (mPtr.getClass().isBipedal(mPtr))
|
||||
{
|
||||
NodeMap::const_iterator found = getNodeMap().find("bip01 head");
|
||||
if (found != getNodeMap().end())
|
||||
{
|
||||
if (found == getNodeMap().end())
|
||||
return;
|
||||
|
||||
osg::MatrixTransform* node = found->second;
|
||||
|
||||
bool foundKeyframeCtrl = false;
|
||||
|
@ -1846,14 +1833,12 @@ namespace MWRender
|
|||
cb = cb->getNestedCallback();
|
||||
}
|
||||
|
||||
if (foundKeyframeCtrl)
|
||||
{
|
||||
if (!foundKeyframeCtrl)
|
||||
return;
|
||||
|
||||
mHeadController = new RotateController(mObjectRoot.get());
|
||||
node->addUpdateCallback(mHeadController);
|
||||
mActiveControllers.insert(std::make_pair(node, mHeadController));
|
||||
}
|
||||
}
|
||||
}
|
||||
mActiveControllers.emplace_back(node, mHeadController);
|
||||
}
|
||||
|
||||
void Animation::setHeadPitch(float pitchRadians)
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/nifosg/textkeymap.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -147,8 +150,8 @@ public:
|
|||
class TextKeyListener
|
||||
{
|
||||
public:
|
||||
virtual void handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
|
||||
const std::multimap<float, std::string>& map) = 0;
|
||||
virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key,
|
||||
const NifOsg::TextKeyMap& map) = 0;
|
||||
|
||||
virtual ~TextKeyListener() = default;
|
||||
};
|
||||
|
@ -246,8 +249,7 @@ protected:
|
|||
|
||||
// Keep track of controllers that we added to our scene graph.
|
||||
// We may need to rebuild these controllers when the active animation groups / sources change.
|
||||
typedef std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> > ControllerMap;
|
||||
ControllerMap mActiveControllers;
|
||||
std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback>>> mActiveControllers;
|
||||
|
||||
std::shared_ptr<AnimationTime> mAnimationTimePtr[sNumBlendMasks];
|
||||
|
||||
|
@ -296,12 +298,12 @@ protected:
|
|||
* the marker is not found, or if the markers are the same, it returns
|
||||
* false.
|
||||
*/
|
||||
bool reset(AnimState &state, const std::multimap<float, std::string> &keys,
|
||||
bool reset(AnimState &state, const NifOsg::TextKeyMap &keys,
|
||||
const std::string &groupname, const std::string &start, const std::string &stop,
|
||||
float startpoint, bool loopfallback);
|
||||
|
||||
void handleTextKey(AnimState &state, const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
|
||||
const std::multimap<float, std::string>& map);
|
||||
void handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key,
|
||||
const NifOsg::TextKeyMap& map);
|
||||
|
||||
/** Sets the root model of the object.
|
||||
*
|
||||
|
|
|
@ -956,7 +956,7 @@ void NpcAnimation::addControllers()
|
|||
osg::MatrixTransform* node = found->second.get();
|
||||
mFirstPersonNeckController = new NeckController(mObjectRoot.get());
|
||||
node->addUpdateCallback(mFirstPersonNeckController);
|
||||
mActiveControllers.emplace(node, mFirstPersonNeckController);
|
||||
mActiveControllers.emplace_back(node, mFirstPersonNeckController);
|
||||
}
|
||||
}
|
||||
else if (mViewMode == VM_Normal)
|
||||
|
|
|
@ -231,7 +231,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
|
|||
}
|
||||
|
||||
void WeaponAnimation::addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
|
||||
std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> > &map, osg::Node* objectRoot)
|
||||
std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback>>> &map, osg::Node* objectRoot)
|
||||
{
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ void WeaponAnimation::addControllers(const std::map<std::string, osg::ref_ptr<os
|
|||
osg::Node* node = found->second;
|
||||
mSpineControllers[i] = new RotateController(objectRoot);
|
||||
node->addUpdateCallback(mSpineControllers[i]);
|
||||
map.insert(std::make_pair(node, mSpineControllers[i]));
|
||||
map.emplace_back(node, mSpineControllers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace MWRender
|
|||
|
||||
/// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map.
|
||||
void addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
|
||||
std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> >& map, osg::Node* objectRoot);
|
||||
std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback>>>& map, osg::Node* objectRoot);
|
||||
|
||||
void deleteControllers();
|
||||
|
||||
|
|
|
@ -496,13 +496,12 @@ namespace MWScript
|
|||
if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId)
|
||||
targetsAreEqual = true;
|
||||
}
|
||||
else
|
||||
else if (testedTargetId == "player") // Currently the player ID is hardcoded
|
||||
{
|
||||
bool turningToPlayer = creatureStats.isTurningToPlayer();
|
||||
bool greeting = creatureStats.getGreetingState() == MWMechanics::Greet_InProgress;
|
||||
MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager();
|
||||
bool greeting = mechMgr->getGreetingState(actor) == MWMechanics::Greet_InProgress;
|
||||
bool sayActive = MWBase::Environment::get().getSoundManager()->sayActive(actor);
|
||||
if (turningToPlayer || (greeting && sayActive))
|
||||
targetsAreEqual = (testedTargetId == "player"); // Currently the player ID is hardcoded
|
||||
targetsAreEqual = (greeting && sayActive) || mechMgr->isTurningToPlayer(actor);
|
||||
}
|
||||
runtime.push(int(targetsAreEqual));
|
||||
}
|
||||
|
|
|
@ -464,5 +464,20 @@ op 0x200030d: RepairedOnMe, explicit
|
|||
op 0x200030e: TestCells
|
||||
op 0x200030f: TestInteriorCells
|
||||
op 0x2000310: ToggleRecastMesh
|
||||
op 0x2000311: MenuMode
|
||||
op 0x2000312: Random
|
||||
op 0x2000313: ScriptRunning
|
||||
op 0x2000314: StartScript
|
||||
op 0x2000315: StopScript
|
||||
op 0x2000316: GetSecondsPassed
|
||||
op 0x2000317: Enable
|
||||
op 0x2000318: Disable
|
||||
op 0x2000319: GetDisabled
|
||||
op 0x200031a: Enable, explicit
|
||||
op 0x200031b: Disable, explicit
|
||||
op 0x200031c: GetDisabled, explicit
|
||||
op 0x200031d: StartScript, explicit
|
||||
op 0x200031e: GetDistance
|
||||
op 0x200031f: GetDistance, explicit
|
||||
|
||||
opcodes 0x2000311-0x3ffffff unused
|
||||
opcodes 0x2000320-0x3ffffff unused
|
||||
|
|
|
@ -315,20 +315,6 @@ namespace MWScript
|
|||
{
|
||||
}
|
||||
|
||||
bool InterpreterContext::menuMode()
|
||||
{
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Being in a menu should not pause scripts in multiplayer, so always return false
|
||||
*/
|
||||
//return MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
return false;
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
|
||||
int InterpreterContext::getGlobalShort (const std::string& name) const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->getGlobalInt (name);
|
||||
|
@ -627,58 +613,6 @@ namespace MWScript
|
|||
return MWBase::Environment::get().getWorld()->getCellName();
|
||||
}
|
||||
|
||||
bool InterpreterContext::isScriptRunning (const std::string& name) const
|
||||
{
|
||||
return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name);
|
||||
}
|
||||
|
||||
void InterpreterContext::startScript (const std::string& name, const std::string& targetId)
|
||||
{
|
||||
MWWorld::Ptr target;
|
||||
if (targetId.empty())
|
||||
target = getReference(false);
|
||||
else
|
||||
target = getReferenceImp(targetId);
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target);
|
||||
}
|
||||
|
||||
void InterpreterContext::stopScript (const std::string& name)
|
||||
{
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().removeScript (name);
|
||||
}
|
||||
|
||||
float InterpreterContext::getDistance (const std::string& name, const std::string& id) const
|
||||
{
|
||||
// NOTE: id may be empty, indicating an implicit reference
|
||||
|
||||
MWWorld::Ptr ref2 = getReferenceImp(id);
|
||||
|
||||
if (ref2.getContainerStore()) // is the object contained?
|
||||
{
|
||||
MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(ref2);
|
||||
|
||||
if (!container.isEmpty())
|
||||
ref2 = container;
|
||||
else
|
||||
throw std::runtime_error("failed to find container ptr");
|
||||
}
|
||||
|
||||
const MWWorld::Ptr ref = MWBase::Environment::get().getWorld()->getPtr(name, false);
|
||||
|
||||
// If the objects are in different worldspaces, return a large value (just like vanilla)
|
||||
if (!ref.isInCell() || !ref2.isInCell() || ref.getCell()->getCell()->getCellId().mWorldspace != ref2.getCell()->getCell()->getCellId().mWorldspace)
|
||||
return std::numeric_limits<float>::max();
|
||||
|
||||
double diff[3];
|
||||
|
||||
const float* const pos1 = ref.getRefData().getPosition().pos;
|
||||
const float* const pos2 = ref2.getRefData().getPosition().pos;
|
||||
for (int i=0; i<3; ++i)
|
||||
diff[i] = pos1[i] - pos2[i];
|
||||
|
||||
return static_cast<float>(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]));
|
||||
}
|
||||
|
||||
void InterpreterContext::executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor)
|
||||
{
|
||||
std::shared_ptr<MWWorld::Action> action = (ptr.getClass().activate(ptr, actor));
|
||||
|
@ -689,101 +623,6 @@ namespace MWScript
|
|||
}
|
||||
}
|
||||
|
||||
float InterpreterContext::getSecondsPassed() const
|
||||
{
|
||||
return MWBase::Environment::get().getFrameDuration();
|
||||
}
|
||||
|
||||
bool InterpreterContext::isDisabled (const std::string& id) const
|
||||
{
|
||||
const MWWorld::Ptr ref = getReferenceImp (id, false);
|
||||
return !ref.getRefData().isEnabled();
|
||||
}
|
||||
|
||||
void InterpreterContext::enable (const std::string& id)
|
||||
{
|
||||
MWWorld::Ptr ref = getReferenceImp (id, false);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as
|
||||
the player is logged in on the server, the object is still disabled, and our last
|
||||
packet regarding its state did not already attempt to enable it (to prevent
|
||||
packet spam)
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
if (ref.isInCell() && !ref.getRefData().isEnabled() &&
|
||||
ref.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled)
|
||||
{
|
||||
ref.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Enabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||
objectList->addObjectState(ref, true);
|
||||
objectList->sendObjectState();
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Disable unilateral state enabling on this client and expect the server's reply to our
|
||||
packet to do it instead
|
||||
*/
|
||||
//MWBase::Environment::get().getWorld()->enable (ref);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
|
||||
void InterpreterContext::disable (const std::string& id)
|
||||
{
|
||||
MWWorld::Ptr ref = getReferenceImp (id, false);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as
|
||||
the player is logged in on the server, the object is still enabled, and our last
|
||||
packet regarding its state did not already attempt to disable it (to prevent
|
||||
packet spam)
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
if (ref.isInCell() && ref.getRefData().isEnabled() &&
|
||||
ref.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled)
|
||||
{
|
||||
ref.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Disabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||
objectList->addObjectState(ref, false);
|
||||
objectList->sendObjectState();
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Disable unilateral state disabling on this client and expect the server's reply to our
|
||||
packet to do it instead
|
||||
*/
|
||||
//MWBase::Environment::get().getWorld()->disable (ref);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
|
||||
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
|
|
|
@ -102,8 +102,6 @@ namespace MWScript
|
|||
virtual void report (const std::string& message);
|
||||
///< By default, do nothing.
|
||||
|
||||
virtual bool menuMode();
|
||||
|
||||
virtual int getGlobalShort (const std::string& name) const;
|
||||
|
||||
virtual int getGlobalLong (const std::string& name) const;
|
||||
|
@ -146,26 +144,9 @@ namespace MWScript
|
|||
|
||||
virtual std::string getCurrentCellName() const;
|
||||
|
||||
virtual bool isScriptRunning (const std::string& name) const;
|
||||
|
||||
virtual void startScript (const std::string& name, const std::string& targetId = "");
|
||||
|
||||
virtual void stopScript (const std::string& name);
|
||||
|
||||
virtual float getDistance (const std::string& name, const std::string& id = "") const;
|
||||
///< @note if \a id is empty, assumes an implicit reference
|
||||
|
||||
void executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor);
|
||||
///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled.
|
||||
|
||||
virtual float getSecondsPassed() const;
|
||||
|
||||
virtual bool isDisabled (const std::string& id = "") const;
|
||||
|
||||
virtual void enable (const std::string& id = "");
|
||||
|
||||
virtual void disable (const std::string& id = "");
|
||||
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const;
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <components/interpreter/runtime.hpp>
|
||||
#include <components/interpreter/opcodes.hpp>
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
|
||||
|
@ -92,6 +94,198 @@ namespace MWScript
|
|||
{
|
||||
namespace Misc
|
||||
{
|
||||
class OpMenuMode : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Being in a menu should not pause scripts in multiplayer, so always return false
|
||||
*/
|
||||
//runtime.push (MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
runtime.push(false);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
class OpRandom : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
Interpreter::Type_Integer limit = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (limit<0)
|
||||
throw std::runtime_error (
|
||||
"random: argument out of range (Don't be so negative!)");
|
||||
|
||||
runtime.push (static_cast<Interpreter::Type_Float>(::Misc::Rng::rollDice(limit))); // [o, limit)
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpStartScript : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr target = R()(runtime, false);
|
||||
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target);
|
||||
}
|
||||
};
|
||||
|
||||
class OpScriptRunning : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
runtime.push(MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name));
|
||||
}
|
||||
};
|
||||
|
||||
class OpStopScript : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().removeScript (name);
|
||||
}
|
||||
};
|
||||
|
||||
class OpGetSecondsPassed : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
runtime.push (MWBase::Environment::get().getFrameDuration());
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpEnable : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as
|
||||
the player is logged in on the server, the object is still disabled, and our last
|
||||
packet regarding its state did not already attempt to enable it (to prevent
|
||||
packet spam)
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
if (ptr.isInCell() && !ptr.getRefData().isEnabled() &&
|
||||
ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled)
|
||||
{
|
||||
ptr.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Enabled);
|
||||
|
||||
mwmp::ObjectList* objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectState(ptr, true);
|
||||
objectList->sendObjectState();
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Disable unilateral state enabling on this client and expect the server's reply to our
|
||||
packet to do it instead
|
||||
*/
|
||||
//MWBase::Environment::get().getWorld()->enable (ptr);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpDisable : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as
|
||||
the player is logged in on the server, the object is still enabled, and our last
|
||||
packet regarding its state did not already attempt to disable it (to prevent
|
||||
packet spam)
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
if (ptr.isInCell() && ptr.getRefData().isEnabled() &&
|
||||
ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled)
|
||||
{
|
||||
ptr.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Disabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectState(ptr, false);
|
||||
objectList->sendObjectState();
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Disable unilateral state disabling on this client and expect the server's reply to our
|
||||
packet to do it instead
|
||||
*/
|
||||
//MWBase::Environment::get().getWorld()->disable (ptr);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpGetDisabled : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
runtime.push (!ptr.getRefData().isEnabled());
|
||||
}
|
||||
};
|
||||
|
||||
class OpPlayBink : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
@ -1575,6 +1769,19 @@ namespace MWScript
|
|||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeMenuMode, new OpMenuMode);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRandom, new OpRandom);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeScriptRunning, new OpScriptRunning);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeStartScript, new OpStartScript<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeStartScriptExplicit, new OpStartScript<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeStopScript, new OpStopScript);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetSecondsPassed, new OpGetSecondsPassed);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeEnable, new OpEnable<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeEnableExplicit, new OpEnable<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDisable, new OpDisable<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDisableExplicit, new OpDisable<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetDisabled, new OpGetDisabled<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetDisabledExplicit, new OpGetDisabled<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeOnActivateExplicit, new OpOnActivate<ExplicitRef>);
|
||||
|
|
|
@ -56,6 +56,63 @@ namespace MWScript
|
|||
}
|
||||
}
|
||||
|
||||
template<class R>
|
||||
class OpGetDistance : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr from = R()(runtime);
|
||||
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
if (from.getContainerStore()) // is the object contained?
|
||||
{
|
||||
MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(from);
|
||||
|
||||
if (!container.isEmpty())
|
||||
from = container;
|
||||
else
|
||||
{
|
||||
std::string error = "Failed to find the container of object '" + from.getCellRef().getRefId() + "'";
|
||||
runtime.getContext().report(error);
|
||||
Log(Debug::Error) << error;
|
||||
runtime.push(0.f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const MWWorld::Ptr to = MWBase::Environment::get().getWorld()->searchPtr(name, false);
|
||||
if (to.isEmpty())
|
||||
{
|
||||
std::string error = "Failed to find an instance of object '" + name + "'";
|
||||
runtime.getContext().report(error);
|
||||
Log(Debug::Error) << error;
|
||||
runtime.push(0.f);
|
||||
return;
|
||||
}
|
||||
|
||||
float distance;
|
||||
// If the objects are in different worldspaces, return a large value (just like vanilla)
|
||||
if (!to.isInCell() || !from.isInCell() || to.getCell()->getCell()->getCellId().mWorldspace != from.getCell()->getCell()->getCellId().mWorldspace)
|
||||
distance = std::numeric_limits<float>::max();
|
||||
else
|
||||
{
|
||||
double diff[3];
|
||||
|
||||
const float* const pos1 = to.getRefData().getPosition().pos;
|
||||
const float* const pos2 = from.getRefData().getPosition().pos;
|
||||
for (int i=0; i<3; ++i)
|
||||
diff[i] = pos1[i] - pos2[i];
|
||||
|
||||
distance = static_cast<float>(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]));
|
||||
}
|
||||
|
||||
runtime.push(distance);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpSetScale : public Interpreter::Opcode0
|
||||
{
|
||||
|
@ -902,6 +959,8 @@ namespace MWScript
|
|||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeGetDistance, new OpGetDistance<ImplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeGetDistanceExplicit, new OpGetDistance<ExplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeSetScale,new OpSetScale<ImplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeSetScaleExplicit,new OpSetScale<ExplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeSetAngle,new OpSetAngle<ImplicitRef>);
|
||||
|
|
|
@ -240,12 +240,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||
|
||||
ESM::ESMWriter writer;
|
||||
|
||||
const std::vector<std::string>& current =
|
||||
MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end();
|
||||
++iter)
|
||||
writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0
|
||||
for (const std::string& contentFile : MWBase::Environment::get().getWorld()->getContentFiles())
|
||||
writer.addMaster(contentFile, 0); // not using the size information anyway -> use value of 0
|
||||
|
||||
writer.setFormat (ESM::SavedGame::sCurrentFormat);
|
||||
|
||||
|
@ -356,10 +352,10 @@ void MWState::StateManager::quickSave (std::string name)
|
|||
|
||||
if (currentCharacter)
|
||||
{
|
||||
for (Character::SlotIterator it = currentCharacter->begin(); it != currentCharacter->end(); ++it)
|
||||
for (auto& save : *currentCharacter)
|
||||
{
|
||||
//Visiting slots allows the quicksave finder to find the oldest quicksave
|
||||
saveFinder.visitSave(&*it);
|
||||
saveFinder.visitSave(&save);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,12 +366,10 @@ void MWState::StateManager::quickSave (std::string name)
|
|||
|
||||
void MWState::StateManager::loadGame(const std::string& filepath)
|
||||
{
|
||||
for (CharacterIterator it = mCharacterManager.begin(); it != mCharacterManager.end(); ++it)
|
||||
for (const auto& character : mCharacterManager)
|
||||
{
|
||||
const MWState::Character& character = *it;
|
||||
for (MWState::Character::SlotIterator slotIt = character.begin(); slotIt != character.end(); ++slotIt)
|
||||
for (const auto& slot : character)
|
||||
{
|
||||
const MWState::Slot& slot = *slotIt;
|
||||
if (slot.mPath == boost::filesystem::path(filepath))
|
||||
{
|
||||
loadGame(&character, slot.mPath.string());
|
||||
|
@ -650,13 +644,12 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const
|
|||
{
|
||||
const std::vector<std::string>& selectedContentFiles = MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
bool notFound = false;
|
||||
for (std::vector<std::string>::const_iterator it = profile.mContentFiles.begin();
|
||||
it != profile.mContentFiles.end(); ++it)
|
||||
for (const std::string& contentFile : profile.mContentFiles)
|
||||
{
|
||||
if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it)
|
||||
if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), contentFile)
|
||||
== selectedContentFiles.end())
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: Saved game dependency " << *it << " is missing.";
|
||||
Log(Debug::Warning) << "Warning: Saved game dependency " << contentFile << " is missing.";
|
||||
notFound = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -785,7 +785,10 @@ namespace MWWorld
|
|||
Ptr ret = searchPtr(name, activeOnly);
|
||||
if (!ret.isEmpty())
|
||||
return ret;
|
||||
throw std::runtime_error ("unknown ID: " + name);
|
||||
std::string error = "failed to find an instance of object '" + name + "'";
|
||||
if (activeOnly)
|
||||
error += " in active cells";
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
Ptr World::searchPtrViaActorId (int actorId)
|
||||
|
@ -4509,4 +4512,10 @@ namespace MWWorld
|
|||
{
|
||||
return mPhysics->isAreaOccupiedByOtherActor(position, radius, ignore);
|
||||
}
|
||||
|
||||
void World::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||
{
|
||||
mNavigator->reportStats(frameNumber, stats);
|
||||
mPhysics->reportStats(frameNumber, stats);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
class Stats;
|
||||
}
|
||||
|
||||
namespace osgViewer
|
||||
|
@ -920,6 +921,8 @@ namespace MWWorld
|
|||
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
|
||||
|
||||
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const override;
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ add_component_dir (compiler
|
|||
|
||||
add_component_dir (interpreter
|
||||
context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes
|
||||
miscopcodes opcodes runtime scriptopcodes spatialopcodes types defines
|
||||
miscopcodes opcodes runtime types defines
|
||||
)
|
||||
|
||||
add_component_dir (translation
|
||||
|
@ -368,3 +368,7 @@ endif()
|
|||
|
||||
# Make the variable accessible for other subdirectories
|
||||
set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE)
|
||||
|
||||
if (BULLET_USE_DOUBLES)
|
||||
add_definitions(-DBT_USE_DOUBLE_PRECISION)
|
||||
endif()
|
||||
|
|
|
@ -372,9 +372,7 @@ namespace Compiler
|
|||
keyword==Scanner::K_elseif || keyword==Scanner::K_while ||
|
||||
keyword==Scanner::K_endwhile || keyword==Scanner::K_return ||
|
||||
keyword==Scanner::K_messagebox || keyword==Scanner::K_set ||
|
||||
keyword==Scanner::K_to || keyword==Scanner::K_startscript ||
|
||||
keyword==Scanner::K_stopscript || keyword==Scanner::K_enable ||
|
||||
keyword==Scanner::K_disable)
|
||||
keyword==Scanner::K_to)
|
||||
{
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
|
@ -385,53 +383,6 @@ namespace Compiler
|
|||
{
|
||||
if (mRefOp && mNextOperand)
|
||||
{
|
||||
if (keyword==Scanner::K_getdisabled)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::getDisabled (mCode, mLiterals, mExplicit);
|
||||
mOperands.push_back ('l');
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
|
||||
std::vector<Interpreter::Type_Code> ignore;
|
||||
parseArguments ("x", scanner, ignore);
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getdistance)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::getDistance (mCode, mLiterals, mExplicit);
|
||||
mOperands.push_back ('f');
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_scriptrunning)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::scriptRunning (mCode);
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for custom extensions
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
|
@ -483,84 +434,6 @@ namespace Compiler
|
|||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_menumode)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::menuMode (mCode);
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_random)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("l", scanner);
|
||||
|
||||
Generator::random (mCode);
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_scriptrunning)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::scriptRunning (mCode);
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getdistance)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::getDistance (mCode, mLiterals, "");
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getsecondspassed)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::getSecondsPassed (mCode);
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getdisabled)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::getDisabled (mCode, mLiterals, "");
|
||||
mOperands.push_back ('l');
|
||||
|
||||
std::vector<Interpreter::Type_Code> ignore;
|
||||
parseArguments ("x", scanner, ignore);
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check for custom extensions
|
||||
|
|
|
@ -241,6 +241,15 @@ namespace Compiler
|
|||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerFunction ("menumode", 'l', "", opcodeMenuMode);
|
||||
extensions.registerFunction ("random", 'f', "l", opcodeRandom);
|
||||
extensions.registerFunction ("scriptrunning", 'l', "c", opcodeScriptRunning);
|
||||
extensions.registerInstruction ("startscript", "c", opcodeStartScript, opcodeStartScriptExplicit);
|
||||
extensions.registerInstruction ("stopscript", "c", opcodeStopScript);
|
||||
extensions.registerFunction ("getsecondspassed", 'f', "", opcodeGetSecondsPassed);
|
||||
extensions.registerInstruction ("enable", "", opcodeEnable, opcodeEnableExplicit);
|
||||
extensions.registerInstruction ("disable", "", opcodeDisable, opcodeDisableExplicit);
|
||||
extensions.registerFunction ("getdisabled", 'l', "x", opcodeGetDisabled, opcodeGetDisabledExplicit);
|
||||
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
|
||||
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate, opcodeOnActivateExplicit);
|
||||
extensions.registerInstruction ("activate", "x", opcodeActivate, opcodeActivateExplicit);
|
||||
|
@ -533,6 +542,7 @@ namespace Compiler
|
|||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerFunction("getdistance",'f',"c",opcodeGetDistance,opcodeGetDistanceExplicit);
|
||||
extensions.registerInstruction("setscale","f",opcodeSetScale,opcodeSetScaleExplicit);
|
||||
extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit);
|
||||
extensions.registerInstruction("setangle","cf",opcodeSetAngle,opcodeSetAngleExplicit);
|
||||
|
|
|
@ -222,11 +222,6 @@ namespace
|
|||
code.push_back (Compiler::Generator::segment5 (37));
|
||||
}
|
||||
|
||||
void opMenuMode (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (38));
|
||||
}
|
||||
|
||||
void opStoreGlobalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (39));
|
||||
|
@ -286,71 +281,6 @@ namespace
|
|||
{
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 70 : 64));
|
||||
}
|
||||
|
||||
void opRandom (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (45));
|
||||
}
|
||||
|
||||
void opScriptRunning (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (46));
|
||||
}
|
||||
|
||||
void opStartScript (Compiler::Generator::CodeContainer& code, bool targeted)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (targeted ? 71 : 47));
|
||||
}
|
||||
|
||||
void opStopScript (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (48));
|
||||
}
|
||||
|
||||
void opGetDistance (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (49));
|
||||
}
|
||||
|
||||
void opGetSecondsPassed (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (50));
|
||||
}
|
||||
|
||||
void opEnable (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (51));
|
||||
}
|
||||
|
||||
void opDisable (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (52));
|
||||
}
|
||||
|
||||
void opGetDisabled (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (53));
|
||||
}
|
||||
|
||||
void opEnableExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (54));
|
||||
}
|
||||
|
||||
void opDisableExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (55));
|
||||
}
|
||||
|
||||
void opGetDisabledExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (56));
|
||||
}
|
||||
|
||||
void opGetDistanceExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (57));
|
||||
}
|
||||
}
|
||||
|
||||
namespace Compiler
|
||||
|
@ -645,11 +575,6 @@ namespace Compiler
|
|||
}
|
||||
}
|
||||
|
||||
void menuMode (CodeContainer& code)
|
||||
{
|
||||
opMenuMode (code);
|
||||
}
|
||||
|
||||
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const CodeContainer& value, char valueType)
|
||||
{
|
||||
|
@ -806,93 +731,5 @@ namespace Compiler
|
|||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void random (CodeContainer& code)
|
||||
{
|
||||
opRandom (code);
|
||||
}
|
||||
|
||||
void scriptRunning (CodeContainer& code)
|
||||
{
|
||||
opScriptRunning (code);
|
||||
}
|
||||
|
||||
void startScript (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
opStartScript (code, false);
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opStartScript (code, true);
|
||||
}
|
||||
}
|
||||
|
||||
void stopScript (CodeContainer& code)
|
||||
{
|
||||
opStopScript (code);
|
||||
}
|
||||
|
||||
void getDistance (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opGetDistance (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opGetDistanceExplicit (code);
|
||||
}
|
||||
}
|
||||
|
||||
void getSecondsPassed (CodeContainer& code)
|
||||
{
|
||||
opGetSecondsPassed (code);
|
||||
}
|
||||
|
||||
void getDisabled (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opGetDisabled (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opGetDisabledExplicit (code);
|
||||
}
|
||||
}
|
||||
|
||||
void enable (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opEnable (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opEnableExplicit (code);
|
||||
}
|
||||
}
|
||||
|
||||
void disable (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opDisable (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opDisableExplicit (code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,8 +91,6 @@ namespace Compiler
|
|||
|
||||
void compare (CodeContainer& code, char op, char valueType1, char valueType2);
|
||||
|
||||
void menuMode (CodeContainer& code);
|
||||
|
||||
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const CodeContainer& value, char valueType);
|
||||
|
||||
|
@ -106,24 +104,6 @@ namespace Compiler
|
|||
void fetchMember (CodeContainer& code, Literals& literals, char memberType,
|
||||
const std::string& name, const std::string& id, bool global);
|
||||
///< \param global Member of a global script instead of a script of a reference.
|
||||
|
||||
void random (CodeContainer& code);
|
||||
|
||||
void scriptRunning (CodeContainer& code);
|
||||
|
||||
void startScript (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void stopScript (CodeContainer& code);
|
||||
|
||||
void getDistance (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void getSecondsPassed (CodeContainer& code);
|
||||
|
||||
void getDisabled (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void enable (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void disable (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -247,35 +247,6 @@ namespace Compiler
|
|||
|
||||
if (mState==BeginState || mState==ExplicitState)
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case Scanner::K_enable:
|
||||
|
||||
Generator::enable (mCode, mLiterals, mExplicit);
|
||||
mState = PotentialEndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_disable:
|
||||
|
||||
Generator::disable (mCode, mLiterals, mExplicit);
|
||||
mState = PotentialEndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_startscript:
|
||||
|
||||
mExprParser.parseArguments ("c", scanner, mCode);
|
||||
Generator::startScript (mCode, mLiterals, mExplicit);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_stopscript:
|
||||
|
||||
mExprParser.parseArguments ("c", scanner, mCode);
|
||||
Generator::stopScript (mCode);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for custom extensions
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
|
@ -323,21 +294,6 @@ namespace Compiler
|
|||
}
|
||||
}
|
||||
|
||||
if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance)
|
||||
{
|
||||
if (mAllowExpression)
|
||||
{
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
parseExpression (scanner, loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
getErrorHandler().warning ("Unexpected naked expression", loc);
|
||||
}
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
char returnType;
|
||||
|
@ -416,13 +372,6 @@ namespace Compiler
|
|||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_stopscript:
|
||||
|
||||
mExprParser.parseArguments ("c", scanner, mCode);
|
||||
Generator::stopScript (mCode);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_else:
|
||||
|
||||
getErrorHandler().warning ("Stray else", loc);
|
||||
|
@ -484,19 +433,6 @@ namespace Compiler
|
|||
return true;
|
||||
}
|
||||
|
||||
if (mAllowExpression)
|
||||
{
|
||||
if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode ||
|
||||
keyword==Scanner::K_random || keyword==Scanner::K_scriptrunning ||
|
||||
keyword==Scanner::K_getsecondspassed)
|
||||
{
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
parseExpression (scanner, loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
|
|
|
@ -305,6 +305,19 @@ namespace Compiler
|
|||
const int opcodeRepairedOnMe = 0x200030c;
|
||||
const int opcodeRepairedOnMeExplicit = 0x200030d;
|
||||
const int opcodeToggleRecastMesh = 0x2000310;
|
||||
const int opcodeMenuMode = 0x2000311;
|
||||
const int opcodeRandom = 0x2000312;
|
||||
const int opcodeScriptRunning = 0x2000313;
|
||||
const int opcodeStartScript = 0x2000314;
|
||||
const int opcodeStopScript = 0x2000315;
|
||||
const int opcodeGetSecondsPassed = 0x2000316;
|
||||
const int opcodeEnable = 0x2000317;
|
||||
const int opcodeDisable = 0x2000318;
|
||||
const int opcodeGetDisabled = 0x2000319;
|
||||
const int opcodeEnableExplicit = 0x200031a;
|
||||
const int opcodeDisableExplicit = 0x200031b;
|
||||
const int opcodeGetDisabledExplicit = 0x200031c;
|
||||
const int opcodeStartScriptExplicit = 0x200031d;
|
||||
}
|
||||
|
||||
namespace Sky
|
||||
|
@ -513,6 +526,8 @@ namespace Compiler
|
|||
const int opcodeMoveWorldExplicit = 0x2000209;
|
||||
const int opcodeResetActors = 0x20002f4;
|
||||
const int opcodeFixme = 0x2000302;
|
||||
const int opcodeGetDistance = 0x200031e;
|
||||
const int opcodeGetDistanceExplicit = 0x200031f;
|
||||
}
|
||||
|
||||
namespace User
|
||||
|
|
|
@ -266,12 +266,6 @@ namespace Compiler
|
|||
"messagebox",
|
||||
"set", "to",
|
||||
"getsquareroot",
|
||||
"menumode",
|
||||
"random",
|
||||
"startscript", "stopscript", "scriptrunning",
|
||||
"getdistance",
|
||||
"getsecondspassed",
|
||||
"enable", "disable", "getdisabled",
|
||||
0
|
||||
};
|
||||
|
||||
|
|
|
@ -208,13 +208,7 @@ namespace Compiler
|
|||
K_return,
|
||||
K_messagebox,
|
||||
K_set, K_to,
|
||||
K_getsquareroot,
|
||||
K_menumode,
|
||||
K_random,
|
||||
K_startscript, K_stopscript, K_scriptrunning,
|
||||
K_getdistance,
|
||||
K_getsecondspassed,
|
||||
K_enable, K_disable, K_getdisabled
|
||||
K_getsquareroot
|
||||
};
|
||||
|
||||
enum special
|
||||
|
|
|
@ -63,12 +63,7 @@ namespace Compiler
|
|||
keyword==Scanner::K_elseif || keyword==Scanner::K_while ||
|
||||
keyword==Scanner::K_endwhile || keyword==Scanner::K_return ||
|
||||
keyword==Scanner::K_messagebox || keyword==Scanner::K_set ||
|
||||
keyword==Scanner::K_to || keyword==Scanner::K_startscript ||
|
||||
keyword==Scanner::K_stopscript || keyword==Scanner::K_enable ||
|
||||
keyword==Scanner::K_disable || keyword==Scanner::K_getdisabled ||
|
||||
keyword==Scanner::K_getdistance || keyword==Scanner::K_scriptrunning ||
|
||||
keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode ||
|
||||
keyword==Scanner::K_random || keyword==Scanner::K_getsecondspassed)
|
||||
keyword==Scanner::K_to || keyword==Scanner::K_getsquareroot)
|
||||
{
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace ESM
|
|||
|
||||
esm.writeHNT ("CAST", params.mCasterActorId);
|
||||
esm.writeHNString ("DISP", params.mDisplayName);
|
||||
esm.writeHNT ("TIME", params.mTimeStamp);
|
||||
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt)
|
||||
{
|
||||
|
@ -25,12 +24,15 @@ namespace ESM
|
|||
esm.writeHNT ("ARG_", effectIt->mArg);
|
||||
esm.writeHNT ("MAGN", effectIt->mMagnitude);
|
||||
esm.writeHNT ("DURA", effectIt->mDuration);
|
||||
esm.writeHNT ("LEFT", effectIt->mTimeLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveSpells::load(ESMReader &esm)
|
||||
{
|
||||
int format = esm.getFormat();
|
||||
|
||||
while (esm.isNextSub("ID__"))
|
||||
{
|
||||
std::string spellId = esm.getHString();
|
||||
|
@ -38,7 +40,10 @@ namespace ESM
|
|||
ActiveSpellParams params;
|
||||
esm.getHNT (params.mCasterActorId, "CAST");
|
||||
params.mDisplayName = esm.getHNString ("DISP");
|
||||
esm.getHNT (params.mTimeStamp, "TIME");
|
||||
|
||||
// spell casting timestamp, no longer used
|
||||
if (esm.isNextSub("TIME"))
|
||||
esm.skipHSub();
|
||||
|
||||
while (esm.isNextSub("MGEF"))
|
||||
{
|
||||
|
@ -48,6 +53,11 @@ namespace ESM
|
|||
esm.getHNOT(effect.mArg, "ARG_");
|
||||
esm.getHNT (effect.mMagnitude, "MAGN");
|
||||
esm.getHNT (effect.mDuration, "DURA");
|
||||
if (format < 9)
|
||||
effect.mTimeLeft = effect.mDuration;
|
||||
else
|
||||
esm.getHNT (effect.mTimeLeft, "LEFT");
|
||||
|
||||
params.mEffects.push_back(effect);
|
||||
}
|
||||
mSpells.insert(std::make_pair(spellId, params));
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace ESM
|
|||
float mMagnitude;
|
||||
int mArg; // skill or attribute
|
||||
float mDuration;
|
||||
float mTimeLeft;
|
||||
};
|
||||
|
||||
// format 0, saved games only
|
||||
|
@ -29,7 +30,6 @@ namespace ESM
|
|||
struct ActiveSpellParams
|
||||
{
|
||||
std::vector<ActiveEffect> mEffects;
|
||||
ESM::TimeStamp mTimeStamp;
|
||||
std::string mDisplayName;
|
||||
int mCasterActorId;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "defs.hpp"
|
||||
|
||||
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
||||
int ESM::SavedGame::sCurrentFormat = 8;
|
||||
int ESM::SavedGame::sCurrentFormat = 9;
|
||||
|
||||
void ESM::SavedGame::load (ESMReader &esm)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <WinReg.h>
|
||||
#include <winreg.h>
|
||||
|
||||
#include <boost/locale.hpp>
|
||||
namespace bconv = boost::locale::conv;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include <components/myguiplatform/myguitexture.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
unsigned long utf8ToUnicode(const std::string& utf8)
|
||||
|
@ -147,15 +149,24 @@ namespace Gui
|
|||
FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, const std::string& userDataPath)
|
||||
: mVFS(vfs)
|
||||
, mUserDataPath(userDataPath)
|
||||
, mFontHeight(16)
|
||||
{
|
||||
if (encoding == ToUTF8::WINDOWS_1252)
|
||||
mEncoding = ToUTF8::CP437;
|
||||
else
|
||||
mEncoding = encoding;
|
||||
|
||||
int fontSize = Settings::Manager::getInt("font size", "GUI");
|
||||
mFontHeight = std::min(std::max(12, fontSize), 20);
|
||||
|
||||
MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource");
|
||||
MyGUI::ResourceManager::getInstance().registerLoadXmlDelegate("Resource") = MyGUI::newDelegate(this, &FontLoader::loadFontFromXml);
|
||||
}
|
||||
|
||||
FontLoader::~FontLoader()
|
||||
{
|
||||
MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource");
|
||||
|
||||
for (std::vector<MyGUI::ITexture*>::iterator it = mTextures.begin(); it != mTextures.end(); ++it)
|
||||
delete *it;
|
||||
mTextures.clear();
|
||||
|
@ -190,7 +201,7 @@ namespace Gui
|
|||
{
|
||||
size_t pos = name.find_last_of('.');
|
||||
if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".fnt") == 0)
|
||||
loadFont(name, exportToFile);
|
||||
loadBitmapFont(name, exportToFile);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -238,7 +249,7 @@ namespace Gui
|
|||
float ascent;
|
||||
} GlyphInfo;
|
||||
|
||||
void FontLoader::loadFont(const std::string &fileName, bool exportToFile)
|
||||
void FontLoader::loadBitmapFont(const std::string &fileName, bool exportToFile)
|
||||
{
|
||||
Files::IStreamPtr file = mVFS->get(fileName);
|
||||
|
||||
|
@ -527,4 +538,96 @@ namespace Gui
|
|||
MyGUI::ResourceManager::getInstance().addResource(bookFont);
|
||||
}
|
||||
|
||||
void FontLoader::loadFontFromXml(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version)
|
||||
{
|
||||
MyGUI::xml::ElementEnumerator resourceNode = _node->getElementEnumerator();
|
||||
bool createCopy = false;
|
||||
while (resourceNode.next("Resource"))
|
||||
{
|
||||
std::string type, name;
|
||||
resourceNode->findAttribute("type", type);
|
||||
resourceNode->findAttribute("name", name);
|
||||
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont"))
|
||||
{
|
||||
createCopy = true;
|
||||
|
||||
// For TrueType fonts we should override Size and Resolution properties
|
||||
// to allow to configure font size via config file, without need to edit XML files.
|
||||
// Also we should take UI scaling factor in account.
|
||||
int resolution = Settings::Manager::getInt("ttf resolution", "GUI");
|
||||
resolution = std::min(960, std::max(48, resolution));
|
||||
|
||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||
resolution *= uiScale;
|
||||
|
||||
MyGUI::xml::ElementPtr resolutionNode = resourceNode->createChild("Property");
|
||||
resolutionNode->addAttribute("key", "Resolution");
|
||||
resolutionNode->addAttribute("value", std::to_string(resolution));
|
||||
|
||||
MyGUI::xml::ElementPtr sizeNode = resourceNode->createChild("Property");
|
||||
sizeNode->addAttribute("key", "Size");
|
||||
sizeNode->addAttribute("value", std::to_string(mFontHeight));
|
||||
}
|
||||
else if (Misc::StringUtils::ciEqual(type, "ResourceSkin") ||
|
||||
Misc::StringUtils::ciEqual(type, "AutoSizedResourceSkin"))
|
||||
{
|
||||
// We should adjust line height for MyGUI widgets depending on font size
|
||||
MyGUI::xml::ElementPtr heightNode = resourceNode->createChild("Property");
|
||||
heightNode->addAttribute("key", "HeightLine");
|
||||
heightNode->addAttribute("value", std::to_string(mFontHeight+2));
|
||||
}
|
||||
}
|
||||
|
||||
MyGUI::ResourceManager::getInstance().loadFromXmlNode(_node, _file, _version);
|
||||
|
||||
if (createCopy)
|
||||
{
|
||||
MyGUI::xml::ElementPtr copy = _node->createCopy();
|
||||
|
||||
MyGUI::xml::ElementEnumerator copyFont = copy->getElementEnumerator();
|
||||
while (copyFont.next("Resource"))
|
||||
{
|
||||
std::string type, name;
|
||||
copyFont->findAttribute("type", type);
|
||||
copyFont->findAttribute("name", name);
|
||||
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont"))
|
||||
{
|
||||
// Since the journal and books use the custom scaling factor depending on resolution,
|
||||
// setup separate fonts with different Resolution to fit these windows.
|
||||
// These fonts have an internal prefix.
|
||||
int resolution = Settings::Manager::getInt("ttf resolution", "GUI");
|
||||
resolution = std::min(960, std::max(48, resolution));
|
||||
|
||||
float currentX = Settings::Manager::getInt("resolution x", "Video");
|
||||
float currentY = Settings::Manager::getInt("resolution y", "Video");
|
||||
// TODO: read size from openmw_layout.xml somehow
|
||||
float heightScale = (currentY / 520);
|
||||
float widthScale = (currentX / 600);
|
||||
float uiScale = std::min(widthScale, heightScale);
|
||||
resolution *= uiScale;
|
||||
|
||||
MyGUI::xml::ElementPtr resolutionNode = copyFont->createChild("Property");
|
||||
resolutionNode->addAttribute("key", "Resolution");
|
||||
resolutionNode->addAttribute("value", std::to_string(resolution));
|
||||
|
||||
copyFont->setAttribute("name", "Journalbook " + name);
|
||||
}
|
||||
}
|
||||
|
||||
MyGUI::ResourceManager::getInstance().loadFromXmlNode(copy, _file, _version);
|
||||
}
|
||||
}
|
||||
|
||||
int FontLoader::getFontHeight()
|
||||
{
|
||||
return mFontHeight;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include "boost/filesystem/operations.hpp"
|
||||
|
||||
#include <MyGUI_XmlDocument.h>
|
||||
#include <MyGUI_Version.h>
|
||||
|
||||
#include <components/myguiplatform/myguidatamanager.hpp>
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
|
@ -19,8 +22,6 @@ namespace MyGUI
|
|||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
|
||||
/// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and OSG
|
||||
/// @note The FontLoader needs to remain in scope as long as you want to use the loaded fonts.
|
||||
class FontLoader
|
||||
|
@ -33,16 +34,21 @@ namespace Gui
|
|||
void loadBitmapFonts (bool exportToFile);
|
||||
void loadTrueTypeFonts ();
|
||||
|
||||
void loadFontFromXml(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version);
|
||||
|
||||
int getFontHeight();
|
||||
|
||||
private:
|
||||
ToUTF8::FromType mEncoding;
|
||||
const VFS::Manager* mVFS;
|
||||
std::string mUserDataPath;
|
||||
int mFontHeight;
|
||||
|
||||
std::vector<MyGUI::ITexture*> mTextures;
|
||||
std::vector<MyGUI::ResourceManualFont*> mFonts;
|
||||
|
||||
/// @param exportToFile export the converted font (Image and XML with glyph metrics) to files?
|
||||
void loadFont (const std::string& fileName, bool exportToFile);
|
||||
void loadBitmapFont (const std::string& fileName, bool exportToFile);
|
||||
|
||||
FontLoader(const FontLoader&);
|
||||
void operator=(const FontLoader&);
|
||||
|
|
|
@ -51,8 +51,6 @@ namespace Interpreter
|
|||
|
||||
virtual void report (const std::string& message) = 0;
|
||||
|
||||
virtual bool menuMode() = 0;
|
||||
|
||||
virtual int getGlobalShort (const std::string& name) const = 0;
|
||||
|
||||
virtual int getGlobalLong (const std::string& name) const = 0;
|
||||
|
@ -95,23 +93,6 @@ namespace Interpreter
|
|||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
|
||||
virtual bool isScriptRunning (const std::string& name) const = 0;
|
||||
|
||||
virtual void startScript (const std::string& name, const std::string& targetId = "") = 0;
|
||||
|
||||
virtual void stopScript (const std::string& name) = 0;
|
||||
|
||||
virtual float getDistance (const std::string& name, const std::string& id = "") const
|
||||
= 0;
|
||||
|
||||
virtual float getSecondsPassed() const = 0;
|
||||
|
||||
virtual bool isDisabled (const std::string& id = "") const = 0;
|
||||
|
||||
virtual void enable (const std::string& id = "") = 0;
|
||||
|
||||
virtual void disable (const std::string& id = "") = 0;
|
||||
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0;
|
||||
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0;
|
||||
|
|
|
@ -96,27 +96,14 @@ op 34: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser than
|
|||
op 35: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser or equal, 0 else
|
||||
op 36: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater than, 0 else
|
||||
op 37: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater or equal, 0 else
|
||||
op 38: push 1 if game is in menu mode, 0 else
|
||||
opcode 38 unused
|
||||
op 39: store stack[0] in global short stack[1] and pop twice
|
||||
op 40: store stack[0] in global long stack[1] and pop twice
|
||||
op 41: store stack[0] in global float stack[1] and pop twice
|
||||
op 42: replace stack[0] with global short stack[0]
|
||||
op 43: replace stack[0] with global long stack[0]
|
||||
op 44: replace stack[0] with global float stack[0]
|
||||
op 45: replace stack[0] with a random integer value in the range [0, stack[0]-1]
|
||||
op 46: replace stack[0] with 1, if global script stack[0] is running, 0 else
|
||||
op 47: start script stack[0] and pop
|
||||
op 48: stop script stack[0] and pop
|
||||
op 49: replace stack[0] with distance between implicit reference and a reference of ID stack[0]
|
||||
op 50: push frame duration (float)
|
||||
op 51: enable implicit reference
|
||||
op 52: disable implicit reference
|
||||
op 53: push 1, if implicit reference is disabled, 0 else
|
||||
op 54: explicit reference = stack[0]; pop; enable explicit reference
|
||||
op 55: explicit reference = stack[0]; pop; disable explicit reference
|
||||
op 56: explicit reference = stack[0]; pop; push 1, if explicit reference is disabled, 0 else
|
||||
op 57: explicit reference = stack[0]; pop;
|
||||
replace stack[0] with distance between explicit reference and a reference of ID stack[0]
|
||||
opcodes 45-57 unused
|
||||
op 58: report string literal index in stack[0];
|
||||
additional arguments (if any) in stack[n]..stack[1];
|
||||
n is determined according to the message string
|
||||
|
@ -133,6 +120,5 @@ op 67: store stack[0] in member float stack[2] of global script with ID stack[1]
|
|||
op 68: replace stack[0] with member short stack[1] of global script with ID stack[0]
|
||||
op 69: replace stack[0] with member short stack[1] of global script with ID stack[0]
|
||||
op 70: replace stack[0] with member short stack[1] of global script with ID stack[0]
|
||||
op 71: explicit reference (target) = stack[0]; pop; start script stack[0] and pop
|
||||
opcodes 72-33554431 unused
|
||||
opcodes 71-33554431 unused
|
||||
opcodes 33554432-67108863 reserved for extensions
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "mathopcodes.hpp"
|
||||
#include "controlopcodes.hpp"
|
||||
#include "miscopcodes.hpp"
|
||||
#include "scriptopcodes.hpp"
|
||||
#include "spatialopcodes.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
|
@ -97,25 +95,6 @@ namespace Interpreter
|
|||
|
||||
// misc
|
||||
interpreter.installSegment3 (0, new OpMessageBox);
|
||||
interpreter.installSegment5 (38, new OpMenuMode);
|
||||
interpreter.installSegment5 (45, new OpRandom);
|
||||
interpreter.installSegment5 (50, new OpGetSecondsPassed);
|
||||
interpreter.installSegment5 (51, new OpEnable);
|
||||
interpreter.installSegment5 (52, new OpDisable);
|
||||
interpreter.installSegment5 (53, new OpGetDisabled);
|
||||
interpreter.installSegment5 (54, new OpEnableExplicit);
|
||||
interpreter.installSegment5 (55, new OpDisableExplicit);
|
||||
interpreter.installSegment5 (56, new OpGetDisabledExplicit);
|
||||
interpreter.installSegment5 (58, new OpReport);
|
||||
|
||||
// script control
|
||||
interpreter.installSegment5 (46, new OpScriptRunning);
|
||||
interpreter.installSegment5 (47, new OpStartScript);
|
||||
interpreter.installSegment5 (48, new OpStopScript);
|
||||
interpreter.installSegment5 (71, new OpStartScriptExplicit);
|
||||
|
||||
// spacial
|
||||
interpreter.installSegment5 (49, new OpGetDistance);
|
||||
interpreter.installSegment5 (57, new OpGetDistanceExplicit);
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue