mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 23:23:52 +00:00
Merge remote-tracking branch 'remotes/upstream/master' into NonTableFields
Conflicts: apps/opencs/CMakeLists.txt apps/opencs/model/doc/document.cpp apps/opencs/model/world/columnbase.hpp apps/opencs/model/world/columns.cpp apps/opencs/model/world/columns.hpp apps/opencs/model/world/commands.cpp apps/opencs/model/world/idtable.cpp apps/opencs/view/world/dialoguesubview.cpp apps/opencs/view/world/dialoguesubview.hpp apps/opencs/view/world/util.cpp
This commit is contained in:
commit
fb2ba7610c
1286 changed files with 57182 additions and 32339 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -37,6 +37,7 @@ resources
|
||||||
/omwlauncher
|
/omwlauncher
|
||||||
/openmw
|
/openmw
|
||||||
/opencs
|
/opencs
|
||||||
|
/niftest
|
||||||
|
|
||||||
## generated objects
|
## generated objects
|
||||||
apps/openmw/config.hpp
|
apps/openmw/config.hpp
|
||||||
|
|
52
.travis.yml
52
.travis.yml
|
@ -1,38 +1,42 @@
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler:
|
|
||||||
- gcc
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
- coverity_scan
|
||||||
- /openmw-.*$/
|
- /openmw-.*$/
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
|
# via the "travis encrypt" command using the project repo's public key
|
||||||
|
- secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE="
|
||||||
|
addons:
|
||||||
|
coverity_scan:
|
||||||
|
project:
|
||||||
|
name: "OpenMW/openmw"
|
||||||
|
description: "<Your project description here>"
|
||||||
|
notification_email: scrawl@baseoftrash.de
|
||||||
|
build_command_prepend: "cmake ."
|
||||||
|
build_command: "make -j3"
|
||||||
|
branch_pattern: coverity_scan
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- pwd
|
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
|
||||||
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
|
||||||
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
|
||||||
- sudo apt-get update -qq
|
|
||||||
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock
|
|
||||||
- sudo apt-get install -qq libqt4-dev
|
|
||||||
- sudo apt-get install -qq libopenal-dev
|
|
||||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
|
|
||||||
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
|
|
||||||
- sudo mkdir /usr/src/gtest/build
|
|
||||||
- cd /usr/src/gtest/build
|
|
||||||
- sudo cmake .. -DBUILD_SHARED_LIBS=1
|
|
||||||
- sudo make -j4
|
|
||||||
- sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
|
|
||||||
- sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
|
||||||
before_script:
|
before_script:
|
||||||
- cd -
|
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_script.linux.sh; fi
|
||||||
- mkdir build
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
|
||||||
- cd build
|
|
||||||
- cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DBUILD_WITH_DPKG=1
|
|
||||||
script:
|
script:
|
||||||
- make -j4
|
- cd ./build
|
||||||
|
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi
|
||||||
|
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
|
||||||
after_script:
|
after_script:
|
||||||
- ./openmw_test_suite
|
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||||
notifications:
|
notifications:
|
||||||
recipients:
|
recipients:
|
||||||
- lgromanowski+travis.ci@gmail.com
|
- corrmage+travis-ci@gmail.com
|
||||||
email:
|
email:
|
||||||
on_success: change
|
on_success: change
|
||||||
on_failure: always
|
on_failure: always
|
||||||
|
|
207
AUTHORS.md
Normal file
207
AUTHORS.md
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
Contributors
|
||||||
|
============
|
||||||
|
|
||||||
|
The OpenMW project was started in 2008 by Nicolay Korslund.
|
||||||
|
In the course of years many people have contributed to the project.
|
||||||
|
|
||||||
|
If you feel your name is missing from this list, please notify a developer.
|
||||||
|
|
||||||
|
|
||||||
|
Programmers
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Marc Zinnschlag (Zini) - Lead Programmer/Project Manager
|
||||||
|
|
||||||
|
Adam Hogan (aurix)
|
||||||
|
Aleksandar Jovanov
|
||||||
|
Alex Haddad (rainChu)
|
||||||
|
Alex McKibben (WeirdSexy)
|
||||||
|
Alexander Nadeau (wareya)
|
||||||
|
Alexander Olofsson (Ace)
|
||||||
|
Artem Kotsynyak (greye)
|
||||||
|
Arthur Moore (EmperorArthur)
|
||||||
|
athile
|
||||||
|
Bret Curtis (psi29a)
|
||||||
|
Britt Mathis (galdor557)
|
||||||
|
cc9cii
|
||||||
|
Chris Boyce (slothlife)
|
||||||
|
Chris Robinson (KittyCat)
|
||||||
|
Cory F. Cohen (cfcohen)
|
||||||
|
Cris Mihalache (Mirceam)
|
||||||
|
darkf
|
||||||
|
Dmitry Shkurskiy (endorph)
|
||||||
|
Douglas Diniz (Dgdiniz)
|
||||||
|
Douglas Mencken (dougmencken)
|
||||||
|
dreamer-dead
|
||||||
|
David Teviotdale (dteviot)
|
||||||
|
Edmondo Tommasina (edmondo)
|
||||||
|
Eduard Cot (trombonecot)
|
||||||
|
Eli2
|
||||||
|
Emanuel Guével (potatoesmaster)
|
||||||
|
eroen
|
||||||
|
Evgeniy Mineev (sandstranger)
|
||||||
|
Fil Krynicki (filkry)
|
||||||
|
Gašper Sedej
|
||||||
|
gugus/gus
|
||||||
|
Hallfaer Tuilinn
|
||||||
|
Internecine
|
||||||
|
Jacob Essex (Yacoby)
|
||||||
|
Jannik Heller (scrawl)
|
||||||
|
Jason Hooks (jhooks)
|
||||||
|
jeaye
|
||||||
|
Jeffrey Haines (Jyby)
|
||||||
|
Jengerer
|
||||||
|
Joel Graff (graffy)
|
||||||
|
John Blomberg (fstp)
|
||||||
|
Jordan Ayers
|
||||||
|
Jordan Milne
|
||||||
|
Julien Voisin (jvoisin/ap0)
|
||||||
|
Karl-Felix Glatzer (k1ll)
|
||||||
|
Kevin Poitra (PuppyKevin)
|
||||||
|
Lars Söderberg (Lazaroth)
|
||||||
|
lazydev
|
||||||
|
Leon Saunders (emoose)
|
||||||
|
Lukasz Gromanowski (lgro)
|
||||||
|
Manuel Edelmann (vorenon)
|
||||||
|
Marc Bouvier (CramitDeFrog)
|
||||||
|
Marcin Hulist (Gohan)
|
||||||
|
Mark Siewert (mark76)
|
||||||
|
Marco Melletti (mellotanica)
|
||||||
|
Marco Schulze
|
||||||
|
Mateusz Kołaczek (PL_kolek)
|
||||||
|
megaton
|
||||||
|
Michael Hogan (Xethik)
|
||||||
|
Michael Mc Donnell
|
||||||
|
Michael Papageorgiou (werdanith)
|
||||||
|
Michał Bień (Glorf)
|
||||||
|
Miroslav Puda (pakanek)
|
||||||
|
MiroslavR
|
||||||
|
naclander
|
||||||
|
Narmo
|
||||||
|
Nathan Jeffords (blunted2night)
|
||||||
|
NeveHanter
|
||||||
|
Nikolay Kasyanov (corristo)
|
||||||
|
nobrakal
|
||||||
|
Nolan Poe (nopoe)
|
||||||
|
Paul McElroy (Greendogo)
|
||||||
|
Pieter van der Kloet (pvdk)
|
||||||
|
Radu-Marius Popovici (rpopovici)
|
||||||
|
rdimesio
|
||||||
|
riothamus
|
||||||
|
Robert MacGregor (Ragora)
|
||||||
|
Rohit Nirmal
|
||||||
|
Roman Melnik (Kromgart)
|
||||||
|
Roman Proskuryakov (humbug)
|
||||||
|
Sandy Carter (bwrsandman)
|
||||||
|
Scott Howard
|
||||||
|
Sebastian Wick (swick)
|
||||||
|
Sergey Shambir
|
||||||
|
sir_herrbatka
|
||||||
|
Stefan Galowicz (bogglez)
|
||||||
|
Stanislav Bobrov (Jiub)
|
||||||
|
Sylvain Thesnieres (Garvek)
|
||||||
|
terrorfisch
|
||||||
|
Thomas Luppi (Digmaster)
|
||||||
|
Tom Mason (wheybags)
|
||||||
|
Torben Leif Carrington (TorbenC)
|
||||||
|
viadanna
|
||||||
|
Vincent Heuken
|
||||||
|
vocollapse
|
||||||
|
|
||||||
|
Packagers
|
||||||
|
---------
|
||||||
|
|
||||||
|
Alexander Olofsson (Ace) - Windows
|
||||||
|
Bret Curtis (psi29a) - Ubuntu Linux
|
||||||
|
Edmondo Tommasina (edmondo) - Gentoo Linux
|
||||||
|
Julian Ospald (hasufell) - Gentoo Linux
|
||||||
|
Karl-Felix Glatzer (k1ll) - Linux Binaries
|
||||||
|
Kenny Armstrong (artorius) - Fedora Linux
|
||||||
|
Nikolay Kasyanov (corristo) - Mac OS X
|
||||||
|
Sandy Carter (bwrsandman) - Arch Linux
|
||||||
|
|
||||||
|
Public Relations and Translations
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Alex McKibben (WeirdSexy) - Podcaster
|
||||||
|
Artem Kotsynyak (greye) - Russian News Writer
|
||||||
|
Jim Clauwaert (Zedd) - Public Outreach
|
||||||
|
Julien Voisin (jvoisin/ap0) - French News Writer
|
||||||
|
Tom Koenderink (Okulo) - English News Writer
|
||||||
|
Lukasz Gromanowski (lgro) - English News Writer
|
||||||
|
Mickey Lyle (raevol) - Release Manager
|
||||||
|
Pithorn - Chinese News Writer
|
||||||
|
sir_herrbatka - Polish News Writer
|
||||||
|
Dawid Lakomy (Vedyimyn) - Polish News Writer
|
||||||
|
|
||||||
|
Website
|
||||||
|
-------
|
||||||
|
|
||||||
|
Lukasz Gromanowski (Lgro) - Website Administrator
|
||||||
|
Ryan Sardonic (Wry) - Wiki Editor
|
||||||
|
sir_herrbatka - Forum Administrator
|
||||||
|
|
||||||
|
Formula Research
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Hrnchamd
|
||||||
|
Epsilon
|
||||||
|
fragonard
|
||||||
|
Greendogo
|
||||||
|
HiPhish
|
||||||
|
modred11
|
||||||
|
Myckel
|
||||||
|
natirips
|
||||||
|
Sadler
|
||||||
|
|
||||||
|
Artwork
|
||||||
|
-------
|
||||||
|
|
||||||
|
Necrod - OpenMW Logo
|
||||||
|
Mickey Lyle (raevol) - Wordpress Theme
|
||||||
|
Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons
|
||||||
|
|
||||||
|
Inactive Contributors
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Ardekantur
|
||||||
|
Armin Preiml
|
||||||
|
Berulacks
|
||||||
|
Carl Maxwell
|
||||||
|
Diggory Hardy
|
||||||
|
Dmitry Marakasov (AMDmi3)
|
||||||
|
ElderTroll
|
||||||
|
guidoj
|
||||||
|
Jan-Peter Nilsson (peppe)
|
||||||
|
Jan Borsodi
|
||||||
|
Josua Grawitter
|
||||||
|
juanmnzsk8
|
||||||
|
Kingpix
|
||||||
|
Lordrea
|
||||||
|
Michal Sciubidlo
|
||||||
|
Nicolay Korslund
|
||||||
|
Nekochan
|
||||||
|
pchan3
|
||||||
|
penguinroad
|
||||||
|
psi29a
|
||||||
|
sergoz
|
||||||
|
spyboot
|
||||||
|
Star-Demon
|
||||||
|
Thoronador
|
||||||
|
Yuri Krupenin
|
||||||
|
|
||||||
|
Additional Credits
|
||||||
|
------------------
|
||||||
|
In this section we would like to thank people not part of OpenMW for their work.
|
||||||
|
|
||||||
|
Thanks to Maxim Nikolaev,
|
||||||
|
for allowing us to use his excellent Morrowind fan-art on our website and in other places.
|
||||||
|
|
||||||
|
Thanks to DokterDume,
|
||||||
|
for kindly providing us with the Moon and Star logo, used as the application icon and project logo.
|
||||||
|
|
||||||
|
Thanks to Kevin Ryan,
|
||||||
|
for creating the icon used for the Data Files tab of the OpenMW Launcher.
|
||||||
|
|
||||||
|
Thanks to DejaVu team,
|
||||||
|
for their DejaVuLGCSansMono fontface, see DejaVu Font License.txt for their license terms.
|
1622
CHANGELOG.md
Normal file
1622
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load diff
18
CI/before_install.linux.sh
Executable file
18
CI/before_install.linux.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export CXX=g++
|
||||||
|
export CC=gcc
|
||||||
|
|
||||||
|
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||||
|
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -qq libgtest-dev google-mock
|
||||||
|
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
|
||||||
|
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
|
||||||
|
sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
||||||
|
sudo mkdir /usr/src/gtest/build
|
||||||
|
cd /usr/src/gtest/build
|
||||||
|
sudo cmake .. -DBUILD_SHARED_LIBS=1
|
||||||
|
sudo make -j4
|
||||||
|
sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
|
||||||
|
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
9
CI/before_install.osx.sh
Executable file
9
CI/before_install.osx.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export CXX=clang++
|
||||||
|
export CC=clang
|
||||||
|
|
||||||
|
brew tap openmw/openmw
|
||||||
|
brew update
|
||||||
|
brew unlink boost
|
||||||
|
brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg openmw/openmw/qt unshield
|
5
CI/before_script.linux.sh
Executable file
5
CI/before_script.linux.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE
|
5
CI/before_script.osx.sh
Executable file
5
CI/before_script.osx.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_FRAMEWORK_PATH="/usr/local/lib/macosx/Release" -DCMAKE_EXE_LINKER_FLAGS="-F/usr/local/lib/macosx/Release" -DCMAKE_CXX_FLAGS="-stdlib=libstdc++" -DCMAKE_BUILD_TYPE=Debug -DBUILD_MYGUI_PLUGIN=OFF -G"Unix Makefiles" ..
|
368
CMakeLists.txt
368
CMakeLists.txt
|
@ -1,5 +1,12 @@
|
||||||
project(OpenMW)
|
project(OpenMW)
|
||||||
|
|
||||||
|
# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them.
|
||||||
|
IF(NOT CMAKE_BUILD_TYPE)
|
||||||
|
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
|
||||||
|
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||||
|
FORCE)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||||
|
|
||||||
|
@ -12,7 +19,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
message(STATUS "Configuring OpenMW...")
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 31)
|
set(OPENMW_VERSION_MINOR 35)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
@ -20,29 +27,13 @@ set(OPENMW_VERSION_TAGHASH "")
|
||||||
|
|
||||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||||
|
|
||||||
|
set(GIT_CHECKOUT FALSE)
|
||||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
find_package(Git)
|
find_package(Git)
|
||||||
|
|
||||||
if(GIT_FOUND)
|
if(GIT_FOUND)
|
||||||
include(GetGitRevisionDescription)
|
set(GIT_CHECKOUT TRUE)
|
||||||
get_git_tag_revision(TAGHASH --tags --max-count=1)
|
|
||||||
get_git_head_revision(REFSPEC COMMITHASH)
|
|
||||||
git_describe(VERSION --tags ${TAGHASH})
|
|
||||||
|
|
||||||
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
|
||||||
if(MATCH)
|
|
||||||
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${VERSION}")
|
|
||||||
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
|
|
||||||
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
|
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
|
||||||
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
|
||||||
|
|
||||||
message(STATUS "OpenMW version ${OPENMW_VERSION}")
|
|
||||||
else(MATCH)
|
|
||||||
message(WARNING "Failed to get valid version information from Git")
|
|
||||||
endif(MATCH)
|
|
||||||
else(GIT_FOUND)
|
else(GIT_FOUND)
|
||||||
message(WARNING "Git executable not found")
|
message(WARNING "Git executable not found")
|
||||||
endif(GIT_FOUND)
|
endif(GIT_FOUND)
|
||||||
|
@ -54,28 +45,35 @@ endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
# Macros
|
# Macros
|
||||||
include(OpenMWMacros)
|
include(OpenMWMacros)
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}")
|
||||||
|
endif (ANDROID)
|
||||||
|
|
||||||
# doxygen main page
|
# doxygen main page
|
||||||
|
|
||||||
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/docs/mainpage.hpp")
|
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp")
|
||||||
|
|
||||||
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
|
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
|
||||||
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
|
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
|
||||||
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||||
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
||||||
|
|
||||||
|
set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)")
|
||||||
|
|
||||||
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
option(BUILD_BSATOOL "build BSA extractor" OFF)
|
option(BUILD_BSATOOL "build BSA extractor" ON)
|
||||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||||
option(BUILD_LAUNCHER "build Launcher" ON)
|
option(BUILD_LAUNCHER "build Launcher" ON)
|
||||||
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
||||||
|
option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON)
|
||||||
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
||||||
|
option(BUILD_WIZARD "build Installation Wizard" ON)
|
||||||
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
||||||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
|
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
||||||
|
option(BUILD_NIFTEST "build nif file tester" OFF)
|
||||||
# Sound source selection
|
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
||||||
option(USE_FFMPEG "use ffmpeg for sound" ON)
|
|
||||||
|
|
||||||
# OS X deployment
|
# OS X deployment
|
||||||
option(OPENMW_OSX_DEPLOYMENT OFF)
|
option(OPENMW_OSX_DEPLOYMENT OFF)
|
||||||
|
@ -101,33 +99,32 @@ cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
||||||
# source directory: libs
|
# source directory: libs
|
||||||
|
|
||||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
|
set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs)
|
||||||
|
|
||||||
set(OENGINE_OGRE
|
set(OENGINE_OGRE
|
||||||
${LIBDIR}/openengine/ogre/renderer.cpp
|
${LIBS_DIR}/openengine/ogre/renderer.cpp
|
||||||
${LIBDIR}/openengine/ogre/fader.cpp
|
${LIBS_DIR}/openengine/ogre/lights.cpp
|
||||||
${LIBDIR}/openengine/ogre/lights.cpp
|
${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp
|
||||||
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
|
${LIBS_DIR}/openengine/ogre/imagerotate.cpp
|
||||||
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(OENGINE_GUI
|
set(OENGINE_GUI
|
||||||
${LIBDIR}/openengine/gui/loglistener.cpp
|
${LIBS_DIR}/openengine/gui/loglistener.cpp
|
||||||
${LIBDIR}/openengine/gui/manager.cpp
|
${LIBS_DIR}/openengine/gui/manager.cpp
|
||||||
${LIBDIR}/openengine/gui/layout.hpp
|
${LIBS_DIR}/openengine/gui/layout.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(OENGINE_BULLET
|
set(OENGINE_BULLET
|
||||||
${LIBDIR}/openengine/bullet/BtOgre.cpp
|
${LIBS_DIR}/openengine/bullet/BtOgre.cpp
|
||||||
${LIBDIR}/openengine/bullet/BtOgreExtras.h
|
${LIBS_DIR}/openengine/bullet/BtOgreExtras.h
|
||||||
${LIBDIR}/openengine/bullet/BtOgreGP.h
|
${LIBS_DIR}/openengine/bullet/BtOgreGP.h
|
||||||
${LIBDIR}/openengine/bullet/BtOgrePG.h
|
${LIBS_DIR}/openengine/bullet/BtOgrePG.h
|
||||||
${LIBDIR}/openengine/bullet/physic.cpp
|
${LIBS_DIR}/openengine/bullet/physic.cpp
|
||||||
${LIBDIR}/openengine/bullet/physic.hpp
|
${LIBS_DIR}/openengine/bullet/physic.hpp
|
||||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
|
${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp
|
||||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.h
|
${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h
|
||||||
${LIBDIR}/openengine/bullet/trace.cpp
|
${LIBS_DIR}/openengine/bullet/trace.cpp
|
||||||
${LIBDIR}/openengine/bullet/trace.h
|
${LIBS_DIR}/openengine/bullet/trace.h
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,32 +135,24 @@ set(OPENMW_LIBS ${OENGINE_ALL})
|
||||||
set(OPENMW_LIBS_HEADER)
|
set(OPENMW_LIBS_HEADER)
|
||||||
|
|
||||||
# Sound setup
|
# Sound setup
|
||||||
set(GOT_SOUND_INPUT 0)
|
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
|
||||||
set(SOUND_INPUT_INCLUDES "")
|
unset(FFMPEG_LIBRARIES CACHE)
|
||||||
set(SOUND_INPUT_LIBRARY "")
|
|
||||||
set(SOUND_DEFINE "")
|
|
||||||
if (USE_FFMPEG)
|
|
||||||
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
|
|
||||||
find_package(FFmpeg)
|
find_package(FFmpeg)
|
||||||
if (FFMPEG_FOUND)
|
if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND )
|
||||||
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS})
|
message(FATAL_ERROR "FFmpeg component required, but not found!")
|
||||||
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
|
endif()
|
||||||
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
|
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
|
||||||
set(GOT_SOUND_INPUT 1)
|
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
|
||||||
endif (FFMPEG_FOUND)
|
if( SWRESAMPLE_FOUND )
|
||||||
endif (USE_FFMPEG)
|
add_definitions(-DHAVE_LIBSWRESAMPLE)
|
||||||
|
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
|
||||||
if (NOT GOT_SOUND_INPUT)
|
else()
|
||||||
message(WARNING "--------------------")
|
if( AVRESAMPLE_FOUND )
|
||||||
message(WARNING "Failed to find any sound input packages")
|
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
|
||||||
message(WARNING "--------------------")
|
else()
|
||||||
endif (NOT GOT_SOUND_INPUT)
|
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
|
||||||
|
endif()
|
||||||
if (NOT FFMPEG_FOUND)
|
endif()
|
||||||
message(WARNING "--------------------")
|
|
||||||
message(WARNING "FFmpeg not found, video playback will be disabled")
|
|
||||||
message(WARNING "--------------------")
|
|
||||||
endif (NOT FFMPEG_FOUND)
|
|
||||||
|
|
||||||
# TinyXML
|
# TinyXML
|
||||||
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
|
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
|
||||||
|
@ -227,7 +216,15 @@ IF(BOOST_STATIC)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(OGRE REQUIRED)
|
find_package(OGRE REQUIRED)
|
||||||
|
if (${OGRE_VERSION} VERSION_LESS "1.9")
|
||||||
|
message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org")
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(MyGUI REQUIRED)
|
find_package(MyGUI REQUIRED)
|
||||||
|
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
|
||||||
|
message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info")
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||||
find_package(SDL2 REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
find_package(OpenAL REQUIRED)
|
find_package(OpenAL REQUIRED)
|
||||||
|
@ -258,7 +255,12 @@ if(OGRE_STATIC)
|
||||||
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
|
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
|
||||||
endif(Cg_FOUND)
|
endif(Cg_FOUND)
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
add_static_ogre_plugin(RenderSystem_GLES2)
|
||||||
|
else ()
|
||||||
add_static_ogre_plugin(RenderSystem_GL)
|
add_static_ogre_plugin(RenderSystem_GL)
|
||||||
|
endif ()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_static_ogre_plugin(RenderSystem_Direct3D9)
|
add_static_ogre_plugin(RenderSystem_Direct3D9)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
@ -266,13 +268,14 @@ endif(OGRE_STATIC)
|
||||||
|
|
||||||
include_directories("."
|
include_directories("."
|
||||||
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS}
|
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS}
|
||||||
|
${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR}
|
||||||
${SDL2_INCLUDE_DIR}
|
${SDL2_INCLUDE_DIR}
|
||||||
${Boost_INCLUDE_DIR}
|
${Boost_INCLUDE_DIR}
|
||||||
${PLATFORM_INCLUDE_DIR}
|
${PLATFORM_INCLUDE_DIR}
|
||||||
${MYGUI_INCLUDE_DIRS}
|
${MYGUI_INCLUDE_DIRS}
|
||||||
${MYGUI_PLATFORM_INCLUDE_DIRS}
|
${MYGUI_PLATFORM_INCLUDE_DIRS}
|
||||||
${OPENAL_INCLUDE_DIR}
|
${OPENAL_INCLUDE_DIR}
|
||||||
${LIBDIR}
|
${LIBS_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
|
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
|
||||||
|
@ -329,8 +332,10 @@ if (APPLE AND OPENMW_OSX_DEPLOYMENT)
|
||||||
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
|
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
|
||||||
add_definitions(-DOGRE_PLUGIN_DIR="")
|
add_definitions(-DOGRE_PLUGIN_DIR="")
|
||||||
else()
|
else()
|
||||||
if (NOT DEFINED ${OGRE_PLUGIN_DIR})
|
if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "")
|
||||||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
|
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
|
||||||
|
else()
|
||||||
|
set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
|
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
|
||||||
|
@ -344,8 +349,10 @@ add_subdirectory(files/mygui)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
|
||||||
else (APPLE)
|
else (APPLE)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
# Other files
|
# Other files
|
||||||
|
@ -368,41 +375,54 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
||||||
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
|
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
|
||||||
|
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt
|
||||||
|
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt")
|
||||||
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
if (NOT WIN32 AND NOT APPLE)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
|
||||||
"${OpenMW_BINARY_DIR}/openmw.desktop")
|
"${OpenMW_BINARY_DIR}/openmw.desktop")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop
|
||||||
"${OpenMW_BINARY_DIR}/opencs.desktop")
|
"${OpenMW_BINARY_DIR}/openmw-cs.desktop")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Compiler settings
|
# Compiler settings
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
if (CMAKE_COMPILER_IS_GNUCC)
|
||||||
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
|
set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long")
|
||||||
|
|
||||||
# Silence warnings in OGRE headers. Remove once OGRE got fixed!
|
|
||||||
SET(CMAKE_CXX_FLAGS "-Wno-ignored-qualifiers ${CMAKE_CXX_FLAGS}")
|
|
||||||
|
|
||||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||||
OUTPUT_VARIABLE GCC_VERSION)
|
OUTPUT_VARIABLE GCC_VERSION)
|
||||||
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
|
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
|
||||||
SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}")
|
set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-unused-but-set-parameter")
|
||||||
endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
|
endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
|
||||||
|
elseif (MSVC)
|
||||||
|
# Enable link-time code generation globally for all linking
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
|
||||||
|
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
|
||||||
endif (CMAKE_COMPILER_IS_GNUCC)
|
endif (CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
IF(NOT WIN32 AND NOT APPLE)
|
IF(NOT WIN32 AND NOT APPLE)
|
||||||
# Linux building
|
# Linux building
|
||||||
# Paths
|
# Paths
|
||||||
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
||||||
|
SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries")
|
||||||
SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
|
SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
|
||||||
SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
|
SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix")
|
||||||
|
SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
|
||||||
SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
|
SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
|
||||||
SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
|
SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
|
||||||
SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir")
|
IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr")
|
||||||
|
SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix")
|
||||||
|
ELSE()
|
||||||
|
SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix")
|
||||||
|
ENDIF()
|
||||||
|
SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir")
|
||||||
|
|
||||||
# Install binaries
|
# Install binaries
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
|
||||||
IF(BUILD_LAUNCHER)
|
IF(BUILD_LAUNCHER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_LAUNCHER)
|
ENDIF(BUILD_LAUNCHER)
|
||||||
IF(BUILD_BSATOOL)
|
IF(BUILD_BSATOOL)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
|
||||||
|
@ -411,34 +431,48 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_ESMTOOL)
|
ENDIF(BUILD_ESMTOOL)
|
||||||
IF(BUILD_MWINIIMPORTER)
|
IF(BUILD_MWINIIMPORTER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-iniimporter" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_MWINIIMPORTER)
|
ENDIF(BUILD_MWINIIMPORTER)
|
||||||
|
IF(BUILD_ESSIMPORTER)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" )
|
||||||
|
ENDIF(BUILD_ESSIMPORTER)
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
IF(BUILD_NIFTEST)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
|
||||||
|
ENDIF(BUILD_NIFTEST)
|
||||||
|
IF(BUILD_WIZARD)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
|
||||||
|
ENDIF(BUILD_WIZARD)
|
||||||
|
if(BUILD_MYGUI_PLUGIN)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
|
||||||
|
ENDIF(BUILD_MYGUI_PLUGIN)
|
||||||
|
|
||||||
# Install licenses
|
# Install licenses
|
||||||
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
||||||
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
|
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
|
||||||
|
|
||||||
# Install icon and desktop file
|
# Install icon and desktop file
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw")
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs")
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/opencs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs")
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs")
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
|
||||||
# Install global configuration files
|
# Install global configuration files
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
|
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
|
||||||
# Install resources
|
# Install resources
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources")
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" COMPONENT "Resources")
|
||||||
INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources")
|
INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources")
|
||||||
ENDIF(NOT WIN32 AND NOT APPLE)
|
ENDIF(NOT WIN32 AND NOT APPLE)
|
||||||
|
|
||||||
|
@ -446,25 +480,36 @@ if(WIN32)
|
||||||
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
|
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
|
||||||
INSTALL(FILES ${dll_files} DESTINATION ".")
|
INSTALL(FILES ${dll_files} DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||||
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
||||||
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
|
||||||
INSTALL(FILES
|
INSTALL(FILES
|
||||||
"${OpenMW_SOURCE_DIR}/readme.txt"
|
|
||||||
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
|
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
|
||||||
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
|
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
||||||
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
|
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
|
||||||
|
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
||||||
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
|
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
|
||||||
DESTINATION ".")
|
DESTINATION ".")
|
||||||
|
|
||||||
IF(BUILD_LAUNCHER)
|
IF(BUILD_LAUNCHER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" DESTINATION ".")
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION ".")
|
||||||
ENDIF(BUILD_LAUNCHER)
|
ENDIF(BUILD_LAUNCHER)
|
||||||
IF(BUILD_MWINIIMPORTER)
|
IF(BUILD_MWINIIMPORTER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" DESTINATION ".")
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION ".")
|
||||||
ENDIF(BUILD_MWINIIMPORTER)
|
ENDIF(BUILD_MWINIIMPORTER)
|
||||||
|
IF(BUILD_ESSIMPORTER)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".")
|
||||||
|
ENDIF(BUILD_ESSIMPORTER)
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".")
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
IF(BUILD_WIZARD)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".")
|
||||||
|
ENDIF(BUILD_WIZARD)
|
||||||
|
if(BUILD_MYGUI_PLUGIN)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".")
|
||||||
|
ENDIF(BUILD_MYGUI_PLUGIN)
|
||||||
|
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||||
|
|
||||||
|
@ -477,25 +522,28 @@ if(WIN32)
|
||||||
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW")
|
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW")
|
||||||
IF(BUILD_LAUNCHER)
|
IF(BUILD_LAUNCHER)
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};omwlauncher;OpenMW Launcher")
|
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher")
|
||||||
ENDIF(BUILD_LAUNCHER)
|
ENDIF(BUILD_LAUNCHER)
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set")
|
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set")
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'")
|
IF(BUILD_WIZARD)
|
||||||
|
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard")
|
||||||
|
ENDIF(BUILD_WIZARD)
|
||||||
|
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\README.txt'")
|
||||||
SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
|
SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
|
||||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
||||||
Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\"
|
Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\"
|
||||||
")
|
")
|
||||||
SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt")
|
SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/README.md")
|
||||||
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
|
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md")
|
||||||
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||||
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}")
|
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}")
|
||||||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
|
SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe")
|
||||||
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico")
|
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||||
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico")
|
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||||
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
||||||
|
|
||||||
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
||||||
|
@ -526,12 +574,23 @@ endif(WIN32)
|
||||||
|
|
||||||
# Extern
|
# Extern
|
||||||
add_subdirectory (extern/shiny)
|
add_subdirectory (extern/shiny)
|
||||||
|
add_subdirectory (extern/ogre-ffmpeg-videoplayer)
|
||||||
add_subdirectory (extern/oics)
|
add_subdirectory (extern/oics)
|
||||||
add_subdirectory (extern/sdl4ogre)
|
add_subdirectory (extern/sdl4ogre)
|
||||||
|
|
||||||
# Components
|
# Components
|
||||||
add_subdirectory (components)
|
add_subdirectory (components)
|
||||||
|
|
||||||
|
# Plugins
|
||||||
|
if (BUILD_MYGUI_PLUGIN)
|
||||||
|
add_subdirectory(plugins/mygui_resource_plugin)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#Testing
|
||||||
|
if (BUILD_NIFTEST)
|
||||||
|
add_subdirectory(components/nif/tests/)
|
||||||
|
endif(BUILD_NIFTEST)
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
add_subdirectory( apps/openmw )
|
add_subdirectory( apps/openmw )
|
||||||
|
|
||||||
|
@ -544,13 +603,6 @@ if (BUILD_ESMTOOL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_LAUNCHER)
|
if (BUILD_LAUNCHER)
|
||||||
if(NOT WIN32)
|
|
||||||
find_package(LIBUNSHIELD REQUIRED)
|
|
||||||
if(NOT LIBUNSHIELD_FOUND)
|
|
||||||
message(SEND_ERROR "Failed to find libunshield")
|
|
||||||
endif(NOT LIBUNSHIELD_FOUND)
|
|
||||||
endif(NOT WIN32)
|
|
||||||
|
|
||||||
add_subdirectory( apps/launcher )
|
add_subdirectory( apps/launcher )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -558,10 +610,18 @@ if (BUILD_MWINIIMPORTER)
|
||||||
add_subdirectory( apps/mwiniimporter )
|
add_subdirectory( apps/mwiniimporter )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (BUILD_ESSIMPORTER)
|
||||||
|
add_subdirectory (apps/essimporter )
|
||||||
|
endif()
|
||||||
|
|
||||||
if (BUILD_OPENCS)
|
if (BUILD_OPENCS)
|
||||||
add_subdirectory (apps/opencs)
|
add_subdirectory (apps/opencs)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (BUILD_WIZARD)
|
||||||
|
add_subdirectory(apps/wizard)
|
||||||
|
endif()
|
||||||
|
|
||||||
# UnitTests
|
# UnitTests
|
||||||
if (BUILD_UNITTESTS)
|
if (BUILD_UNITTESTS)
|
||||||
add_subdirectory( apps/openmw_test_suite )
|
add_subdirectory( apps/openmw_test_suite )
|
||||||
|
@ -569,6 +629,16 @@ endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
if (MULTITHREADED_BUILD)
|
||||||
|
set( MT_BUILD "/MP")
|
||||||
|
endif (MULTITHREADED_BUILD)
|
||||||
|
|
||||||
|
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
|
||||||
|
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
|
||||||
|
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(SolutionDir)$(Configuration)" )
|
||||||
|
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" )
|
||||||
|
endforeach( OUTPUTCONFIG )
|
||||||
|
|
||||||
if (USE_DEBUG_CONSOLE)
|
if (USE_DEBUG_CONSOLE)
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||||
|
@ -608,10 +678,15 @@ if (WIN32)
|
||||||
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
|
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
|
||||||
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
|
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
|
||||||
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
|
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
|
||||||
|
4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h)
|
||||||
|
|
||||||
|
# caused by boost
|
||||||
|
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
|
||||||
|
|
||||||
# OpenMW specific warnings
|
# OpenMW specific warnings
|
||||||
4099 # Type mismatch, declared class or struct is defined with other type
|
4099 # Type mismatch, declared class or struct is defined with other type
|
||||||
4100 # Unreferenced formal parameter (-Wunused-parameter)
|
4100 # Unreferenced formal parameter (-Wunused-parameter)
|
||||||
|
4101 # Unreferenced local variable (-Wunused-variable)
|
||||||
4127 # Conditional expression is constant
|
4127 # Conditional expression is constant
|
||||||
4242 # Storing value in a variable of a smaller type, possible loss of data
|
4242 # Storing value in a variable of a smaller type, possible loss of data
|
||||||
4244 # Storing value of one type in variable of another (size_t in int, for example)
|
4244 # Storing value of one type in variable of another (size_t in int, for example)
|
||||||
|
@ -630,51 +705,23 @@ if (WIN32)
|
||||||
set(WARNINGS "${WARNINGS} /wd${d}")
|
set(WARNINGS "${WARNINGS} /wd${d}")
|
||||||
endforeach(d)
|
endforeach(d)
|
||||||
|
|
||||||
|
set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||||
|
|
||||||
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
|
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
|
||||||
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
|
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
|
||||||
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${SHINY_WARNINGS})
|
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
|
||||||
# there's an unreferenced local variable in the ogre platform, suppress it
|
|
||||||
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
|
|
||||||
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS})
|
|
||||||
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
# oics uses tinyxml, which has an initialized but unused variable
|
# oics uses tinyxml, which has an initialized but unused variable
|
||||||
set(OICS_WARNINGS "${WARNINGS} /wd4189")
|
set(OICS_WARNINGS "${WARNINGS} /wd4189")
|
||||||
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${OICS_WARNINGS})
|
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
|
||||||
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
if (BUILD_LAUNCHER)
|
|
||||||
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
endif (BUILD_LAUNCHER)
|
|
||||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
if (BUILD_BSATOOL)
|
|
||||||
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
endif (BUILD_BSATOOL)
|
|
||||||
if (BUILD_ESMTOOL)
|
|
||||||
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
endif (BUILD_ESMTOOL)
|
|
||||||
if (BUILD_OPENCS)
|
if (BUILD_OPENCS)
|
||||||
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
# QT triggers an informational warning that the object layout may differ when compiled with /vd2
|
||||||
|
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")
|
||||||
|
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
|
||||||
endif (BUILD_OPENCS)
|
endif (BUILD_OPENCS)
|
||||||
if (BUILD_MWINIIMPORTER)
|
|
||||||
set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
|
||||||
endif (BUILD_MWINIIMPORTER)
|
|
||||||
endif(MSVC)
|
endif(MSVC)
|
||||||
|
|
||||||
# Same for MinGW
|
|
||||||
if (MINGW)
|
|
||||||
if (USE_DEBUG_CONSOLE)
|
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,console")
|
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,console")
|
|
||||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
|
|
||||||
else(USE_DEBUG_CONSOLE)
|
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,windows")
|
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,windows")
|
|
||||||
endif(USE_DEBUG_CONSOLE)
|
|
||||||
|
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "-Wl,-subsystem,console")
|
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "-Wl,-subsystem,console")
|
|
||||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
|
||||||
endif(MINGW)
|
|
||||||
|
|
||||||
# TODO: At some point release builds should not use the console but rather write to a log file
|
# TODO: At some point release builds should not use the console but rather write to a log file
|
||||||
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||||
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||||
|
@ -688,6 +735,7 @@ if (APPLE)
|
||||||
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
|
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||||
|
|
||||||
|
@ -699,7 +747,7 @@ if (APPLE)
|
||||||
|
|
||||||
set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
||||||
|
|
||||||
set(OPENCS_BUNDLE_NAME "OpenCS.app")
|
set(OPENCS_BUNDLE_NAME "OpenMW-CS.app")
|
||||||
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
||||||
|
|
||||||
set(ABSOLUTE_PLUGINS "")
|
set(ABSOLUTE_PLUGINS "")
|
||||||
|
@ -789,3 +837,25 @@ if (APPLE)
|
||||||
include(CPack)
|
include(CPack)
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
|
# Doxygen Target -- simply run 'make doc' or 'make doc_pages'
|
||||||
|
# output directory for 'make doc' is "${OpenMW_BINARY_DIR}/docs/Doxygen"
|
||||||
|
# output directory for 'make doc_pages' is "${DOXYGEN_PAGES_OUTPUT_DIR}" if defined
|
||||||
|
# or "${OpenMW_BINARY_DIR}/docs/Pages" otherwise
|
||||||
|
find_package(Doxygen)
|
||||||
|
if (DOXYGEN_FOUND)
|
||||||
|
# determine output directory for doc_pages
|
||||||
|
if (NOT DEFINED DOXYGEN_PAGES_OUTPUT_DIR)
|
||||||
|
set(DOXYGEN_PAGES_OUTPUT_DIR "${OpenMW_BINARY_DIR}/docs/Pages")
|
||||||
|
endif ()
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/docs/Doxyfile.cmake ${OpenMW_BINARY_DIR}/docs/Doxyfile @ONLY)
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/docs/DoxyfilePages.cmake ${OpenMW_BINARY_DIR}/docs/DoxyfilePages @ONLY)
|
||||||
|
add_custom_target(doc
|
||||||
|
${DOXYGEN_EXECUTABLE} ${OpenMW_BINARY_DIR}/docs/Doxyfile
|
||||||
|
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
||||||
|
COMMENT "Generating Doxygen documentation at ${OpenMW_BINARY_DIR}/docs/Doxygen"
|
||||||
|
VERBATIM)
|
||||||
|
add_custom_target(doc_pages
|
||||||
|
${DOXYGEN_EXECUTABLE} ${OpenMW_BINARY_DIR}/docs/DoxyfilePages
|
||||||
|
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
||||||
|
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
||||||
|
endif ()
|
||||||
|
|
99
README.md
Normal file
99
README.md
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
OpenMW
|
||||||
|
======
|
||||||
|
|
||||||
|
[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740)
|
||||||
|
|
||||||
|
OpenMW is an attempt at recreating the engine for the popular role-playing game
|
||||||
|
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
|
||||||
|
|
||||||
|
* Version: 0.35.0
|
||||||
|
* License: GPL (see docs/license/GPL3.txt for more information)
|
||||||
|
* Website: http://www.openmw.org
|
||||||
|
* IRC: #openmw on irc.freenode.net
|
||||||
|
|
||||||
|
Font Licenses:
|
||||||
|
* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information)
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
---------------
|
||||||
|
|
||||||
|
* [Official forums](https://forum.openmw.org/)
|
||||||
|
* [Installation instructions](https://wiki.openmw.org/index.php?title=Installation_Instructions)
|
||||||
|
* [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup)
|
||||||
|
* [Testing the game](https://wiki.openmw.org/index.php?title=Testing)
|
||||||
|
* [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted)
|
||||||
|
* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug!
|
||||||
|
* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker)
|
||||||
|
|
||||||
|
The data path
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install).
|
||||||
|
|
||||||
|
Command line options
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Syntax: openmw <options>
|
||||||
|
Allowed options:
|
||||||
|
--help print help message
|
||||||
|
--version print version information and quit
|
||||||
|
--data arg (=data) set data directories (later directories
|
||||||
|
have higher priority)
|
||||||
|
--data-local arg set local data directory (highest
|
||||||
|
priority)
|
||||||
|
--fallback-archive arg (=fallback-archive)
|
||||||
|
set fallback BSA archives (later
|
||||||
|
archives have higher priority)
|
||||||
|
--resources arg (=resources) set resources directory
|
||||||
|
--start arg set initial cell
|
||||||
|
--content arg content file(s): esm/esp, or
|
||||||
|
omwgame/omwaddon
|
||||||
|
--no-sound [=arg(=1)] (=0) disable all sounds
|
||||||
|
--script-verbose [=arg(=1)] (=0) verbose script output
|
||||||
|
--script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue
|
||||||
|
scripts) at startup
|
||||||
|
--script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup
|
||||||
|
--script-console [=arg(=1)] (=0) enable console-only script
|
||||||
|
functionality
|
||||||
|
--script-run arg select a file containing a list of
|
||||||
|
console commands that is executed on
|
||||||
|
startup
|
||||||
|
--script-warn [=arg(=1)] (=1) handling of warnings when compiling
|
||||||
|
scripts
|
||||||
|
0 - ignore warning
|
||||||
|
1 - show warning but consider script as
|
||||||
|
correctly compiled anyway
|
||||||
|
2 - treat warnings as errors
|
||||||
|
--script-blacklist arg ignore the specified script (if the use
|
||||||
|
of the blacklist is enabled)
|
||||||
|
--script-blacklist-use [=arg(=1)] (=1)
|
||||||
|
enable script blacklisting
|
||||||
|
--load-savegame arg load a save game file on game startup
|
||||||
|
(specify an absolute filename or a
|
||||||
|
filename relative to the current
|
||||||
|
working directory)
|
||||||
|
--skip-menu [=arg(=1)] (=0) skip main menu on game startup
|
||||||
|
--new-game [=arg(=1)] (=0) run new game sequence (ignored if
|
||||||
|
skip-menu=0)
|
||||||
|
--fs-strict [=arg(=1)] (=0) strict file system handling (no case
|
||||||
|
folding)
|
||||||
|
--encoding arg (=win1252) Character encoding used in OpenMW game
|
||||||
|
messages:
|
||||||
|
|
||||||
|
win1250 - Central and Eastern European
|
||||||
|
such as Polish, Czech, Slovak,
|
||||||
|
Hungarian, Slovene, Bosnian, Croatian,
|
||||||
|
Serbian (Latin script), Romanian and
|
||||||
|
Albanian languages
|
||||||
|
|
||||||
|
win1251 - Cyrillic alphabet such as
|
||||||
|
Russian, Bulgarian, Serbian Cyrillic
|
||||||
|
and other languages
|
||||||
|
|
||||||
|
win1252 - Western European (Latin)
|
||||||
|
alphabet, used by default
|
||||||
|
--fallback arg fallback values
|
||||||
|
--no-grab Don't grab mouse cursor
|
||||||
|
--export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG
|
||||||
|
image and XML file in current directory
|
||||||
|
--activate-dist arg (=-1) activation distance override
|
|
@ -27,8 +27,8 @@ struct Arguments
|
||||||
|
|
||||||
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
|
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
|
||||||
{
|
{
|
||||||
int pos = str.find(needle);
|
size_t pos = str.find(needle);
|
||||||
while(pos != -1)
|
while(pos != std::string::npos)
|
||||||
{
|
{
|
||||||
str.replace(pos, needle.size(), substitute);
|
str.replace(pos, needle.size(), substitute);
|
||||||
pos = str.find(needle);
|
pos = str.find(needle);
|
||||||
|
@ -51,7 +51,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
("help,h", "print help message.")
|
("help,h", "print help message.")
|
||||||
("version,v", "print version information and quit.")
|
("version,v", "print version information and quit.")
|
||||||
("long,l", "Include extra information in archive listing.")
|
("long,l", "Include extra information in archive listing.")
|
||||||
("full-path,f", "Create diretory hierarchy on file extraction "
|
("full-path,f", "Create directory hierarchy on file extraction "
|
||||||
"(always true for extractall).")
|
"(always true for extractall).")
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -138,8 +138,8 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
||||||
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
|
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
|
||||||
|
|
||||||
info.longformat = variables.count("long");
|
info.longformat = variables.count("long") != 0;
|
||||||
info.fullpath = variables.count("full-path");
|
info.fullpath = variables.count("full-path") != 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,8 @@ int extract(Bsa::BSAFile& bsa, Arguments& info);
|
||||||
int extractAll(Bsa::BSAFile& bsa, Arguments& info);
|
int extractAll(Bsa::BSAFile& bsa, Arguments& info);
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Arguments info;
|
Arguments info;
|
||||||
if(!parseOptions (argc, argv, info))
|
if(!parseOptions (argc, argv, info))
|
||||||
|
@ -156,16 +158,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
Bsa::BSAFile bsa;
|
Bsa::BSAFile bsa;
|
||||||
try
|
|
||||||
{
|
|
||||||
bsa.open(info.filename);
|
bsa.open(info.filename);
|
||||||
}
|
|
||||||
catch(std::exception &e)
|
|
||||||
{
|
|
||||||
std::cout << "ERROR reading BSA archive '" << info.filename
|
|
||||||
<< "'\nDetails:\n" << e.what() << std::endl;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.mode == "list")
|
if (info.mode == "list")
|
||||||
return list(bsa, info);
|
return list(bsa, info);
|
||||||
|
@ -179,6 +172,12 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR reading BSA archive\nDetails:\n" << e.what() << std::endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int list(Bsa::BSAFile& bsa, Arguments& info)
|
int list(Bsa::BSAFile& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
|
@ -189,9 +188,11 @@ int list(Bsa::BSAFile& bsa, Arguments& info)
|
||||||
if(info.longformat)
|
if(info.longformat)
|
||||||
{
|
{
|
||||||
// Long format
|
// Long format
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << std::setw(50) << std::left << files[i].name;
|
std::cout << std::setw(50) << std::left << files[i].name;
|
||||||
std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize;
|
std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize;
|
||||||
std::cout << "@ 0x" << std::hex << files[i].offset << std::endl;
|
std::cout << "@ 0x" << std::hex << files[i].offset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << files[i].name << std::endl;
|
std::cout << files[i].name << std::endl;
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct ESMData
|
||||||
{
|
{
|
||||||
std::string author;
|
std::string author;
|
||||||
std::string description;
|
std::string description;
|
||||||
int version;
|
unsigned int version;
|
||||||
std::vector<ESM::Header::MasterData> masters;
|
std::vector<ESM::Header::MasterData> masters;
|
||||||
|
|
||||||
std::deque<EsmTool::RecordBase *> mRecords;
|
std::deque<EsmTool::RecordBase *> mRecords;
|
||||||
|
@ -48,9 +48,9 @@ const std::set<int> ESMData::sLabeledRec =
|
||||||
// Based on the legacy struct
|
// Based on the legacy struct
|
||||||
struct Arguments
|
struct Arguments
|
||||||
{
|
{
|
||||||
unsigned int raw_given;
|
bool raw_given;
|
||||||
unsigned int quiet_given;
|
bool quiet_given;
|
||||||
unsigned int loadcells_given;
|
bool loadcells_given;
|
||||||
bool plain_given;
|
bool plain_given;
|
||||||
|
|
||||||
std::string mode;
|
std::string mode;
|
||||||
|
@ -59,6 +59,7 @@ struct Arguments
|
||||||
std::string outname;
|
std::string outname;
|
||||||
|
|
||||||
std::vector<std::string> types;
|
std::vector<std::string> types;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
ESMData data;
|
ESMData data;
|
||||||
ESM::ESMReader reader;
|
ESM::ESMReader reader;
|
||||||
|
@ -78,6 +79,8 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
("type,t", bpo::value< std::vector<std::string> >(),
|
("type,t", bpo::value< std::vector<std::string> >(),
|
||||||
"Show only records of this type (four character record code). May "
|
"Show only records of this type (four character record code). May "
|
||||||
"be specified multiple times. Only affects dump mode.")
|
"be specified multiple times. Only affects dump mode.")
|
||||||
|
("name,n", bpo::value<std::string>(),
|
||||||
|
"Show only the record with this name. Only affects dump mode.")
|
||||||
("plain,p", "Print contents of dialogs, books and scripts. "
|
("plain,p", "Print contents of dialogs, books and scripts. "
|
||||||
"(skipped by default)"
|
"(skipped by default)"
|
||||||
"Only affects dump mode.")
|
"Only affects dump mode.")
|
||||||
|
@ -149,6 +152,8 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
|
|
||||||
if (variables.count("type") > 0)
|
if (variables.count("type") > 0)
|
||||||
info.types = variables["type"].as< std::vector<std::string> >();
|
info.types = variables["type"].as< std::vector<std::string> >();
|
||||||
|
if (variables.count("name") > 0)
|
||||||
|
info.name = variables["name"].as<std::string>();
|
||||||
|
|
||||||
info.mode = variables["mode"].as<std::string>();
|
info.mode = variables["mode"].as<std::string>();
|
||||||
if (!(info.mode == "dump" || info.mode == "clone" || info.mode == "comp"))
|
if (!(info.mode == "dump" || info.mode == "clone" || info.mode == "comp"))
|
||||||
|
@ -177,10 +182,10 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
||||||
info.outname = variables["input-file"].as< std::vector<std::string> >()[1];
|
info.outname = variables["input-file"].as< std::vector<std::string> >()[1];
|
||||||
|
|
||||||
info.raw_given = variables.count ("raw");
|
info.raw_given = variables.count ("raw") != 0;
|
||||||
info.quiet_given = variables.count ("quiet");
|
info.quiet_given = variables.count ("quiet") != 0;
|
||||||
info.loadcells_given = variables.count ("loadcells");
|
info.loadcells_given = variables.count ("loadcells") != 0;
|
||||||
info.plain_given = (variables.count("plain") > 0);
|
info.plain_given = variables.count("plain") != 0;
|
||||||
|
|
||||||
// Font encoding settings
|
// Font encoding settings
|
||||||
info.encoding = variables["encoding"].as<std::string>();
|
info.encoding = variables["encoding"].as<std::string>();
|
||||||
|
@ -202,6 +207,8 @@ int clone(Arguments& info);
|
||||||
int comp(Arguments& info);
|
int comp(Arguments& info);
|
||||||
|
|
||||||
int main(int argc, char**argv)
|
int main(int argc, char**argv)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Arguments info;
|
Arguments info;
|
||||||
if(!parseOptions (argc, argv, info))
|
if(!parseOptions (argc, argv, info))
|
||||||
|
@ -218,6 +225,12 @@ int main(int argc, char**argv)
|
||||||
std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl;
|
std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -253,10 +266,12 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
||||||
std::cout << " Faction: '" << ref.mFaction << "'" << std::endl;
|
std::cout << " Faction: '" << ref.mFaction << "'" << std::endl;
|
||||||
std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl;
|
std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl;
|
||||||
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
||||||
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
std::cout << " Uses/health: '" << ref.mChargeInt << "'\n";
|
||||||
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
||||||
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
|
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
|
||||||
std::cout << " Deleted: " << deleted << std::endl;
|
std::cout << " Deleted: " << deleted << std::endl;
|
||||||
|
if (!ref.mKey.empty())
|
||||||
|
std::cout << " Key: '" << ref.mKey << "'" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,8 +288,10 @@ void printRaw(ESM::ESMReader &esm)
|
||||||
esm.getSubName();
|
esm.getSubName();
|
||||||
esm.skipHSub();
|
esm.skipHSub();
|
||||||
n = esm.retSubName();
|
n = esm.retSubName();
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << " " << n.toString() << " - " << esm.getSubSize()
|
std::cout << " " << n.toString() << " - " << esm.getSubSize()
|
||||||
<< " bytes @ 0x" << std::hex << offs << "\n";
|
<< " bytes @ 0x" << std::hex << offs << "\n";
|
||||||
|
std::cout.flags(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,6 +365,9 @@ int load(Arguments& info)
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
id = esm.getHNOString("INAM");
|
id = esm.getHNOString("INAM");
|
||||||
|
|
||||||
|
if (!info.name.empty() && !Misc::StringUtils::ciEqual(info.name, id))
|
||||||
|
interested = false;
|
||||||
|
|
||||||
if(!quiet && interested)
|
if(!quiet && interested)
|
||||||
std::cout << "\nRecord: " << n.toString()
|
std::cout << "\nRecord: " << n.toString()
|
||||||
<< " '" << id << "'\n";
|
<< " '" << id << "'\n";
|
||||||
|
@ -375,7 +395,7 @@ int load(Arguments& info)
|
||||||
record->load(esm);
|
record->load(esm);
|
||||||
if (!quiet && interested) record->print();
|
if (!quiet && interested) record->print();
|
||||||
|
|
||||||
if (record->getType().val == ESM::REC_CELL && loadCells) {
|
if (record->getType().val == ESM::REC_CELL && loadCells && interested) {
|
||||||
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
|
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +440,7 @@ int clone(Arguments& info)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int recordCount = info.data.mRecords.size();
|
size_t recordCount = info.data.mRecords.size();
|
||||||
|
|
||||||
int digitCount = 1; // For a nicer output
|
int digitCount = 1; // For a nicer output
|
||||||
if (recordCount > 9) ++digitCount;
|
if (recordCount > 9) ++digitCount;
|
||||||
|
@ -491,9 +511,9 @@ int clone(Arguments& info)
|
||||||
if (!info.data.mCellRefs[ptr].empty()) {
|
if (!info.data.mCellRefs[ptr].empty()) {
|
||||||
typedef std::deque<ESM::CellRef> RefList;
|
typedef std::deque<ESM::CellRef> RefList;
|
||||||
RefList &refs = info.data.mCellRefs[ptr];
|
RefList &refs = info.data.mCellRefs[ptr];
|
||||||
for (RefList::iterator it = refs.begin(); it != refs.end(); ++it)
|
for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt)
|
||||||
{
|
{
|
||||||
it->save(esm);
|
refIt->save(esm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,7 +521,7 @@ int clone(Arguments& info)
|
||||||
esm.endRecord(name.toString());
|
esm.endRecord(name.toString());
|
||||||
|
|
||||||
saved++;
|
saved++;
|
||||||
int perc = (saved / (float)recordCount)*100;
|
int perc = (int)((saved / (float)recordCount)*100);
|
||||||
if (perc % 10 == 0)
|
if (perc % 10 == 0)
|
||||||
{
|
{
|
||||||
std::cerr << "\r" << perc << "%";
|
std::cerr << "\r" << perc << "%";
|
||||||
|
|
|
@ -13,12 +13,13 @@
|
||||||
#include <components/esm/loadweap.hpp>
|
#include <components/esm/loadweap.hpp>
|
||||||
#include <components/esm/aipackage.hpp>
|
#include <components/esm/aipackage.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
std::string bodyPartLabel(int idx)
|
std::string bodyPartLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *bodyPartLabels[] = {
|
if (idx >= 0 && idx <= 26)
|
||||||
|
{
|
||||||
|
static const char *bodyPartLabels[] = {
|
||||||
"Head",
|
"Head",
|
||||||
"Hair",
|
"Hair",
|
||||||
"Neck",
|
"Neck",
|
||||||
|
@ -47,16 +48,17 @@ std::string bodyPartLabel(int idx)
|
||||||
"Weapon",
|
"Weapon",
|
||||||
"Tail"
|
"Tail"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 26)
|
|
||||||
return bodyPartLabels[idx];
|
return bodyPartLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string meshPartLabel(int idx)
|
std::string meshPartLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *meshPartLabels[] = {
|
if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail)
|
||||||
|
{
|
||||||
|
static const char *meshPartLabels[] = {
|
||||||
"Head",
|
"Head",
|
||||||
"Hair",
|
"Hair",
|
||||||
"Neck",
|
"Neck",
|
||||||
|
@ -73,30 +75,32 @@ std::string meshPartLabel(int idx)
|
||||||
"Clavicle",
|
"Clavicle",
|
||||||
"Tail"
|
"Tail"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail)
|
|
||||||
return meshPartLabels[idx];
|
return meshPartLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string meshTypeLabel(int idx)
|
std::string meshTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *meshTypeLabels[] = {
|
if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor)
|
||||||
|
{
|
||||||
|
static const char *meshTypeLabels[] = {
|
||||||
"Skin",
|
"Skin",
|
||||||
"Clothing",
|
"Clothing",
|
||||||
"Armor"
|
"Armor"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor)
|
|
||||||
return meshTypeLabels[idx];
|
return meshTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string clothingTypeLabel(int idx)
|
std::string clothingTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *clothingTypeLabels[] = {
|
if (idx >= 0 && idx <= 9)
|
||||||
|
{
|
||||||
|
static const char *clothingTypeLabels[] = {
|
||||||
"Pants",
|
"Pants",
|
||||||
"Shoes",
|
"Shoes",
|
||||||
"Shirt",
|
"Shirt",
|
||||||
|
@ -108,16 +112,17 @@ std::string clothingTypeLabel(int idx)
|
||||||
"Ring",
|
"Ring",
|
||||||
"Amulet"
|
"Amulet"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 9)
|
|
||||||
return clothingTypeLabels[idx];
|
return clothingTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string armorTypeLabel(int idx)
|
std::string armorTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *armorTypeLabels[] = {
|
if (idx >= 0 && idx <= 10)
|
||||||
|
{
|
||||||
|
static const char *armorTypeLabels[] = {
|
||||||
"Helmet",
|
"Helmet",
|
||||||
"Cuirass",
|
"Cuirass",
|
||||||
"Left Pauldron",
|
"Left Pauldron",
|
||||||
|
@ -130,25 +135,25 @@ std::string armorTypeLabel(int idx)
|
||||||
"Left Bracer",
|
"Left Bracer",
|
||||||
"Right Bracer"
|
"Right Bracer"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 10)
|
|
||||||
return armorTypeLabels[idx];
|
return armorTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string dialogTypeLabel(int idx)
|
std::string dialogTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *dialogTypeLabels[] = {
|
if (idx >= 0 && idx <= 4)
|
||||||
|
{
|
||||||
|
static const char *dialogTypeLabels[] = {
|
||||||
"Topic",
|
"Topic",
|
||||||
"Voice",
|
"Voice",
|
||||||
"Greeting",
|
"Greeting",
|
||||||
"Persuasion",
|
"Persuasion",
|
||||||
"Journal"
|
"Journal"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 4)
|
|
||||||
return dialogTypeLabels[idx];
|
return dialogTypeLabels[idx];
|
||||||
|
}
|
||||||
else if (idx == -1)
|
else if (idx == -1)
|
||||||
return "Deleted";
|
return "Deleted";
|
||||||
else
|
else
|
||||||
|
@ -157,38 +162,42 @@ std::string dialogTypeLabel(int idx)
|
||||||
|
|
||||||
std::string questStatusLabel(int idx)
|
std::string questStatusLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *questStatusLabels[] = {
|
if (idx >= 0 && idx <= 4)
|
||||||
|
{
|
||||||
|
static const char *questStatusLabels[] = {
|
||||||
"None",
|
"None",
|
||||||
"Name",
|
"Name",
|
||||||
"Finished",
|
"Finished",
|
||||||
"Restart",
|
"Restart",
|
||||||
"Deleted"
|
"Deleted"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 4)
|
|
||||||
return questStatusLabels[idx];
|
return questStatusLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string creatureTypeLabel(int idx)
|
std::string creatureTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *creatureTypeLabels[] = {
|
if (idx >= 0 && idx <= 3)
|
||||||
|
{
|
||||||
|
static const char *creatureTypeLabels[] = {
|
||||||
"Creature",
|
"Creature",
|
||||||
"Daedra",
|
"Daedra",
|
||||||
"Undead",
|
"Undead",
|
||||||
"Humanoid",
|
"Humanoid",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 3)
|
|
||||||
return creatureTypeLabels[idx];
|
return creatureTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string soundTypeLabel(int idx)
|
std::string soundTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *soundTypeLabels[] = {
|
if (idx >= 0 && idx <= 7)
|
||||||
|
{
|
||||||
|
static const char *soundTypeLabels[] = {
|
||||||
"Left Foot",
|
"Left Foot",
|
||||||
"Right Foot",
|
"Right Foot",
|
||||||
"Swim Left",
|
"Swim Left",
|
||||||
|
@ -198,16 +207,17 @@ std::string soundTypeLabel(int idx)
|
||||||
"Scream",
|
"Scream",
|
||||||
"Land"
|
"Land"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 7)
|
|
||||||
return soundTypeLabels[idx];
|
return soundTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string weaponTypeLabel(int idx)
|
std::string weaponTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
const char *weaponTypeLabels[] = {
|
if (idx >= 0 && idx <= 13)
|
||||||
|
{
|
||||||
|
static const char *weaponTypeLabels[] = {
|
||||||
"Short Blade One Hand",
|
"Short Blade One Hand",
|
||||||
"Long Blade One Hand",
|
"Long Blade One Hand",
|
||||||
"Long Blade Two Hand",
|
"Long Blade Two Hand",
|
||||||
|
@ -223,9 +233,8 @@ std::string weaponTypeLabel(int idx)
|
||||||
"Arrow",
|
"Arrow",
|
||||||
"Bolt"
|
"Bolt"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx <= 13)
|
|
||||||
return weaponTypeLabels[idx];
|
return weaponTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
@ -241,6 +250,8 @@ std::string aiTypeLabel(int type)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string magicEffectLabel(int idx)
|
std::string magicEffectLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 142)
|
||||||
{
|
{
|
||||||
const char* magicEffectLabels [] = {
|
const char* magicEffectLabels [] = {
|
||||||
"Water Breathing",
|
"Water Breathing",
|
||||||
|
@ -387,13 +398,15 @@ std::string magicEffectLabel(int idx)
|
||||||
"sEffectSummonCreature04",
|
"sEffectSummonCreature04",
|
||||||
"sEffectSummonCreature05"
|
"sEffectSummonCreature05"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 142)
|
|
||||||
return magicEffectLabels[idx];
|
return magicEffectLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string attributeLabel(int idx)
|
std::string attributeLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 7)
|
||||||
{
|
{
|
||||||
const char* attributeLabels [] = {
|
const char* attributeLabels [] = {
|
||||||
"Strength",
|
"Strength",
|
||||||
|
@ -405,13 +418,15 @@ std::string attributeLabel(int idx)
|
||||||
"Personality",
|
"Personality",
|
||||||
"Luck"
|
"Luck"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 7)
|
|
||||||
return attributeLabels[idx];
|
return attributeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string spellTypeLabel(int idx)
|
std::string spellTypeLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 5)
|
||||||
{
|
{
|
||||||
const char* spellTypeLabels [] = {
|
const char* spellTypeLabels [] = {
|
||||||
"Spells",
|
"Spells",
|
||||||
|
@ -421,26 +436,30 @@ std::string spellTypeLabel(int idx)
|
||||||
"Curse",
|
"Curse",
|
||||||
"Powers"
|
"Powers"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 5)
|
|
||||||
return spellTypeLabels[idx];
|
return spellTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string specializationLabel(int idx)
|
std::string specializationLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 2)
|
||||||
{
|
{
|
||||||
const char* specializationLabels [] = {
|
const char* specializationLabels [] = {
|
||||||
"Combat",
|
"Combat",
|
||||||
"Magic",
|
"Magic",
|
||||||
"Stealth"
|
"Stealth"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 2)
|
|
||||||
return specializationLabels[idx];
|
return specializationLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string skillLabel(int idx)
|
std::string skillLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 26)
|
||||||
{
|
{
|
||||||
const char* skillLabels [] = {
|
const char* skillLabels [] = {
|
||||||
"Block",
|
"Block",
|
||||||
|
@ -471,13 +490,15 @@ std::string skillLabel(int idx)
|
||||||
"Speechcraft",
|
"Speechcraft",
|
||||||
"Hand-to-hand"
|
"Hand-to-hand"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 26)
|
|
||||||
return skillLabels[idx];
|
return skillLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string apparatusTypeLabel(int idx)
|
std::string apparatusTypeLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 3)
|
||||||
{
|
{
|
||||||
const char* apparatusTypeLabels [] = {
|
const char* apparatusTypeLabels [] = {
|
||||||
"Mortar",
|
"Mortar",
|
||||||
|
@ -485,26 +506,30 @@ std::string apparatusTypeLabel(int idx)
|
||||||
"Calcinator",
|
"Calcinator",
|
||||||
"Retort",
|
"Retort",
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 3)
|
|
||||||
return apparatusTypeLabels[idx];
|
return apparatusTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rangeTypeLabel(int idx)
|
std::string rangeTypeLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 2)
|
||||||
{
|
{
|
||||||
const char* rangeTypeLabels [] = {
|
const char* rangeTypeLabels [] = {
|
||||||
"Self",
|
"Self",
|
||||||
"Touch",
|
"Touch",
|
||||||
"Target"
|
"Target"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 2)
|
|
||||||
return rangeTypeLabels[idx];
|
return rangeTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string schoolLabel(int idx)
|
std::string schoolLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 5)
|
||||||
{
|
{
|
||||||
const char* schoolLabels [] = {
|
const char* schoolLabels [] = {
|
||||||
"Alteration",
|
"Alteration",
|
||||||
|
@ -514,13 +539,15 @@ std::string schoolLabel(int idx)
|
||||||
"Mysticism",
|
"Mysticism",
|
||||||
"Restoration"
|
"Restoration"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 5)
|
|
||||||
return schoolLabels[idx];
|
return schoolLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string enchantTypeLabel(int idx)
|
std::string enchantTypeLabel(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 3)
|
||||||
{
|
{
|
||||||
const char* enchantTypeLabels [] = {
|
const char* enchantTypeLabels [] = {
|
||||||
"Cast Once",
|
"Cast Once",
|
||||||
|
@ -528,13 +555,15 @@ std::string enchantTypeLabel(int idx)
|
||||||
"Cast When Used",
|
"Cast When Used",
|
||||||
"Constant Effect"
|
"Constant Effect"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 3)
|
|
||||||
return enchantTypeLabels[idx];
|
return enchantTypeLabels[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ruleFunction(int idx)
|
std::string ruleFunction(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx <= 72)
|
||||||
{
|
{
|
||||||
std::string ruleFunctions[] = {
|
std::string ruleFunctions[] = {
|
||||||
"Reaction Low",
|
"Reaction Low",
|
||||||
|
@ -611,8 +640,8 @@ std::string ruleFunction(int idx)
|
||||||
"Should Attack",
|
"Should Attack",
|
||||||
"Werewolf"
|
"Werewolf"
|
||||||
};
|
};
|
||||||
if (idx >= 0 && idx <= 72)
|
|
||||||
return ruleFunctions[idx];
|
return ruleFunctions[idx];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
@ -787,6 +816,10 @@ std::string magicEffectFlags(int flags)
|
||||||
if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
|
if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
|
||||||
if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
|
if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
|
||||||
if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
|
if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
|
||||||
|
if (flags & ESM::MagicEffect::AllowSpellmaking) properties += "AllowSpellmaking ";
|
||||||
|
if (flags & ESM::MagicEffect::AllowEnchanting) properties += "AllowEnchanting ";
|
||||||
|
if (flags & ESM::MagicEffect::NegativeLight) properties += "NegativeLight ";
|
||||||
|
|
||||||
if (flags & 0xFFFC0000) properties += "Invalid ";
|
if (flags & 0xFFFC0000) properties += "Invalid ";
|
||||||
properties += str(boost::format("(0x%08X)") % flags);
|
properties += str(boost::format("(0x%08X)") % flags);
|
||||||
return properties;
|
return properties;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "labels.hpp"
|
#include "labels.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
void printAIPackage(ESM::AIPackage p)
|
void printAIPackage(ESM::AIPackage p)
|
||||||
|
@ -25,7 +27,7 @@ void printAIPackage(ESM::AIPackage p)
|
||||||
{
|
{
|
||||||
std::cout << " Travel Coordinates: (" << p.mTravel.mX << ","
|
std::cout << " Travel Coordinates: (" << p.mTravel.mX << ","
|
||||||
<< p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl;
|
<< p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl;
|
||||||
std::cout << " Travel Unknown: " << (int)p.mTravel.mUnk << std::endl;
|
std::cout << " Travel Unknown: " << p.mTravel.mUnk << std::endl;
|
||||||
}
|
}
|
||||||
else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort)
|
else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort)
|
||||||
{
|
{
|
||||||
|
@ -33,12 +35,12 @@ void printAIPackage(ESM::AIPackage p)
|
||||||
<< p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl;
|
<< p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl;
|
||||||
std::cout << " Duration: " << p.mTarget.mDuration << std::endl;
|
std::cout << " Duration: " << p.mTarget.mDuration << std::endl;
|
||||||
std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl;
|
std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl;
|
||||||
std::cout << " Unknown: " << (int)p.mTarget.mUnk << std::endl;
|
std::cout << " Unknown: " << p.mTarget.mUnk << std::endl;
|
||||||
}
|
}
|
||||||
else if (p.mType == ESM::AI_Activate)
|
else if (p.mType == ESM::AI_Activate)
|
||||||
{
|
{
|
||||||
std::cout << " Name: " << p.mActivate.mName.toString() << std::endl;
|
std::cout << " Name: " << p.mActivate.mName.toString() << std::endl;
|
||||||
std::cout << " Activate Unknown: " << (int)p.mActivate.mUnk << std::endl;
|
std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl;
|
std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl;
|
||||||
|
@ -89,6 +91,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
|
||||||
case 'A': if (indicator == 'R') type_str = "Not Race"; break;
|
case 'A': if (indicator == 'R') type_str = "Not Race"; break;
|
||||||
case 'B': if (indicator == 'L') type_str = "Not Cell"; break;
|
case 'B': if (indicator == 'L') type_str = "Not Cell"; break;
|
||||||
case 'C': if (indicator == 's') type_str = "Not Local"; break;
|
case 'C': if (indicator == 's') type_str = "Not Local"; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the variable name to the function string if any.
|
// Append the variable name to the function string if any.
|
||||||
|
@ -110,6 +113,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
|
||||||
case '3': oper_str = ">="; break;
|
case '3': oper_str = ">="; break;
|
||||||
case '4': oper_str = "< "; break;
|
case '4': oper_str = "< "; break;
|
||||||
case '5': oper_str = "<="; break;
|
case '5': oper_str = "<="; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
@ -412,7 +416,7 @@ void Record<ESM::Armor>::print()
|
||||||
std::cout << " Armor: " << mData.mData.mArmor << std::endl;
|
std::cout << " Armor: " << mData.mData.mArmor << std::endl;
|
||||||
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
|
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
|
||||||
std::vector<ESM::PartReference>::iterator pit;
|
std::vector<ESM::PartReference>::iterator pit;
|
||||||
for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); pit++)
|
for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); ++pit)
|
||||||
{
|
{
|
||||||
std::cout << " Body Part: " << bodyPartLabel(pit->mPart)
|
std::cout << " Body Part: " << bodyPartLabel(pit->mPart)
|
||||||
<< " (" << (int)(pit->mPart) << ")" << std::endl;
|
<< " (" << (int)(pit->mPart) << ")" << std::endl;
|
||||||
|
@ -430,7 +434,7 @@ void Record<ESM::Apparatus>::print()
|
||||||
std::cout << " Icon: " << mData.mIcon << std::endl;
|
std::cout << " Icon: " << mData.mIcon << std::endl;
|
||||||
std::cout << " Script: " << mData.mScript << std::endl;
|
std::cout << " Script: " << mData.mScript << std::endl;
|
||||||
std::cout << " Type: " << apparatusTypeLabel(mData.mData.mType)
|
std::cout << " Type: " << apparatusTypeLabel(mData.mData.mType)
|
||||||
<< " (" << (int)mData.mData.mType << ")" << std::endl;
|
<< " (" << mData.mData.mType << ")" << std::endl;
|
||||||
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
|
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
|
||||||
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
||||||
std::cout << " Quality: " << mData.mData.mQuality << std::endl;
|
std::cout << " Quality: " << mData.mData.mQuality << std::endl;
|
||||||
|
@ -484,7 +488,7 @@ void Record<ESM::BirthSign>::print()
|
||||||
std::cout << " Texture: " << mData.mTexture << std::endl;
|
std::cout << " Texture: " << mData.mTexture << std::endl;
|
||||||
std::cout << " Description: " << mData.mDescription << std::endl;
|
std::cout << " Description: " << mData.mDescription << std::endl;
|
||||||
std::vector<std::string>::iterator pit;
|
std::vector<std::string>::iterator pit;
|
||||||
for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); pit++)
|
for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit)
|
||||||
std::cout << " Power: " << *pit << std::endl;
|
std::cout << " Power: " << *pit << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,7 +517,7 @@ void Record<ESM::Cell>::print()
|
||||||
else
|
else
|
||||||
std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl;
|
std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl;
|
||||||
std::cout << " Water Level Int: " << mData.mWaterInt << std::endl;
|
std::cout << " Water Level Int: " << mData.mWaterInt << std::endl;
|
||||||
std::cout << " RefId counter: " << mData.mRefIdCounter << std::endl;
|
std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,10 +535,10 @@ void Record<ESM::Class>::print()
|
||||||
std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization)
|
std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization)
|
||||||
<< " (" << mData.mData.mSpecialization << ")" << std::endl;
|
<< " (" << mData.mData.mSpecialization << ")" << std::endl;
|
||||||
for (int i = 0; i != 5; i++)
|
for (int i = 0; i != 5; i++)
|
||||||
std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0])
|
std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0])
|
||||||
<< " (" << mData.mData.mSkills[i][0] << ")" << std::endl;
|
<< " (" << mData.mData.mSkills[i][0] << ")" << std::endl;
|
||||||
for (int i = 0; i != 5; i++)
|
for (int i = 0; i != 5; i++)
|
||||||
std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1])
|
std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1])
|
||||||
<< " (" << mData.mData.mSkills[i][1] << ")" << std::endl;
|
<< " (" << mData.mData.mSkills[i][1] << ")" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +558,7 @@ void Record<ESM::Clothing>::print()
|
||||||
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
||||||
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
|
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
|
||||||
std::vector<ESM::PartReference>::iterator pit;
|
std::vector<ESM::PartReference>::iterator pit;
|
||||||
for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); pit++)
|
for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); ++pit)
|
||||||
{
|
{
|
||||||
std::cout << " Body Part: " << bodyPartLabel(pit->mPart)
|
std::cout << " Body Part: " << bodyPartLabel(pit->mPart)
|
||||||
<< " (" << (int)(pit->mPart) << ")" << std::endl;
|
<< " (" << (int)(pit->mPart) << ")" << std::endl;
|
||||||
|
@ -574,7 +578,7 @@ void Record<ESM::Container>::print()
|
||||||
std::cout << " Flags: " << containerFlags(mData.mFlags) << std::endl;
|
std::cout << " Flags: " << containerFlags(mData.mFlags) << std::endl;
|
||||||
std::cout << " Weight: " << mData.mWeight << std::endl;
|
std::cout << " Weight: " << mData.mWeight << std::endl;
|
||||||
std::vector<ESM::ContItem>::iterator cit;
|
std::vector<ESM::ContItem>::iterator cit;
|
||||||
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++)
|
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit)
|
||||||
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
|
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
|
||||||
<< " Item: " << cit->mItem.toString() << std::endl;
|
<< " Item: " << cit->mItem.toString() << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -619,12 +623,12 @@ void Record<ESM::Creature>::print()
|
||||||
std::cout << " Gold: " << mData.mData.mGold << std::endl;
|
std::cout << " Gold: " << mData.mData.mGold << std::endl;
|
||||||
|
|
||||||
std::vector<ESM::ContItem>::iterator cit;
|
std::vector<ESM::ContItem>::iterator cit;
|
||||||
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++)
|
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit)
|
||||||
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
|
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
|
||||||
<< " Item: " << cit->mItem.toString() << std::endl;
|
<< " Item: " << cit->mItem.toString() << std::endl;
|
||||||
|
|
||||||
std::vector<std::string>::iterator sit;
|
std::vector<std::string>::iterator sit;
|
||||||
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); sit++)
|
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit)
|
||||||
std::cout << " Spell: " << *sit << std::endl;
|
std::cout << " Spell: " << *sit << std::endl;
|
||||||
|
|
||||||
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl;
|
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl;
|
||||||
|
@ -639,7 +643,7 @@ void Record<ESM::Creature>::print()
|
||||||
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
|
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
|
||||||
|
|
||||||
std::vector<ESM::AIPackage>::iterator pit;
|
std::vector<ESM::AIPackage>::iterator pit;
|
||||||
for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); pit++)
|
for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit)
|
||||||
printAIPackage(*pit);
|
printAIPackage(*pit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,7 +710,7 @@ void Record<ESM::Faction>::print()
|
||||||
<< mData.mData.mRankData[i].mFactReaction << std::endl;
|
<< mData.mData.mRankData[i].mFactReaction << std::endl;
|
||||||
}
|
}
|
||||||
std::map<std::string, int>::iterator rit;
|
std::map<std::string, int>::iterator rit;
|
||||||
for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); rit++)
|
for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit)
|
||||||
std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl;
|
std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,7 +754,7 @@ void Record<ESM::DialInfo>::print()
|
||||||
if (mData.mCell != "")
|
if (mData.mCell != "")
|
||||||
std::cout << " Cell: " << mData.mCell << std::endl;
|
std::cout << " Cell: " << mData.mCell << std::endl;
|
||||||
if (mData.mData.mDisposition > 0)
|
if (mData.mData.mDisposition > 0)
|
||||||
std::cout << " Disposition: " << mData.mData.mDisposition << std::endl;
|
std::cout << " Disposition/Journal index: " << mData.mData.mDisposition << std::endl;
|
||||||
if (mData.mData.mGender != ESM::DialInfo::NA)
|
if (mData.mData.mGender != ESM::DialInfo::NA)
|
||||||
std::cout << " Gender: " << mData.mData.mGender << std::endl;
|
std::cout << " Gender: " << mData.mData.mGender << std::endl;
|
||||||
if (mData.mSound != "")
|
if (mData.mSound != "")
|
||||||
|
@ -763,7 +767,7 @@ void Record<ESM::DialInfo>::print()
|
||||||
std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl;
|
std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl;
|
||||||
|
|
||||||
std::vector<ESM::DialInfo::SelectStruct>::iterator sit;
|
std::vector<ESM::DialInfo::SelectStruct>::iterator sit;
|
||||||
for (sit = mData.mSelects.begin(); sit != mData.mSelects.end(); sit++)
|
for (sit = mData.mSelects.begin(); sit != mData.mSelects.end(); ++sit)
|
||||||
std::cout << " Select Rule: " << ruleString(*sit) << std::endl;
|
std::cout << " Select Rule: " << ruleString(*sit) << std::endl;
|
||||||
|
|
||||||
if (mData.mResultScript != "")
|
if (mData.mResultScript != "")
|
||||||
|
@ -810,13 +814,12 @@ void Record<ESM::Land>::print()
|
||||||
{
|
{
|
||||||
std::cout << " Coordinates: (" << mData.mX << "," << mData.mY << ")" << std::endl;
|
std::cout << " Coordinates: (" << mData.mX << "," << mData.mY << ")" << std::endl;
|
||||||
std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl;
|
std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl;
|
||||||
std::cout << " HasData: " << mData.mHasData << std::endl;
|
|
||||||
std::cout << " DataTypes: " << mData.mDataTypes << std::endl;
|
std::cout << " DataTypes: " << mData.mDataTypes << std::endl;
|
||||||
|
|
||||||
// Seems like this should done with reference counting in the
|
// Seems like this should done with reference counting in the
|
||||||
// loader to me. But I'm not really knowledgable about this
|
// loader to me. But I'm not really knowledgable about this
|
||||||
// record type yet. --Cory
|
// record type yet. --Cory
|
||||||
bool wasLoaded = mData.mDataLoaded;
|
bool wasLoaded = (mData.mDataLoaded != 0);
|
||||||
if (mData.mDataTypes) mData.loadData(mData.mDataTypes);
|
if (mData.mDataTypes) mData.loadData(mData.mDataTypes);
|
||||||
if (mData.mDataLoaded)
|
if (mData.mDataLoaded)
|
||||||
{
|
{
|
||||||
|
@ -834,8 +837,8 @@ void Record<ESM::CreatureLevList>::print()
|
||||||
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
|
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
|
||||||
std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
|
std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
|
||||||
std::cout << " Number of items: " << mData.mList.size() << std::endl;
|
std::cout << " Number of items: " << mData.mList.size() << std::endl;
|
||||||
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
|
std::vector<ESM::LevelledListBase::LevelItem>::iterator iit;
|
||||||
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
|
for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit)
|
||||||
std::cout << " Creature: Level: " << iit->mLevel
|
std::cout << " Creature: Level: " << iit->mLevel
|
||||||
<< " Creature: " << iit->mId << std::endl;
|
<< " Creature: " << iit->mId << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -846,8 +849,8 @@ void Record<ESM::ItemLevList>::print()
|
||||||
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
|
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
|
||||||
std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
|
std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
|
||||||
std::cout << " Number of items: " << mData.mList.size() << std::endl;
|
std::cout << " Number of items: " << mData.mList.size() << std::endl;
|
||||||
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
|
std::vector<ESM::LevelledListBase::LevelItem>::iterator iit;
|
||||||
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
|
for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit)
|
||||||
std::cout << " Inventory: Level: " << iit->mLevel
|
std::cout << " Inventory: Level: " << iit->mLevel
|
||||||
<< " Item: " << iit->mId << std::endl;
|
<< " Item: " << iit->mId << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -950,9 +953,9 @@ void Record<ESM::MagicEffect>::print()
|
||||||
std::cout << " School: " << schoolLabel(mData.mData.mSchool)
|
std::cout << " School: " << schoolLabel(mData.mData.mSchool)
|
||||||
<< " (" << mData.mData.mSchool << ")" << std::endl;
|
<< " (" << mData.mData.mSchool << ")" << std::endl;
|
||||||
std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl;
|
std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl;
|
||||||
|
std::cout << " Unknown 1: " << mData.mData.mUnknown1 << std::endl;
|
||||||
std::cout << " Speed: " << mData.mData.mSpeed << std::endl;
|
std::cout << " Speed: " << mData.mData.mSpeed << std::endl;
|
||||||
std::cout << " Size: " << mData.mData.mSize << std::endl;
|
std::cout << " Unknown 2: " << mData.mData.mUnknown2 << std::endl;
|
||||||
std::cout << " Size Cap: " << mData.mData.mSizeCap << std::endl;
|
|
||||||
std::cout << " RGB Color: " << "("
|
std::cout << " RGB Color: " << "("
|
||||||
<< mData.mData.mRed << ","
|
<< mData.mData.mRed << ","
|
||||||
<< mData.mData.mGreen << ","
|
<< mData.mData.mGreen << ","
|
||||||
|
@ -992,7 +995,6 @@ void Record<ESM::NPC>::print()
|
||||||
std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl;
|
std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl;
|
||||||
std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl;
|
std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl;
|
||||||
std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl;
|
std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl;
|
||||||
std::cout << " Faction: " << (int)mData.mNpdt52.mFactionID << std::endl;
|
|
||||||
std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl;
|
std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl;
|
||||||
std::cout << " Unknown1: "
|
std::cout << " Unknown1: "
|
||||||
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl;
|
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl;
|
||||||
|
@ -1000,13 +1002,14 @@ void Record<ESM::NPC>::print()
|
||||||
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl;
|
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl;
|
||||||
std::cout << " Unknown3: "
|
std::cout << " Unknown3: "
|
||||||
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl;
|
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl;
|
||||||
std::cout << " Gold: " << (int)mData.mNpdt12.mGold << std::endl;
|
std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl;
|
std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl;
|
||||||
std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl;
|
std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl;
|
||||||
std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl;
|
std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl;
|
||||||
std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl;
|
std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl;
|
||||||
|
std::cout << " FactionID: " << (int)mData.mNpdt52.mFactionID << std::endl;
|
||||||
|
|
||||||
std::cout << " Attributes:" << std::endl;
|
std::cout << " Attributes:" << std::endl;
|
||||||
std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl;
|
std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl;
|
||||||
|
@ -1021,7 +1024,7 @@ void Record<ESM::NPC>::print()
|
||||||
std::cout << " Skills:" << std::endl;
|
std::cout << " Skills:" << std::endl;
|
||||||
for (int i = 0; i != ESM::Skill::Length; i++)
|
for (int i = 0; i != ESM::Skill::Length; i++)
|
||||||
std::cout << " " << skillLabel(i) << ": "
|
std::cout << " " << skillLabel(i) << ": "
|
||||||
<< (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl;
|
<< (int)(mData.mNpdt52.mSkills[i]) << std::endl;
|
||||||
|
|
||||||
std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl;
|
std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl;
|
||||||
std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl;
|
std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl;
|
||||||
|
@ -1031,16 +1034,16 @@ void Record<ESM::NPC>::print()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::ContItem>::iterator cit;
|
std::vector<ESM::ContItem>::iterator cit;
|
||||||
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++)
|
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit)
|
||||||
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
|
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
|
||||||
<< " Item: " << cit->mItem.toString() << std::endl;
|
<< " Item: " << cit->mItem.toString() << std::endl;
|
||||||
|
|
||||||
std::vector<std::string>::iterator sit;
|
std::vector<std::string>::iterator sit;
|
||||||
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); sit++)
|
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit)
|
||||||
std::cout << " Spell: " << *sit << std::endl;
|
std::cout << " Spell: " << *sit << std::endl;
|
||||||
|
|
||||||
std::vector<ESM::NPC::Dest>::iterator dit;
|
std::vector<ESM::NPC::Dest>::iterator dit;
|
||||||
for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); dit++)
|
for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); ++dit)
|
||||||
{
|
{
|
||||||
std::cout << " Destination Position: "
|
std::cout << " Destination Position: "
|
||||||
<< boost::format("%12.3f") % dit->mPos.pos[0] << ","
|
<< boost::format("%12.3f") % dit->mPos.pos[0] << ","
|
||||||
|
@ -1066,7 +1069,7 @@ void Record<ESM::NPC>::print()
|
||||||
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
|
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
|
||||||
|
|
||||||
std::vector<ESM::AIPackage>::iterator pit;
|
std::vector<ESM::AIPackage>::iterator pit;
|
||||||
for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); pit++)
|
for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit)
|
||||||
printAIPackage(*pit);
|
printAIPackage(*pit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,9 +1126,9 @@ void Record<ESM::Race>::print()
|
||||||
|
|
||||||
std::cout << (male ? " Male:" : " Female:") << std::endl;
|
std::cout << (male ? " Male:" : " Female:") << std::endl;
|
||||||
|
|
||||||
for (int i=0; i<8; ++i)
|
for (int j=0; j<8; ++j)
|
||||||
std::cout << " " << sAttributeNames[i] << ": "
|
std::cout << " " << sAttributeNames[j] << ": "
|
||||||
<< mData.mData.mAttributeValues[i].getValue (male) << std::endl;
|
<< mData.mData.mAttributeValues[j].getValue (male) << std::endl;
|
||||||
|
|
||||||
std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl;
|
std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl;
|
||||||
std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl;
|
std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl;
|
||||||
|
@ -1140,7 +1143,7 @@ void Record<ESM::Race>::print()
|
||||||
<< mData.mData.mBonus[i].mBonus << std::endl;
|
<< mData.mData.mBonus[i].mBonus << std::endl;
|
||||||
|
|
||||||
std::vector<std::string>::iterator sit;
|
std::vector<std::string>::iterator sit;
|
||||||
for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); sit++)
|
for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit)
|
||||||
std::cout << " Power: " << *sit << std::endl;
|
std::cout << " Power: " << *sit << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,7 +1167,7 @@ void Record<ESM::Region>::print()
|
||||||
if (mData.mSleepList != "")
|
if (mData.mSleepList != "")
|
||||||
std::cout << " Sleep List: " << mData.mSleepList << std::endl;
|
std::cout << " Sleep List: " << mData.mSleepList << std::endl;
|
||||||
std::vector<ESM::Region::SoundRef>::iterator sit;
|
std::vector<ESM::Region::SoundRef>::iterator sit;
|
||||||
for (sit = mData.mSoundList.begin(); sit != mData.mSoundList.end(); sit++)
|
for (sit = mData.mSoundList.begin(); sit != mData.mSoundList.end(); ++sit)
|
||||||
std::cout << " Sound: " << (int)sit->mChance << " = " << sit->mSound.toString() << std::endl;
|
std::cout << " Sound: " << (int)sit->mChance << " = " << sit->mSound.toString() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,12 +1184,12 @@ void Record<ESM::Script>::print()
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string>::iterator vit;
|
std::vector<std::string>::iterator vit;
|
||||||
for (vit = mData.mVarNames.begin(); vit != mData.mVarNames.end(); vit++)
|
for (vit = mData.mVarNames.begin(); vit != mData.mVarNames.end(); ++vit)
|
||||||
std::cout << " Variable: " << *vit << std::endl;
|
std::cout << " Variable: " << *vit << std::endl;
|
||||||
|
|
||||||
std::cout << " ByteCode: ";
|
std::cout << " ByteCode: ";
|
||||||
std::vector<unsigned char>::iterator cit;
|
std::vector<unsigned char>::iterator cit;
|
||||||
for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); cit++)
|
for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); ++cit)
|
||||||
std::cout << boost::format("%02X") % (int)(*cit);
|
std::cout << boost::format("%02X") % (int)(*cit);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
@ -1250,7 +1253,7 @@ void Record<ESM::Spell>::print()
|
||||||
template<>
|
template<>
|
||||||
void Record<ESM::StartScript>::print()
|
void Record<ESM::StartScript>::print()
|
||||||
{
|
{
|
||||||
std::cout << "Start Script: " << mData.mScript << std::endl;
|
std::cout << "Start Script: " << mData.mId << std::endl;
|
||||||
std::cout << "Start Data: " << mData.mData << std::endl;
|
std::cout << "Start Data: " << mData.mData << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace EsmTool
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::string mId;
|
std::string mId;
|
||||||
int mFlags;
|
uint32_t mFlags;
|
||||||
ESM::NAME mType;
|
ESM::NAME mType;
|
||||||
bool mPrintPlain;
|
bool mPrintPlain;
|
||||||
|
|
||||||
|
@ -40,11 +40,11 @@ namespace EsmTool
|
||||||
mId = id;
|
mId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFlags() const {
|
uint32_t getFlags() const {
|
||||||
return mFlags;
|
return mFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFlags(int flags) {
|
void setFlags(uint32_t flags) {
|
||||||
mFlags = flags;
|
mFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,10 +52,6 @@ namespace EsmTool
|
||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getPrintPlain() const {
|
|
||||||
return mPrintPlain;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPrintPlain(bool plain) {
|
void setPrintPlain(bool plain) {
|
||||||
mPrintPlain = plain;
|
mPrintPlain = plain;
|
||||||
}
|
}
|
||||||
|
|
43
apps/essimporter/CMakeLists.txt
Normal file
43
apps/essimporter/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
set(ESSIMPORTER_FILES
|
||||||
|
main.cpp
|
||||||
|
importer.cpp
|
||||||
|
importplayer.cpp
|
||||||
|
importnpcc.cpp
|
||||||
|
importcrec.cpp
|
||||||
|
importcellref.cpp
|
||||||
|
importacdt.cpp
|
||||||
|
importinventory.cpp
|
||||||
|
importklst.cpp
|
||||||
|
importcntc.cpp
|
||||||
|
importgame.cpp
|
||||||
|
importinfo.cpp
|
||||||
|
importdial.cpp
|
||||||
|
importques.cpp
|
||||||
|
importjour.cpp
|
||||||
|
importscri.cpp
|
||||||
|
importscpt.cpp
|
||||||
|
importercontext.cpp
|
||||||
|
converter.cpp
|
||||||
|
convertacdt.cpp
|
||||||
|
convertnpcc.cpp
|
||||||
|
convertinventory.cpp
|
||||||
|
convertcrec.cpp
|
||||||
|
convertcntc.cpp
|
||||||
|
convertscri.cpp
|
||||||
|
convertscpt.cpp
|
||||||
|
convertplayer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(openmw-essimporter
|
||||||
|
${ESSIMPORTER_FILES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(openmw-essimporter
|
||||||
|
${Boost_LIBRARIES}
|
||||||
|
components
|
||||||
|
)
|
||||||
|
|
||||||
|
if (BUILD_WITH_CODE_COVERAGE)
|
||||||
|
add_definitions (--coverage)
|
||||||
|
target_link_libraries(openmw-essimporter gcov)
|
||||||
|
endif()
|
52
apps/essimporter/convertacdt.cpp
Normal file
52
apps/essimporter/convertacdt.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include "convertacdt.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
int translateDynamicIndex(int mwIndex)
|
||||||
|
{
|
||||||
|
if (mwIndex == 1)
|
||||||
|
return 2;
|
||||||
|
else if (mwIndex == 2)
|
||||||
|
return 1;
|
||||||
|
return mwIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats)
|
||||||
|
{
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
|
int writeIndex = translateDynamicIndex(i);
|
||||||
|
cStats.mDynamic[writeIndex].mBase = acdt.mDynamic[i][1];
|
||||||
|
cStats.mDynamic[writeIndex].mMod = acdt.mDynamic[i][1];
|
||||||
|
cStats.mDynamic[writeIndex].mCurrent = acdt.mDynamic[i][0];
|
||||||
|
}
|
||||||
|
for (int i=0; i<8; ++i)
|
||||||
|
{
|
||||||
|
cStats.mAttributes[i].mBase = acdt.mAttributes[i][1];
|
||||||
|
cStats.mAttributes[i].mMod = acdt.mAttributes[i][0];
|
||||||
|
cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0];
|
||||||
|
}
|
||||||
|
cStats.mGoldPool = acdt.mGoldPool;
|
||||||
|
cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer;
|
||||||
|
cStats.mAttacked = acdt.mFlags & Attacked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats)
|
||||||
|
{
|
||||||
|
cStats.mDead = acsc.mFlags & Dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats)
|
||||||
|
{
|
||||||
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
|
{
|
||||||
|
npcStats.mSkills[i].mRegular.mMod = actorData.mSkills[i][1];
|
||||||
|
npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1];
|
||||||
|
npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
apps/essimporter/convertacdt.hpp
Normal file
23
apps/essimporter/convertacdt.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTACDT_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTACDT_H
|
||||||
|
|
||||||
|
#include <components/esm/creaturestats.hpp>
|
||||||
|
#include <components/esm/npcstats.hpp>
|
||||||
|
#include <components/esm/loadskil.hpp>
|
||||||
|
|
||||||
|
#include "importacdt.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
// OpenMW uses Health,Magicka,Fatigue, MW uses Health,Fatigue,Magicka
|
||||||
|
int translateDynamicIndex(int mwIndex);
|
||||||
|
|
||||||
|
|
||||||
|
void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats);
|
||||||
|
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats);
|
||||||
|
|
||||||
|
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
13
apps/essimporter/convertcntc.cpp
Normal file
13
apps/essimporter/convertcntc.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "convertcntc.hpp"
|
||||||
|
|
||||||
|
#include "convertinventory.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertCNTC(const CNTC &cntc, ESM::ContainerState &state)
|
||||||
|
{
|
||||||
|
convertInventory(cntc.mInventory, state.mInventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
apps/essimporter/convertcntc.hpp
Normal file
15
apps/essimporter/convertcntc.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTCNTC_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTCNTC_H
|
||||||
|
|
||||||
|
#include "importcntc.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/containerstate.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertCNTC(const CNTC& cntc, ESM::ContainerState& state);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
13
apps/essimporter/convertcrec.cpp
Normal file
13
apps/essimporter/convertcrec.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "convertcrec.hpp"
|
||||||
|
|
||||||
|
#include "convertinventory.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertCREC(const CREC &crec, ESM::CreatureState &state)
|
||||||
|
{
|
||||||
|
convertInventory(crec.mInventory, state.mInventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
apps/essimporter/convertcrec.hpp
Normal file
15
apps/essimporter/convertcrec.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTCREC_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTCREC_H
|
||||||
|
|
||||||
|
#include "importcrec.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/creaturestate.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertCREC(const CREC& crec, ESM::CreatureState& state);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
389
apps/essimporter/converter.cpp
Normal file
389
apps/essimporter/converter.cpp
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
#include "converter.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <OgreImage.h>
|
||||||
|
#include <OgreColourValue.h>
|
||||||
|
|
||||||
|
#include <components/esm/creaturestate.hpp>
|
||||||
|
#include <components/esm/containerstate.hpp>
|
||||||
|
|
||||||
|
#include "convertcrec.hpp"
|
||||||
|
#include "convertcntc.hpp"
|
||||||
|
#include "convertscri.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out)
|
||||||
|
{
|
||||||
|
Ogre::Image screenshot;
|
||||||
|
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size));
|
||||||
|
screenshot.loadRawData(stream, width, height, 1, pf);
|
||||||
|
screenshot.save(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void convertCellRef(const ESSImport::CellRef& cellref, ESM::ObjectState& objstate)
|
||||||
|
{
|
||||||
|
objstate.mEnabled = cellref.mEnabled;
|
||||||
|
objstate.mPosition = cellref.mPos;
|
||||||
|
objstate.mRef.mRefNum = cellref.mRefNum;
|
||||||
|
if (cellref.mDeleted)
|
||||||
|
objstate.mCount = 0;
|
||||||
|
convertSCRI(cellref.mSCRI, objstate.mLocals);
|
||||||
|
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIndexedRefId(const std::string& indexedRefId)
|
||||||
|
{
|
||||||
|
if (indexedRefId.size() <= 8)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (indexedRefId.find_first_not_of("0123456789") == std::string::npos)
|
||||||
|
return false; // entirely numeric refid, this is a reference to
|
||||||
|
// a dynamically created record e.g. player-enchanted weapon
|
||||||
|
|
||||||
|
std::string index = indexedRefId.substr(indexedRefId.size()-8);
|
||||||
|
if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
struct MAPH
|
||||||
|
{
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConvertFMAP::read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
MAPH maph;
|
||||||
|
esm.getHNT(maph, "MAPH");
|
||||||
|
std::vector<char> data;
|
||||||
|
esm.getSubNameIs("MAPD");
|
||||||
|
esm.getSubHeader();
|
||||||
|
data.resize(esm.getSubSize());
|
||||||
|
esm.getExact(&data[0], data.size());
|
||||||
|
|
||||||
|
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(&data[0], data.size()));
|
||||||
|
mGlobalMapImage.loadRawData(stream, maph.size, maph.size, 1, Ogre::PF_BYTE_RGB);
|
||||||
|
// to match openmw size
|
||||||
|
mGlobalMapImage.resize(maph.size*2, maph.size*2, Ogre::Image::FILTER_BILINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertFMAP::write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
int numcells = mGlobalMapImage.getWidth() / 18; // NB truncating, doesn't divide perfectly
|
||||||
|
// with the 512x512 map the game has by default
|
||||||
|
int cellSize = mGlobalMapImage.getWidth()/numcells;
|
||||||
|
|
||||||
|
// Note the upper left corner of the (0,0) cell should be at (width/2, height/2)
|
||||||
|
|
||||||
|
mContext->mGlobalMapState.mBounds.mMinX = -numcells/2;
|
||||||
|
mContext->mGlobalMapState.mBounds.mMaxX = (numcells-1)/2;
|
||||||
|
mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2;
|
||||||
|
mContext->mGlobalMapState.mBounds.mMaxY = numcells/2;
|
||||||
|
|
||||||
|
Ogre::Image image2;
|
||||||
|
std::vector<Ogre::uint8> data;
|
||||||
|
int width = cellSize*numcells;
|
||||||
|
int height = cellSize*numcells;
|
||||||
|
data.resize(width*height*4, 0);
|
||||||
|
image2.loadDynamicImage(&data[0], width, height, Ogre::PF_BYTE_RGBA);
|
||||||
|
|
||||||
|
for (std::set<std::pair<int, int> >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->first > mContext->mGlobalMapState.mBounds.mMaxX
|
||||||
|
|| it->first < mContext->mGlobalMapState.mBounds.mMinX
|
||||||
|
|| it->second > mContext->mGlobalMapState.mBounds.mMaxY
|
||||||
|
|| it->second < mContext->mGlobalMapState.mBounds.mMinY)
|
||||||
|
{
|
||||||
|
// out of bounds, I think this could happen, since the original engine had a fixed-size map
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int imageLeftSrc = mGlobalMapImage.getWidth()/2;
|
||||||
|
int imageTopSrc = mGlobalMapImage.getHeight()/2;
|
||||||
|
imageLeftSrc += it->first * cellSize;
|
||||||
|
imageTopSrc -= it->second * cellSize;
|
||||||
|
int imageLeftDst = width/2;
|
||||||
|
int imageTopDst = height/2;
|
||||||
|
imageLeftDst += it->first * cellSize;
|
||||||
|
imageTopDst -= it->second * cellSize;
|
||||||
|
for (int x=0; x<cellSize; ++x)
|
||||||
|
for (int y=0; y<cellSize; ++y)
|
||||||
|
image2.setColourAt(mGlobalMapImage.getColourAt(imageLeftSrc+x, imageTopSrc+y, 0)
|
||||||
|
, imageLeftDst+x, imageTopDst+y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::DataStreamPtr encoded = image2.encode("png");
|
||||||
|
mContext->mGlobalMapState.mImageData.resize(encoded->size());
|
||||||
|
encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size());
|
||||||
|
|
||||||
|
esm.startRecord(ESM::REC_GMAP);
|
||||||
|
mContext->mGlobalMapState.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_GMAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertCell::read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
ESM::Cell cell;
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
cell.mName = id;
|
||||||
|
cell.load(esm, false);
|
||||||
|
|
||||||
|
// I wonder what 0x40 does?
|
||||||
|
if (cell.isExterior() && cell.mData.mFlags & 0x20)
|
||||||
|
{
|
||||||
|
mContext->mGlobalMapState.mMarkers.insert(std::make_pair(cell.mData.mX, cell.mData.mY));
|
||||||
|
}
|
||||||
|
|
||||||
|
// note if the player is in a nameless exterior cell, we will assign the cellId later based on player position
|
||||||
|
if (id == mContext->mPlayerCellName)
|
||||||
|
{
|
||||||
|
mContext->mPlayer.mCellId = cell.getCellId();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell newcell;
|
||||||
|
newcell.mCell = cell;
|
||||||
|
|
||||||
|
// fog of war
|
||||||
|
// seems to be a 1-bit pixel format, 16*16 pixels
|
||||||
|
// TODO: add bleeding of FOW into neighbouring cells (openmw handles this by writing to the textures,
|
||||||
|
// MW handles it when rendering only)
|
||||||
|
unsigned char nam8[32];
|
||||||
|
// exterior has 1 NAM8, interior can have multiple ones, and have an extra 4 byte flag at the start
|
||||||
|
// (probably offset of that specific fog texture?)
|
||||||
|
while (esm.isNextSub("NAM8"))
|
||||||
|
{
|
||||||
|
if (cell.isExterior()) // TODO: NAM8 occasionally exists for cells that haven't been explored.
|
||||||
|
// are there any flags marking explored cells?
|
||||||
|
mContext->mExploredCells.insert(std::make_pair(cell.mData.mX, cell.mData.mY));
|
||||||
|
|
||||||
|
esm.getSubHeader();
|
||||||
|
|
||||||
|
if (esm.getSubSize() == 36)
|
||||||
|
{
|
||||||
|
// flag on interiors
|
||||||
|
esm.skip(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
esm.getExact(nam8, 32);
|
||||||
|
|
||||||
|
newcell.mFogOfWar.reserve(16*16);
|
||||||
|
for (int x=0; x<16; ++x)
|
||||||
|
{
|
||||||
|
for (int y=0; y<16; ++y)
|
||||||
|
{
|
||||||
|
size_t pos = x*16+y;
|
||||||
|
size_t bytepos = pos/8;
|
||||||
|
assert(bytepos<32);
|
||||||
|
int bit = pos%8;
|
||||||
|
newcell.mFogOfWar.push_back(((nam8[bytepos] >> bit) & (0x1)) ? 0xffffffff : 0x000000ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell.isExterior())
|
||||||
|
{
|
||||||
|
std::ostringstream filename;
|
||||||
|
filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga";
|
||||||
|
|
||||||
|
convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// moved reference, not handled yet
|
||||||
|
// NOTE: MVRF can also occur in within normal references (importcellref.cpp)?
|
||||||
|
// this does not match the ESM file implementation,
|
||||||
|
// verify if that can happen with ESM files too
|
||||||
|
while (esm.isNextSub("MVRF"))
|
||||||
|
{
|
||||||
|
esm.skipHSub(); // skip MVRF
|
||||||
|
esm.getSubName();
|
||||||
|
esm.skipHSub(); // skip CNDT
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CellRef> cellrefs;
|
||||||
|
while (esm.hasMoreSubs() && esm.isNextSub("FRMR"))
|
||||||
|
{
|
||||||
|
CellRef ref;
|
||||||
|
ref.load (esm);
|
||||||
|
cellrefs.push_back(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (esm.isNextSub("MPCD"))
|
||||||
|
{
|
||||||
|
float notepos[3];
|
||||||
|
esm.getHT(notepos, 3*sizeof(float));
|
||||||
|
|
||||||
|
// Markers seem to be arranged in a 32*32 grid, notepos has grid-indices.
|
||||||
|
// This seems to be the reason markers can't be placed everywhere in interior cells,
|
||||||
|
// i.e. when the grid is exceeded.
|
||||||
|
// Converting the interior markers correctly could be rather tricky, but is probably similar logic
|
||||||
|
// as used for the FoW texture placement, which we need to figure out anyway
|
||||||
|
notepos[1] += 31.f;
|
||||||
|
notepos[0] += 0.5;
|
||||||
|
notepos[1] += 0.5;
|
||||||
|
notepos[0] = 8192 * notepos[0] / 32.f;
|
||||||
|
notepos[1] = 8192 * notepos[1] / 32.f;
|
||||||
|
if (cell.isExterior())
|
||||||
|
{
|
||||||
|
notepos[0] += 8192 * cell.mData.mX;
|
||||||
|
notepos[1] += 8192 * cell.mData.mY;
|
||||||
|
}
|
||||||
|
// TODO: what encoding is this in?
|
||||||
|
std::string note = esm.getHNString("MPNT");
|
||||||
|
ESM::CustomMarker marker;
|
||||||
|
marker.mWorldX = notepos[0];
|
||||||
|
marker.mWorldY = notepos[1];
|
||||||
|
marker.mNote = note;
|
||||||
|
marker.mCell = cell.getCellId();
|
||||||
|
mMarkers.push_back(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
newcell.mRefs = cellrefs;
|
||||||
|
|
||||||
|
|
||||||
|
if (cell.isExterior())
|
||||||
|
mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell;
|
||||||
|
else
|
||||||
|
mIntCells[id] = newcell;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
ESM::Cell esmcell = cell.mCell;
|
||||||
|
esm.startRecord(ESM::REC_CSTA);
|
||||||
|
ESM::CellState csta;
|
||||||
|
csta.mHasFogOfWar = 0;
|
||||||
|
csta.mId = esmcell.getCellId();
|
||||||
|
csta.mId.save(esm);
|
||||||
|
// TODO csta.mLastRespawn;
|
||||||
|
// shouldn't be needed if we respawn on global schedule like in original MW
|
||||||
|
csta.mWaterLevel = esmcell.mWater;
|
||||||
|
csta.save(esm);
|
||||||
|
|
||||||
|
for (std::vector<CellRef>::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt)
|
||||||
|
{
|
||||||
|
const CellRef& cellref = *refIt;
|
||||||
|
ESM::CellRef out (cellref);
|
||||||
|
|
||||||
|
// TODO: use mContext->mCreatures/mNpcs
|
||||||
|
|
||||||
|
if (!isIndexedRefId(cellref.mIndexedRefId))
|
||||||
|
{
|
||||||
|
// non-indexed RefNum, i.e. no CREC/NPCC/CNTC record associated with it
|
||||||
|
// this could be any type of object really (even creatures/npcs too)
|
||||||
|
out.mRefID = cellref.mIndexedRefId;
|
||||||
|
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||||
|
|
||||||
|
ESM::ObjectState objstate;
|
||||||
|
objstate.blank();
|
||||||
|
objstate.mRef = out;
|
||||||
|
objstate.mRef.mRefID = idLower;
|
||||||
|
objstate.mHasCustomState = false;
|
||||||
|
convertCellRef(cellref, objstate);
|
||||||
|
esm.writeHNT ("OBJE", 0);
|
||||||
|
objstate.save(esm);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8);
|
||||||
|
int refIndex;
|
||||||
|
stream >> refIndex;
|
||||||
|
|
||||||
|
out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8);
|
||||||
|
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||||
|
|
||||||
|
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
|
||||||
|
std::make_pair(refIndex, out.mRefID));
|
||||||
|
if (npccIt != mContext->mNpcChanges.end())
|
||||||
|
{
|
||||||
|
ESM::NpcState objstate;
|
||||||
|
objstate.blank();
|
||||||
|
objstate.mRef = out;
|
||||||
|
objstate.mRef.mRefID = idLower;
|
||||||
|
// TODO: need more micromanagement here so we don't overwrite values
|
||||||
|
// from the ESM with default values
|
||||||
|
if (cellref.mHasACDT)
|
||||||
|
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||||
|
if (cellref.mHasACSC)
|
||||||
|
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||||
|
convertNpcData(cellref, objstate.mNpcStats);
|
||||||
|
convertNPCC(npccIt->second, objstate);
|
||||||
|
convertCellRef(cellref, objstate);
|
||||||
|
esm.writeHNT ("OBJE", ESM::REC_NPC_);
|
||||||
|
objstate.save(esm);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::pair<int, std::string>, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find(
|
||||||
|
std::make_pair(refIndex, out.mRefID));
|
||||||
|
if (cntcIt != mContext->mContainerChanges.end())
|
||||||
|
{
|
||||||
|
ESM::ContainerState objstate;
|
||||||
|
objstate.blank();
|
||||||
|
objstate.mRef = out;
|
||||||
|
objstate.mRef.mRefID = idLower;
|
||||||
|
convertCNTC(cntcIt->second, objstate);
|
||||||
|
convertCellRef(cellref, objstate);
|
||||||
|
esm.writeHNT ("OBJE", ESM::REC_CONT);
|
||||||
|
objstate.save(esm);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::pair<int, std::string>, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find(
|
||||||
|
std::make_pair(refIndex, out.mRefID));
|
||||||
|
if (crecIt != mContext->mCreatureChanges.end())
|
||||||
|
{
|
||||||
|
ESM::CreatureState objstate;
|
||||||
|
objstate.blank();
|
||||||
|
objstate.mRef = out;
|
||||||
|
objstate.mRef.mRefID = idLower;
|
||||||
|
// TODO: need more micromanagement here so we don't overwrite values
|
||||||
|
// from the ESM with default values
|
||||||
|
if (cellref.mHasACDT)
|
||||||
|
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||||
|
if (cellref.mHasACSC)
|
||||||
|
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||||
|
convertCREC(crecIt->second, objstate);
|
||||||
|
convertCellRef(cellref, objstate);
|
||||||
|
esm.writeHNT ("OBJE", ESM::REC_CREA);
|
||||||
|
objstate.save(esm);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream error;
|
||||||
|
error << "Can't find type for " << cellref.mIndexedRefId << std::endl;
|
||||||
|
throw std::runtime_error(error.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esm.endRecord(ESM::REC_CSTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertCell::write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
for (std::map<std::string, Cell>::const_iterator it = mIntCells.begin(); it != mIntCells.end(); ++it)
|
||||||
|
writeCell(it->second, esm);
|
||||||
|
|
||||||
|
for (std::map<std::pair<int, int>, Cell>::const_iterator it = mExtCells.begin(); it != mExtCells.end(); ++it)
|
||||||
|
writeCell(it->second, esm);
|
||||||
|
|
||||||
|
for (std::vector<ESM::CustomMarker>::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.startRecord(ESM::REC_MARK);
|
||||||
|
it->save(esm);
|
||||||
|
esm.endRecord(ESM::REC_MARK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
597
apps/essimporter/converter.hpp
Normal file
597
apps/essimporter/converter.hpp
Normal file
|
@ -0,0 +1,597 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTER_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTER_H
|
||||||
|
|
||||||
|
#include <OgreImage.h>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
#include <components/esm/loadbook.hpp>
|
||||||
|
#include <components/esm/loadclas.hpp>
|
||||||
|
#include <components/esm/loadglob.hpp>
|
||||||
|
#include <components/esm/cellstate.hpp>
|
||||||
|
#include <components/esm/loadfact.hpp>
|
||||||
|
#include <components/esm/dialoguestate.hpp>
|
||||||
|
#include <components/esm/custommarkerstate.hpp>
|
||||||
|
#include <components/esm/loadcrea.hpp>
|
||||||
|
#include <components/esm/weatherstate.hpp>
|
||||||
|
#include <components/esm/globalscript.hpp>
|
||||||
|
#include <components/esm/queststate.hpp>
|
||||||
|
#include <components/esm/stolenitems.hpp>
|
||||||
|
|
||||||
|
#include "importcrec.hpp"
|
||||||
|
#include "importcntc.hpp"
|
||||||
|
|
||||||
|
#include "importercontext.hpp"
|
||||||
|
#include "importcellref.hpp"
|
||||||
|
#include "importklst.hpp"
|
||||||
|
#include "importgame.hpp"
|
||||||
|
#include "importinfo.hpp"
|
||||||
|
#include "importdial.hpp"
|
||||||
|
#include "importques.hpp"
|
||||||
|
#include "importjour.hpp"
|
||||||
|
#include "importscpt.hpp"
|
||||||
|
|
||||||
|
#include "convertacdt.hpp"
|
||||||
|
#include "convertnpcc.hpp"
|
||||||
|
#include "convertscpt.hpp"
|
||||||
|
#include "convertplayer.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
class Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// @return the order for writing this converter's records to the output file, in relation to other converters
|
||||||
|
virtual int getStage() { return 1; }
|
||||||
|
|
||||||
|
virtual ~Converter() {}
|
||||||
|
|
||||||
|
void setContext(Context& context) { mContext = &context; }
|
||||||
|
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called after the input file has been read in completely, which may be necessary
|
||||||
|
/// if the conversion process relies on information in other records
|
||||||
|
virtual void write(ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Context* mContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Default converter: simply reads the record and writes it unmodified to the output
|
||||||
|
template <typename T>
|
||||||
|
class DefaultConverter : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual int getStage() { return 0; }
|
||||||
|
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
T record;
|
||||||
|
record.load(esm);
|
||||||
|
mRecords[id] = record;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write(ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
for (typename std::map<std::string, T>::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.startRecord(T::sRecordId);
|
||||||
|
esm.writeHNString("NAME", it->first);
|
||||||
|
it->second.save(esm);
|
||||||
|
esm.endRecord(T::sRecordId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::map<std::string, T> mRecords;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertNPC : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
ESM::NPC npc;
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
npc.load(esm);
|
||||||
|
if (id != "player")
|
||||||
|
{
|
||||||
|
// Handles changes to the NPC struct, but since there is no index here
|
||||||
|
// it will apply to ALL instances of the class. seems to be the reason for the
|
||||||
|
// "feature" in MW where changing AI settings of one guard will change it for all guards of that refID.
|
||||||
|
mContext->mNpcs[Misc::StringUtils::lowerCase(id)] = npc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel;
|
||||||
|
mContext->mPlayerBase = npc;
|
||||||
|
std::map<const int, float> empty;
|
||||||
|
// FIXME: player start spells and birthsign spells aren't listed here,
|
||||||
|
// need to fix openmw to account for this
|
||||||
|
for (std::vector<std::string>::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it)
|
||||||
|
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty;
|
||||||
|
|
||||||
|
// Clear the list now that we've written it, this prevents issues cropping up with
|
||||||
|
// ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal.
|
||||||
|
mContext->mPlayerBase.mSpells.mList.clear();
|
||||||
|
|
||||||
|
// Same with inventory. Actually it's strange this would contain something, since there's already an
|
||||||
|
// inventory list in NPCC. There seems to be a fair amount of redundancy in this format.
|
||||||
|
mContext->mPlayerBase.mInventory.mList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertCREA : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
// See comment in ConvertNPC
|
||||||
|
ESM::Creature creature;
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
creature.load(esm);
|
||||||
|
mContext->mCreatures[Misc::StringUtils::lowerCase(id)] = creature;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do we need ConvertCONT?
|
||||||
|
// I've seen a CONT record in a certain save file, but the container contents in it
|
||||||
|
// were identical to a corresponding CNTC record. See previous comment about redundancy...
|
||||||
|
|
||||||
|
class ConvertGlobal : public DefaultConverter<ESM::Global>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
ESM::Global global;
|
||||||
|
global.load(esm);
|
||||||
|
if (Misc::StringUtils::ciEqual(id, "gamehour"))
|
||||||
|
mContext->mHour = global.mValue.getFloat();
|
||||||
|
if (Misc::StringUtils::ciEqual(id, "day"))
|
||||||
|
mContext->mDay = global.mValue.getInteger();
|
||||||
|
if (Misc::StringUtils::ciEqual(id, "month"))
|
||||||
|
mContext->mMonth = global.mValue.getInteger();
|
||||||
|
if (Misc::StringUtils::ciEqual(id, "year"))
|
||||||
|
mContext->mYear = global.mValue.getInteger();
|
||||||
|
mRecords[id] = global;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertClass : public DefaultConverter<ESM::Class>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
ESM::Class class_;
|
||||||
|
class_.load(esm);
|
||||||
|
|
||||||
|
if (id == "NEWCLASSID_CHARGEN")
|
||||||
|
mContext->mCustomPlayerClassName = class_.mName;
|
||||||
|
|
||||||
|
mRecords[id] = class_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertBook : public DefaultConverter<ESM::Book>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
ESM::Book book;
|
||||||
|
book.load(esm);
|
||||||
|
if (book.mData.mSkillID == -1)
|
||||||
|
mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(id));
|
||||||
|
|
||||||
|
mRecords[id] = book;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertNPCC : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
NPCC npcc;
|
||||||
|
npcc.load(esm);
|
||||||
|
if (id == "PlayerSaveGame")
|
||||||
|
{
|
||||||
|
convertNPCC(npcc, mContext->mPlayer.mObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int index = npcc.mNPDT.mIndex;
|
||||||
|
mContext->mNpcChanges.insert(std::make_pair(std::make_pair(index,id), npcc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertREFR : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
REFR refr;
|
||||||
|
refr.load(esm);
|
||||||
|
assert(refr.mRefID == "PlayerSaveGame");
|
||||||
|
mContext->mPlayer.mObject.mPosition = refr.mPos;
|
||||||
|
|
||||||
|
ESM::CreatureStats& cStats = mContext->mPlayer.mObject.mCreatureStats;
|
||||||
|
convertACDT(refr.mActorData.mACDT, cStats);
|
||||||
|
|
||||||
|
ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats;
|
||||||
|
convertNpcData(refr.mActorData, npcStats);
|
||||||
|
|
||||||
|
mSelectedSpell = refr.mActorData.mSelectedSpell;
|
||||||
|
if (!refr.mActorData.mSelectedEnchantItem.empty())
|
||||||
|
{
|
||||||
|
ESM::InventoryState& invState = mContext->mPlayer.mObject.mInventory;
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<invState.mItems.size(); ++i)
|
||||||
|
{
|
||||||
|
// FIXME: in case of conflict (multiple items with this refID) use the already equipped one?
|
||||||
|
if (Misc::StringUtils::ciEqual(invState.mItems[i].mRef.mRefID, refr.mActorData.mSelectedEnchantItem))
|
||||||
|
invState.mSelectedEnchantItem = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void write(ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
esm.startRecord(ESM::REC_ASPL);
|
||||||
|
esm.writeHNString("ID__", mSelectedSpell);
|
||||||
|
esm.endRecord(ESM::REC_ASPL);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string mSelectedSpell;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertPCDT : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConvertPCDT() : mFirstPersonCam(true) {}
|
||||||
|
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
PCDT pcdt;
|
||||||
|
pcdt.load(esm);
|
||||||
|
|
||||||
|
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam);
|
||||||
|
}
|
||||||
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
esm.startRecord(ESM::REC_CAM_);
|
||||||
|
esm.writeHNT("FIRS", mFirstPersonCam);
|
||||||
|
esm.endRecord(ESM::REC_CAM_);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool mFirstPersonCam;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertCNTC : public Converter
|
||||||
|
{
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
CNTC cntc;
|
||||||
|
cntc.load(esm);
|
||||||
|
mContext->mContainerChanges.insert(std::make_pair(std::make_pair(cntc.mIndex,id), cntc));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertCREC : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
CREC crec;
|
||||||
|
crec.load(esm);
|
||||||
|
mContext->mCreatureChanges.insert(std::make_pair(std::make_pair(crec.mIndex,id), crec));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertFMAP : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm);
|
||||||
|
virtual void write(ESM::ESMWriter &esm);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ogre::Image mGlobalMapImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertCell : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm);
|
||||||
|
virtual void write(ESM::ESMWriter& esm);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Cell
|
||||||
|
{
|
||||||
|
ESM::Cell mCell;
|
||||||
|
std::vector<CellRef> mRefs;
|
||||||
|
std::vector<unsigned int> mFogOfWar;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, Cell> mIntCells;
|
||||||
|
std::map<std::pair<int, int>, Cell> mExtCells;
|
||||||
|
|
||||||
|
std::vector<ESM::CustomMarker> mMarkers;
|
||||||
|
|
||||||
|
void writeCell(const Cell& cell, ESM::ESMWriter &esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertKLST : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
KLST klst;
|
||||||
|
klst.load(esm);
|
||||||
|
mKillCounter = klst.mKillCounter;
|
||||||
|
|
||||||
|
mContext->mPlayer.mObject.mNpcStats.mWerewolfKills = klst.mWerewolfKills;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
esm.startRecord(ESM::REC_DCOU);
|
||||||
|
for (std::map<std::string, int>::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.writeHNString("ID__", it->first);
|
||||||
|
esm.writeHNT ("COUN", it->second);
|
||||||
|
}
|
||||||
|
esm.endRecord(ESM::REC_DCOU);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, int> mKillCounter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertFACT : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
ESM::Faction faction;
|
||||||
|
faction.load(esm);
|
||||||
|
|
||||||
|
Misc::StringUtils::toLower(id);
|
||||||
|
for (std::map<std::string, int>::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it)
|
||||||
|
{
|
||||||
|
std::string faction2 = Misc::StringUtils::lowerCase(it->first);
|
||||||
|
mContext->mDialogueState.mChangedFactionReaction[id].insert(std::make_pair(faction2, it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Stolen items
|
||||||
|
class ConvertSTLN : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
std::string itemid = esm.getHNString("NAME");
|
||||||
|
Misc::StringUtils::toLower(itemid);
|
||||||
|
|
||||||
|
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
|
||||||
|
{
|
||||||
|
if (esm.retSubName().toString() == "FNAM")
|
||||||
|
{
|
||||||
|
std::string factionid = esm.getHString();
|
||||||
|
mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string ownerid = esm.getHString();
|
||||||
|
mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
ESM::StolenItems items;
|
||||||
|
for (std::map<std::string, std::set<Owner> >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
|
||||||
|
{
|
||||||
|
std::map<std::pair<std::string, bool>, int> owners;
|
||||||
|
for (std::set<Owner>::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt)
|
||||||
|
{
|
||||||
|
owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second)
|
||||||
|
// Since OpenMW doesn't suffer from the owner contamination bug,
|
||||||
|
// it needs a count argument. But for legacy savegames, we don't know
|
||||||
|
// this count, so must assume all items of that ID are stolen,
|
||||||
|
// like vanilla MW did.
|
||||||
|
,std::numeric_limits<int>::max()));
|
||||||
|
}
|
||||||
|
|
||||||
|
items.mStolenItems.insert(std::make_pair(it->first, owners));
|
||||||
|
}
|
||||||
|
|
||||||
|
esm.startRecord(ESM::REC_STLN);
|
||||||
|
items.write(esm);
|
||||||
|
esm.endRecord(ESM::REC_STLN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::pair<std::string, bool> Owner; // <owner id, bool isFaction>
|
||||||
|
|
||||||
|
std::map<std::string, std::set<Owner> > mStolenItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Seen responses for a dialogue topic?
|
||||||
|
/// Each DIAL record is followed by a number of INFO records, I believe, just like in ESMs
|
||||||
|
/// Dialogue conversion problems:
|
||||||
|
/// - Journal is stored in one continuous HTML markup rather than each entry separately with associated info ID.
|
||||||
|
/// - Seen dialogue responses only store the INFO id, rather than the fulltext.
|
||||||
|
/// - Quest stages only store the INFO id, rather than the journal entry fulltext.
|
||||||
|
class ConvertINFO : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
INFO info;
|
||||||
|
info.load(esm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertDIAL : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
DIAL dial;
|
||||||
|
dial.load(esm);
|
||||||
|
if (dial.mIndex > 0)
|
||||||
|
mDials[id] = dial;
|
||||||
|
}
|
||||||
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
for (std::map<std::string, DIAL>::const_iterator it = mDials.begin(); it != mDials.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.startRecord(ESM::REC_QUES);
|
||||||
|
ESM::QuestState state;
|
||||||
|
state.mFinished = 0;
|
||||||
|
state.mState = it->second.mIndex;
|
||||||
|
state.mTopic = Misc::StringUtils::lowerCase(it->first);
|
||||||
|
state.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_QUES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::map<std::string, DIAL> mDials;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertQUES : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
std::string id = esm.getHNString("NAME");
|
||||||
|
QUES quest;
|
||||||
|
quest.load(esm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertJOUR : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
JOUR journal;
|
||||||
|
journal.load(esm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertGAME : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConvertGAME() : mHasGame(false) {}
|
||||||
|
|
||||||
|
std::string toString(int weatherId)
|
||||||
|
{
|
||||||
|
switch (weatherId)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "clear";
|
||||||
|
case 1:
|
||||||
|
return "cloudy";
|
||||||
|
case 2:
|
||||||
|
return "foggy";
|
||||||
|
case 3:
|
||||||
|
return "overcast";
|
||||||
|
case 4:
|
||||||
|
return "rain";
|
||||||
|
case 5:
|
||||||
|
return "thunderstorm";
|
||||||
|
case 6:
|
||||||
|
return "ashstorm";
|
||||||
|
case 7:
|
||||||
|
return "blight";
|
||||||
|
case 8:
|
||||||
|
return "snow";
|
||||||
|
case 9:
|
||||||
|
return "blizzard";
|
||||||
|
case -1:
|
||||||
|
return "";
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
std::stringstream error;
|
||||||
|
error << "unknown weather id: " << weatherId;
|
||||||
|
throw std::runtime_error(error.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
mGame.load(esm);
|
||||||
|
mHasGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
if (!mHasGame)
|
||||||
|
return;
|
||||||
|
esm.startRecord(ESM::REC_WTHR);
|
||||||
|
ESM::WeatherState weather;
|
||||||
|
weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather);
|
||||||
|
weather.mNextWeather = toString(mGame.mGMDT.mNextWeather);
|
||||||
|
weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600);
|
||||||
|
weather.mHour = mContext->mHour;
|
||||||
|
weather.mWindSpeed = 0.f;
|
||||||
|
weather.mTimePassed = 0.0;
|
||||||
|
weather.mFirstUpdate = false;
|
||||||
|
weather.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_WTHR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mHasGame;
|
||||||
|
GAME mGame;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Running global script
|
||||||
|
class ConvertSCPT : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
SCPT script;
|
||||||
|
script.load(esm);
|
||||||
|
ESM::GlobalScript out;
|
||||||
|
convertSCPT(script, out);
|
||||||
|
mScripts.push_back(out);
|
||||||
|
}
|
||||||
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::GlobalScript>::const_iterator it = mScripts.begin(); it != mScripts.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.startRecord(ESM::REC_GSCR);
|
||||||
|
it->save(esm);
|
||||||
|
esm.endRecord(ESM::REC_GSCR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector<ESM::GlobalScript> mScripts;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
30
apps/essimporter/convertinventory.cpp
Normal file
30
apps/essimporter/convertinventory.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include "convertinventory.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
for (std::vector<Inventory::InventoryItem>::const_iterator it = inventory.mItems.begin();
|
||||||
|
it != inventory.mItems.end(); ++it)
|
||||||
|
{
|
||||||
|
ESM::ObjectState objstate;
|
||||||
|
objstate.blank();
|
||||||
|
objstate.mRef = *it;
|
||||||
|
objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId);
|
||||||
|
objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile
|
||||||
|
// openmw handles them differently, so no need to set any flags
|
||||||
|
state.mItems.push_back(objstate);
|
||||||
|
if (it->mRelativeEquipmentSlot != -1)
|
||||||
|
// Note we should really write the absolute slot here, which we do not know about
|
||||||
|
// Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when
|
||||||
|
// an item could be equipped in two different slots (e.g. equipped two rings)
|
||||||
|
state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
apps/essimporter/convertinventory.hpp
Normal file
15
apps/essimporter/convertinventory.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTINVENTORY_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTINVENTORY_H
|
||||||
|
|
||||||
|
#include "importinventory.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/inventorystate.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertInventory (const Inventory& inventory, ESM::InventoryState& state);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
15
apps/essimporter/convertnpcc.cpp
Normal file
15
apps/essimporter/convertnpcc.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "convertnpcc.hpp"
|
||||||
|
|
||||||
|
#include "convertinventory.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState)
|
||||||
|
{
|
||||||
|
npcState.mNpcStats.mDisposition = npcc.mNPDT.mDisposition;
|
||||||
|
npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation;
|
||||||
|
|
||||||
|
convertInventory(npcc.mInventory, npcState.mInventory);
|
||||||
|
}
|
||||||
|
}
|
15
apps/essimporter/convertnpcc.hpp
Normal file
15
apps/essimporter/convertnpcc.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTNPCC_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTNPCC_H
|
||||||
|
|
||||||
|
#include "importnpcc.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/npcstate.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertNPCC (const NPCC& npcc, ESM::NpcState& npcState);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
38
apps/essimporter/convertplayer.cpp
Normal file
38
apps/essimporter/convertplayer.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "convertplayer.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam)
|
||||||
|
{
|
||||||
|
out.mBirthsign = pcdt.mBirthsign;
|
||||||
|
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
||||||
|
for (std::vector<PCDT::FNAM>::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it)
|
||||||
|
{
|
||||||
|
ESM::NpcStats::Faction faction;
|
||||||
|
faction.mExpelled = (it->mFlags & 0x2) != 0;
|
||||||
|
faction.mRank = it->mRank;
|
||||||
|
faction.mReputation = it->mReputation;
|
||||||
|
out.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(it->mFactionName.toString())] = faction;
|
||||||
|
}
|
||||||
|
for (int i=0; i<8; ++i)
|
||||||
|
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
|
||||||
|
for (int i=0; i<27; ++i)
|
||||||
|
out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i];
|
||||||
|
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
||||||
|
|
||||||
|
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)
|
||||||
|
out.mObject.mCreatureStats.mDrawState = 1;
|
||||||
|
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell)
|
||||||
|
out.mObject.mCreatureStats.mDrawState = 2;
|
||||||
|
|
||||||
|
firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson);
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
||||||
|
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
||||||
|
{
|
||||||
|
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
apps/essimporter/convertplayer.hpp
Normal file
15
apps/essimporter/convertplayer.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTPLAYER_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTPLAYER_H
|
||||||
|
|
||||||
|
#include "importplayer.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/player.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
17
apps/essimporter/convertscpt.cpp
Normal file
17
apps/essimporter/convertscpt.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include "convertscpt.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
#include "convertscri.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertSCPT(const SCPT &scpt, ESM::GlobalScript &out)
|
||||||
|
{
|
||||||
|
out.mId = Misc::StringUtils::lowerCase(scpt.mSCHD.mName.toString());
|
||||||
|
out.mRunning = scpt.mRunning;
|
||||||
|
convertSCRI(scpt.mSCRI, out.mLocals);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
apps/essimporter/convertscpt.hpp
Normal file
15
apps/essimporter/convertscpt.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTSCPT_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTSCPT_H
|
||||||
|
|
||||||
|
#include <components/esm/globalscript.hpp>
|
||||||
|
|
||||||
|
#include "importscpt.hpp"
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertSCPT(const SCPT& scpt, ESM::GlobalScript& out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
32
apps/essimporter/convertscri.cpp
Normal file
32
apps/essimporter/convertscri.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "convertscri.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T, ESM::VarType VariantType>
|
||||||
|
void storeVariables(const std::vector<T>& variables, ESM::Locals& locals, const std::string& scriptname)
|
||||||
|
{
|
||||||
|
for (typename std::vector<T>::const_iterator it = variables.begin(); it != variables.end(); ++it)
|
||||||
|
{
|
||||||
|
ESM::Variant val(*it);
|
||||||
|
val.setType(VariantType);
|
||||||
|
locals.mVariables.push_back(std::make_pair(std::string(), val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void convertSCRI(const SCRI &scri, ESM::Locals &locals)
|
||||||
|
{
|
||||||
|
// order *is* important, as we do not have variable names available in this format
|
||||||
|
storeVariables<short, ESM::VT_Short> (scri.mShorts, locals, scri.mScript);
|
||||||
|
storeVariables<int, ESM::VT_Int> (scri.mLongs, locals, scri.mScript);
|
||||||
|
storeVariables<float, ESM::VT_Float> (scri.mFloats, locals, scri.mScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
apps/essimporter/convertscri.hpp
Normal file
16
apps/essimporter/convertscri.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTSCRI_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTSCRI_H
|
||||||
|
|
||||||
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/locals.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Convert script variable assignments
|
||||||
|
void convertSCRI (const SCRI& scri, ESM::Locals& locals);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
115
apps/essimporter/importacdt.cpp
Normal file
115
apps/essimporter/importacdt.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#include "importacdt.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void ActorData::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
if (esm.isNextSub("ACTN"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
if (esm.isNextSub("STPR"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
if (esm.isNextSub("MNAM"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
ESM::CellRef::loadData(esm);
|
||||||
|
|
||||||
|
mHasACDT = false;
|
||||||
|
if (esm.isNextSub("ACDT"))
|
||||||
|
{
|
||||||
|
mHasACDT = true;
|
||||||
|
esm.getHT(mACDT);
|
||||||
|
}
|
||||||
|
|
||||||
|
mHasACSC = false;
|
||||||
|
if (esm.isNextSub("ACSC"))
|
||||||
|
{
|
||||||
|
mHasACSC = true;
|
||||||
|
esm.getHT(mACSC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esm.isNextSub("ACSL"))
|
||||||
|
esm.skipHSubSize(112);
|
||||||
|
|
||||||
|
if (esm.isNextSub("CSTN"))
|
||||||
|
esm.skipHSub(); // "PlayerSaveGame", link to some object?
|
||||||
|
|
||||||
|
if (esm.isNextSub("LSTN"))
|
||||||
|
esm.skipHSub(); // "PlayerSaveGame", link to some object?
|
||||||
|
|
||||||
|
// unsure at which point between LSTN and TGTN
|
||||||
|
if (esm.isNextSub("CSHN"))
|
||||||
|
esm.skipHSub(); // "PlayerSaveGame", link to some object?
|
||||||
|
|
||||||
|
// unsure if before or after CSTN/LSTN
|
||||||
|
if (esm.isNextSub("LSHN"))
|
||||||
|
esm.skipHSub(); // "PlayerSaveGame", link to some object?
|
||||||
|
|
||||||
|
while (esm.isNextSub("TGTN"))
|
||||||
|
esm.skipHSub(); // "PlayerSaveGame", link to some object?
|
||||||
|
|
||||||
|
while (esm.isNextSub("FGTN"))
|
||||||
|
esm.getHString(); // fight target?
|
||||||
|
|
||||||
|
// unsure at which point between TGTN and CRED
|
||||||
|
if (esm.isNextSub("AADT"))
|
||||||
|
{
|
||||||
|
// occured when a creature was in the middle of its attack, 44 bytes
|
||||||
|
esm.skipHSub();
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsure at which point between FGTN and CHRD
|
||||||
|
if (esm.isNextSub("PWPC"))
|
||||||
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("PWPS"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
if (esm.isNextSub("WNAM"))
|
||||||
|
{
|
||||||
|
std::string id = esm.getHString();
|
||||||
|
|
||||||
|
if (esm.isNextSub("XNAM"))
|
||||||
|
mSelectedEnchantItem = esm.getHString();
|
||||||
|
else
|
||||||
|
mSelectedSpell = id;
|
||||||
|
|
||||||
|
if (esm.isNextSub("YNAM"))
|
||||||
|
esm.skipHSub(); // 4 byte, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
while (esm.isNextSub("APUD"))
|
||||||
|
{
|
||||||
|
// used power
|
||||||
|
esm.getSubHeader();
|
||||||
|
std::string id = esm.getString(32);
|
||||||
|
(void)id;
|
||||||
|
// timestamp can't be used: this is the total hours passed, calculated by
|
||||||
|
// timestamp = 24 * (365 * year + cumulativeDays[month] + day)
|
||||||
|
// unfortunately cumulativeDays[month] is not clearly defined,
|
||||||
|
// in the (non-MCP) vanilla version the first month was missing, but MCP added it.
|
||||||
|
double timestamp;
|
||||||
|
esm.getT(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: not all actors have this, add flag
|
||||||
|
if (esm.isNextSub("CHRD")) // npc only
|
||||||
|
esm.getHExact(mSkills, 27*2*sizeof(int));
|
||||||
|
|
||||||
|
if (esm.isNextSub("CRED")) // creature only
|
||||||
|
esm.getHExact(mCombatStats, 3*2*sizeof(int));
|
||||||
|
|
||||||
|
mSCRI.load(esm);
|
||||||
|
|
||||||
|
if (esm.isNextSub("ND3D"))
|
||||||
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("ANIS"))
|
||||||
|
esm.skipHSub();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
85
apps/essimporter/importacdt.hpp
Normal file
85
apps/essimporter/importacdt.hpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_ACDT_H
|
||||||
|
#define OPENMW_ESSIMPORT_ACDT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
|
||||||
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ACDTFlags
|
||||||
|
{
|
||||||
|
TalkedToPlayer = 0x4,
|
||||||
|
Attacked = 0x100,
|
||||||
|
Unknown = 0x200
|
||||||
|
};
|
||||||
|
enum ACSCFlags
|
||||||
|
{
|
||||||
|
Dead = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Actor data, shared by (at least) REFR and CellRef
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct ACDT
|
||||||
|
{
|
||||||
|
// Note, not stored at *all*:
|
||||||
|
// - Level changes are lost on reload, except for the player (there it's in the NPC record).
|
||||||
|
unsigned char mUnknown[12];
|
||||||
|
unsigned int mFlags;
|
||||||
|
float mBreathMeter; // Seconds left before drowning
|
||||||
|
unsigned char mUnknown2[20];
|
||||||
|
float mDynamic[3][2];
|
||||||
|
unsigned char mUnknown3[16];
|
||||||
|
float mAttributes[8][2];
|
||||||
|
float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||||
|
unsigned char mUnknown4[4];
|
||||||
|
unsigned int mGoldPool;
|
||||||
|
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
||||||
|
// this one is for respawning?
|
||||||
|
unsigned char mUnknown5[3];
|
||||||
|
};
|
||||||
|
struct ACSC
|
||||||
|
{
|
||||||
|
unsigned char mUnknown1[17];
|
||||||
|
unsigned char mFlags; // ACSCFlags
|
||||||
|
unsigned char mUnknown2[22];
|
||||||
|
unsigned char mCorpseClearCountdown; // hours?
|
||||||
|
unsigned char mUnknown3[71];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct ActorData : public ESM::CellRef
|
||||||
|
{
|
||||||
|
bool mHasACDT;
|
||||||
|
ACDT mACDT;
|
||||||
|
|
||||||
|
bool mHasACSC;
|
||||||
|
ACSC mACSC;
|
||||||
|
|
||||||
|
int mSkills[27][2]; // skills, base and modified
|
||||||
|
|
||||||
|
// creature combat stats, base and modified
|
||||||
|
// I think these can be ignored in the conversion, because it is not possible
|
||||||
|
// to change them ingame
|
||||||
|
int mCombatStats[3][2];
|
||||||
|
|
||||||
|
std::string mSelectedSpell;
|
||||||
|
std::string mSelectedEnchantItem;
|
||||||
|
|
||||||
|
SCRI mSCRI;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
57
apps/essimporter/importcellref.cpp
Normal file
57
apps/essimporter/importcellref.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include "importcellref.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void CellRef::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
blank();
|
||||||
|
|
||||||
|
// (FRMR subrecord name is already read by the loop in ConvertCell)
|
||||||
|
esm.getHT(mRefNum.mIndex); // FRMR
|
||||||
|
|
||||||
|
// this is required since openmw supports more than 255 content files
|
||||||
|
int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24;
|
||||||
|
mRefNum.mContentFile = pluginIndex-1;
|
||||||
|
mRefNum.mIndex &= 0x00ffffff;
|
||||||
|
|
||||||
|
mIndexedRefId = esm.getHNString("NAME");
|
||||||
|
|
||||||
|
ActorData::load(esm);
|
||||||
|
if (esm.isNextSub("LVCR"))
|
||||||
|
{
|
||||||
|
// occurs on levelled creature spawner references
|
||||||
|
// probably some identifier for the creature that has been spawned?
|
||||||
|
unsigned char lvcr;
|
||||||
|
esm.getHT(lvcr);
|
||||||
|
//std::cout << "LVCR: " << (int)lvcr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEnabled = true;
|
||||||
|
esm.getHNOT(mEnabled, "ZNAM");
|
||||||
|
|
||||||
|
// DATA should occur for all references, except levelled creature spawners
|
||||||
|
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird
|
||||||
|
// alarmvoi0000.ess
|
||||||
|
esm.getHNOT(mPos, "DATA", 24);
|
||||||
|
esm.getHNOT(mPos, "DATA", 24);
|
||||||
|
|
||||||
|
mDeleted = 0;
|
||||||
|
if (esm.isNextSub("DELE"))
|
||||||
|
{
|
||||||
|
unsigned int deleted;
|
||||||
|
esm.getHT(deleted);
|
||||||
|
mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esm.isNextSub("MVRF"))
|
||||||
|
{
|
||||||
|
esm.skipHSub();
|
||||||
|
esm.getSubName();
|
||||||
|
esm.skipHSub();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
apps/essimporter/importcellref.hpp
Normal file
33
apps/essimporter/importcellref.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CELLREF_H
|
||||||
|
#define OPENMW_ESSIMPORT_CELLREF_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
|
||||||
|
#include "importacdt.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct CellRef : public ActorData
|
||||||
|
{
|
||||||
|
std::string mIndexedRefId;
|
||||||
|
|
||||||
|
std::string mScript;
|
||||||
|
|
||||||
|
bool mEnabled;
|
||||||
|
|
||||||
|
bool mDeleted;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
16
apps/essimporter/importcntc.cpp
Normal file
16
apps/essimporter/importcntc.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "importcntc.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void CNTC::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
mIndex = 0;
|
||||||
|
esm.getHNT(mIndex, "INDX");
|
||||||
|
|
||||||
|
mInventory.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
apps/essimporter/importcntc.hpp
Normal file
25
apps/essimporter/importcntc.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTCNTC_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTCNTC_H
|
||||||
|
|
||||||
|
#include "importinventory.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Changed container contents
|
||||||
|
struct CNTC
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
|
||||||
|
Inventory mInventory;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
25
apps/essimporter/importcrec.cpp
Normal file
25
apps/essimporter/importcrec.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "importcrec.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void CREC::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mIndex, "INDX");
|
||||||
|
|
||||||
|
// equivalent of ESM::Creature XSCL? probably don't have to convert this,
|
||||||
|
// since the value can't be changed
|
||||||
|
float scale;
|
||||||
|
esm.getHNOT(scale, "XSCL");
|
||||||
|
|
||||||
|
|
||||||
|
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||||
|
|| esm.isNextSub("AI_A"))
|
||||||
|
mAiPackages.add(esm);
|
||||||
|
|
||||||
|
mInventory.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
apps/essimporter/importcrec.hpp
Normal file
28
apps/essimporter/importcrec.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CREC_H
|
||||||
|
#define OPENMW_ESSIMPORT_CREC_H
|
||||||
|
|
||||||
|
#include "importinventory.hpp"
|
||||||
|
#include <components/esm/aipackage.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Creature changes
|
||||||
|
struct CREC
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
|
||||||
|
Inventory mInventory;
|
||||||
|
ESM::AIPackageList mAiPackages;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
23
apps/essimporter/importdial.cpp
Normal file
23
apps/essimporter/importdial.cpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#include "importdial.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void DIAL::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
// See ESM::Dialogue::Type enum, not sure why we would need this here though
|
||||||
|
int type = 0;
|
||||||
|
esm.getHNOT(type, "DATA");
|
||||||
|
|
||||||
|
// Deleted dialogue in a savefile. No clue what this means...
|
||||||
|
int deleted = 0;
|
||||||
|
esm.getHNOT(deleted, "DELE");
|
||||||
|
|
||||||
|
mIndex = 0;
|
||||||
|
// *should* always occur except when the dialogue is deleted, but leaving it optional just in case...
|
||||||
|
esm.getHNOT(mIndex, "XIDX");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
apps/essimporter/importdial.hpp
Normal file
20
apps/essimporter/importdial.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct DIAL
|
||||||
|
{
|
||||||
|
int mIndex; // Journal index
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
378
apps/essimporter/importer.cpp
Normal file
378
apps/essimporter/importer.cpp
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
#include "importer.hpp"
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include <OgreRoot.h>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
#include <components/esm/defs.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/savedgame.hpp>
|
||||||
|
#include <components/esm/player.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/loadalch.hpp>
|
||||||
|
#include <components/esm/loadclas.hpp>
|
||||||
|
#include <components/esm/loadspel.hpp>
|
||||||
|
#include <components/esm/loadarmo.hpp>
|
||||||
|
#include <components/esm/loadweap.hpp>
|
||||||
|
#include <components/esm/loadclot.hpp>
|
||||||
|
#include <components/esm/loadench.hpp>
|
||||||
|
#include <components/esm/loadweap.hpp>
|
||||||
|
#include <components/esm/loadlevlist.hpp>
|
||||||
|
#include <components/esm/loadglob.hpp>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
|
#include "importercontext.hpp"
|
||||||
|
|
||||||
|
#include "converter.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out)
|
||||||
|
{
|
||||||
|
Ogre::Image screenshot;
|
||||||
|
std::vector<unsigned char> screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :(
|
||||||
|
Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size()));
|
||||||
|
screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA);
|
||||||
|
Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
|
||||||
|
out.mScreenshot.resize(encoded->size());
|
||||||
|
encoded->read(&out.mScreenshot[0], encoded->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
Importer::Importer(const std::string &essfile, const std::string &outfile, const std::string &encoding)
|
||||||
|
: mEssFile(essfile)
|
||||||
|
, mOutFile(outfile)
|
||||||
|
, mEncoding(encoding)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct File
|
||||||
|
{
|
||||||
|
struct Subrecord
|
||||||
|
{
|
||||||
|
std::string mName;
|
||||||
|
size_t mFileOffset;
|
||||||
|
std::vector<unsigned char> mData;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Record
|
||||||
|
{
|
||||||
|
std::string mName;
|
||||||
|
size_t mFileOffset;
|
||||||
|
std::vector<Subrecord> mSubrecords;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Record> mRecords;
|
||||||
|
};
|
||||||
|
|
||||||
|
void read(const std::string& filename, File& file)
|
||||||
|
{
|
||||||
|
ESM::ESMReader esm;
|
||||||
|
esm.open(filename);
|
||||||
|
|
||||||
|
while (esm.hasMoreRecs())
|
||||||
|
{
|
||||||
|
ESM::NAME n = esm.getRecName();
|
||||||
|
esm.getRecHeader();
|
||||||
|
|
||||||
|
File::Record rec;
|
||||||
|
rec.mName = n.toString();
|
||||||
|
rec.mFileOffset = esm.getFileOffset();
|
||||||
|
while (esm.hasMoreSubs())
|
||||||
|
{
|
||||||
|
File::Subrecord sub;
|
||||||
|
esm.getSubName();
|
||||||
|
esm.getSubHeader();
|
||||||
|
sub.mFileOffset = esm.getFileOffset();
|
||||||
|
sub.mName = esm.retSubName().toString();
|
||||||
|
sub.mData.resize(esm.getSubSize());
|
||||||
|
esm.getExact(&sub.mData[0], sub.mData.size());
|
||||||
|
rec.mSubrecords.push_back(sub);
|
||||||
|
}
|
||||||
|
file.mRecords.push_back(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Importer::compare()
|
||||||
|
{
|
||||||
|
// data that always changes (and/or is already fully decoded) should be blacklisted
|
||||||
|
std::set<std::pair<std::string, std::string> > blacklist;
|
||||||
|
blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour
|
||||||
|
blacklist.insert(std::make_pair("REFR", "DATA")); // player position
|
||||||
|
blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war
|
||||||
|
blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes
|
||||||
|
blacklist.insert(std::make_pair("CELL", "DELE")); // first 3 bytes are uninitialized
|
||||||
|
|
||||||
|
// this changes way too often, name suggests some renderer internal data?
|
||||||
|
blacklist.insert(std::make_pair("CELL", "ND3D"));
|
||||||
|
blacklist.insert(std::make_pair("REFR", "ND3D"));
|
||||||
|
|
||||||
|
File file1;
|
||||||
|
read(mEssFile, file1);
|
||||||
|
File file2;
|
||||||
|
read(mOutFile, file2); // todo rename variable
|
||||||
|
|
||||||
|
// FIXME: use max(size1, size2)
|
||||||
|
for (unsigned int i=0; i<file1.mRecords.size(); ++i)
|
||||||
|
{
|
||||||
|
File::Record rec = file1.mRecords[i];
|
||||||
|
|
||||||
|
if (i >= file2.mRecords.size())
|
||||||
|
{
|
||||||
|
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::Record rec2 = file2.mRecords[i];
|
||||||
|
|
||||||
|
if (rec.mName != rec2.mName)
|
||||||
|
{
|
||||||
|
std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl;
|
||||||
|
return; // TODO: try to recover
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: use max(size1, size2)
|
||||||
|
for (unsigned int j=0; j<rec.mSubrecords.size(); ++j)
|
||||||
|
{
|
||||||
|
File::Subrecord sub = rec.mSubrecords[j];
|
||||||
|
|
||||||
|
if (j >= rec2.mSubrecords.size())
|
||||||
|
{
|
||||||
|
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::Subrecord sub2 = rec2.mSubrecords[j];
|
||||||
|
|
||||||
|
if (sub.mName != sub2.mName)
|
||||||
|
{
|
||||||
|
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset
|
||||||
|
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||||
|
break; // TODO: try to recover
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sub.mData != sub2.mData)
|
||||||
|
{
|
||||||
|
if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset
|
||||||
|
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Data 1:" << std::endl;
|
||||||
|
for (unsigned int k=0; k<sub.mData.size(); ++k)
|
||||||
|
{
|
||||||
|
bool different = false;
|
||||||
|
if (k >= sub2.mData.size() || sub2.mData[k] != sub.mData[k])
|
||||||
|
different = true;
|
||||||
|
|
||||||
|
if (different)
|
||||||
|
std::cout << "\033[033m";
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)sub.mData[k] << " ";
|
||||||
|
if (different)
|
||||||
|
std::cout << "\033[0m";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Data 2:" << std::endl;
|
||||||
|
for (unsigned int k=0; k<sub2.mData.size(); ++k)
|
||||||
|
{
|
||||||
|
bool different = false;
|
||||||
|
if (k >= sub.mData.size() || sub.mData[k] != sub2.mData[k])
|
||||||
|
different = true;
|
||||||
|
|
||||||
|
if (different)
|
||||||
|
std::cout << "\033[033m";
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)sub2.mData[k] << " ";
|
||||||
|
if (different)
|
||||||
|
std::cout << "\033[0m";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Importer::run()
|
||||||
|
{
|
||||||
|
// construct Ogre::Root to gain access to image codecs
|
||||||
|
Ogre::LogManager logman;
|
||||||
|
Ogre::Root root;
|
||||||
|
|
||||||
|
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding));
|
||||||
|
ESM::ESMReader esm;
|
||||||
|
esm.open(mEssFile);
|
||||||
|
esm.setEncoder(&encoder);
|
||||||
|
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
const ESM::Header& header = esm.getHeader();
|
||||||
|
context.mPlayerCellName = header.mGameData.mCurrentCell.toString();
|
||||||
|
|
||||||
|
const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value;
|
||||||
|
const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value;
|
||||||
|
const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value;
|
||||||
|
const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value;
|
||||||
|
const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value;
|
||||||
|
const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value;
|
||||||
|
const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value;
|
||||||
|
|
||||||
|
std::map<unsigned int, boost::shared_ptr<Converter> > converters;
|
||||||
|
converters[ESM::REC_GLOB] = boost::shared_ptr<Converter>(new ConvertGlobal());
|
||||||
|
converters[ESM::REC_BOOK] = boost::shared_ptr<Converter>(new ConvertBook());
|
||||||
|
converters[ESM::REC_NPC_] = boost::shared_ptr<Converter>(new ConvertNPC());
|
||||||
|
converters[ESM::REC_CREA] = boost::shared_ptr<Converter>(new ConvertCREA());
|
||||||
|
converters[ESM::REC_NPCC] = boost::shared_ptr<Converter>(new ConvertNPCC());
|
||||||
|
converters[ESM::REC_CREC] = boost::shared_ptr<Converter>(new ConvertCREC());
|
||||||
|
converters[recREFR ] = boost::shared_ptr<Converter>(new ConvertREFR());
|
||||||
|
converters[recPCDT ] = boost::shared_ptr<Converter>(new ConvertPCDT());
|
||||||
|
converters[recFMAP ] = boost::shared_ptr<Converter>(new ConvertFMAP());
|
||||||
|
converters[recKLST ] = boost::shared_ptr<Converter>(new ConvertKLST());
|
||||||
|
converters[recSTLN ] = boost::shared_ptr<Converter>(new ConvertSTLN());
|
||||||
|
converters[recGAME ] = boost::shared_ptr<Converter>(new ConvertGAME());
|
||||||
|
converters[ESM::REC_CELL] = boost::shared_ptr<Converter>(new ConvertCell());
|
||||||
|
converters[ESM::REC_ALCH] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Potion>());
|
||||||
|
converters[ESM::REC_CLAS] = boost::shared_ptr<Converter>(new ConvertClass());
|
||||||
|
converters[ESM::REC_SPEL] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Spell>());
|
||||||
|
converters[ESM::REC_ARMO] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Armor>());
|
||||||
|
converters[ESM::REC_WEAP] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Weapon>());
|
||||||
|
converters[ESM::REC_CLOT] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Clothing>());
|
||||||
|
converters[ESM::REC_ENCH] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Enchantment>());
|
||||||
|
converters[ESM::REC_WEAP] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Weapon>());
|
||||||
|
converters[ESM::REC_LEVC] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::CreatureLevList>());
|
||||||
|
converters[ESM::REC_LEVI] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::ItemLevList>());
|
||||||
|
converters[ESM::REC_CNTC] = boost::shared_ptr<Converter>(new ConvertCNTC());
|
||||||
|
converters[ESM::REC_FACT] = boost::shared_ptr<Converter>(new ConvertFACT());
|
||||||
|
converters[ESM::REC_INFO] = boost::shared_ptr<Converter>(new ConvertINFO());
|
||||||
|
converters[ESM::REC_DIAL] = boost::shared_ptr<Converter>(new ConvertDIAL());
|
||||||
|
converters[ESM::REC_QUES] = boost::shared_ptr<Converter>(new ConvertQUES());
|
||||||
|
converters[recJOUR ] = boost::shared_ptr<Converter>(new ConvertJOUR());
|
||||||
|
converters[ESM::REC_SCPT] = boost::shared_ptr<Converter>(new ConvertSCPT());
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - REGN (weather in certain regions?)
|
||||||
|
// - VFXM
|
||||||
|
// - SPLM (active spell effects)
|
||||||
|
// - PROJ (magic projectiles in air)
|
||||||
|
|
||||||
|
std::set<unsigned int> unknownRecords;
|
||||||
|
|
||||||
|
for (std::map<unsigned int, boost::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
||||||
|
it != converters.end(); ++it)
|
||||||
|
{
|
||||||
|
it->second->setContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (esm.hasMoreRecs())
|
||||||
|
{
|
||||||
|
ESM::NAME n = esm.getRecName();
|
||||||
|
esm.getRecHeader();
|
||||||
|
|
||||||
|
std::map<unsigned int, boost::shared_ptr<Converter> >::iterator it = converters.find(n.val);
|
||||||
|
if (it != converters.end())
|
||||||
|
{
|
||||||
|
it->second->read(esm);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unknownRecords.insert(n.val).second)
|
||||||
|
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
||||||
|
|
||||||
|
esm.skipRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::ESMWriter writer;
|
||||||
|
|
||||||
|
writer.setFormat (ESM::Header::CurrentFormat);
|
||||||
|
|
||||||
|
std::ofstream stream(mOutFile.c_str(), std::ios::binary);
|
||||||
|
// all unused
|
||||||
|
writer.setVersion(0);
|
||||||
|
writer.setType(0);
|
||||||
|
writer.setAuthor("");
|
||||||
|
writer.setDescription("");
|
||||||
|
writer.setRecordCount (0);
|
||||||
|
|
||||||
|
for (std::vector<ESM::Header::MasterData>::const_iterator it = header.mMaster.begin();
|
||||||
|
it != header.mMaster.end(); ++it)
|
||||||
|
writer.addMaster (it->name, 0); // not using the size information anyway -> use value of 0
|
||||||
|
|
||||||
|
writer.save (stream);
|
||||||
|
|
||||||
|
ESM::SavedGame profile;
|
||||||
|
for (std::vector<ESM::Header::MasterData>::const_iterator it = header.mMaster.begin();
|
||||||
|
it != header.mMaster.end(); ++it)
|
||||||
|
{
|
||||||
|
profile.mContentFiles.push_back(it->name);
|
||||||
|
}
|
||||||
|
profile.mDescription = esm.getDesc();
|
||||||
|
profile.mInGameTime.mDay = context.mDay;
|
||||||
|
profile.mInGameTime.mGameHour = context.mHour;
|
||||||
|
profile.mInGameTime.mMonth = context.mMonth;
|
||||||
|
profile.mInGameTime.mYear = context.mYear;
|
||||||
|
profile.mPlayerCell = header.mGameData.mCurrentCell.toString();
|
||||||
|
if (context.mPlayerBase.mClass == "NEWCLASSID_CHARGEN")
|
||||||
|
profile.mPlayerClassName = context.mCustomPlayerClassName;
|
||||||
|
else
|
||||||
|
profile.mPlayerClassId = context.mPlayerBase.mClass;
|
||||||
|
profile.mPlayerLevel = context.mPlayerBase.mNpdt52.mLevel;
|
||||||
|
profile.mPlayerName = header.mGameData.mPlayerName.toString();
|
||||||
|
|
||||||
|
writeScreenshot(header, profile);
|
||||||
|
|
||||||
|
writer.startRecord (ESM::REC_SAVE);
|
||||||
|
profile.save (writer);
|
||||||
|
writer.endRecord (ESM::REC_SAVE);
|
||||||
|
|
||||||
|
// Writing order should be Dynamic Store -> Cells -> Player,
|
||||||
|
// so that references to dynamic records can be recognized when loading
|
||||||
|
for (std::map<unsigned int, boost::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
||||||
|
it != converters.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->second->getStage() != 0)
|
||||||
|
continue;
|
||||||
|
it->second->write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.startRecord(ESM::REC_NPC_);
|
||||||
|
writer.writeHNString("NAME", "player");
|
||||||
|
context.mPlayerBase.save(writer);
|
||||||
|
writer.endRecord(ESM::REC_NPC_);
|
||||||
|
|
||||||
|
for (std::map<unsigned int, boost::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
||||||
|
it != converters.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->second->getStage() != 1)
|
||||||
|
continue;
|
||||||
|
it->second->write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.startRecord(ESM::REC_PLAY);
|
||||||
|
if (context.mPlayer.mCellId.mPaged)
|
||||||
|
{
|
||||||
|
// exterior cell -> determine cell coordinates based on position
|
||||||
|
const int cellSize = 8192;
|
||||||
|
int cellX = static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize));
|
||||||
|
int cellY = static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[1] / cellSize));
|
||||||
|
context.mPlayer.mCellId.mIndex.mX = cellX;
|
||||||
|
context.mPlayer.mCellId.mIndex.mY = cellY;
|
||||||
|
}
|
||||||
|
context.mPlayer.save(writer);
|
||||||
|
writer.endRecord(ESM::REC_PLAY);
|
||||||
|
|
||||||
|
writer.startRecord (ESM::REC_DIAS);
|
||||||
|
context.mDialogueState.save(writer);
|
||||||
|
writer.endRecord(ESM::REC_DIAS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
26
apps/essimporter/importer.hpp
Normal file
26
apps/essimporter/importer.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORTER_IMPORTER_H
|
||||||
|
#define OPENMW_ESSIMPORTER_IMPORTER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
class Importer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Importer(const std::string& essfile, const std::string& outfile, const std::string& encoding);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
void compare();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mEssFile;
|
||||||
|
std::string mOutFile;
|
||||||
|
std::string mEncoding;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
73
apps/essimporter/importercontext.hpp
Normal file
73
apps/essimporter/importercontext.hpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONTEXT_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONTEXT_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
#include <components/esm/player.hpp>
|
||||||
|
#include <components/esm/dialoguestate.hpp>
|
||||||
|
#include <components/esm/globalmap.hpp>
|
||||||
|
#include <components/esm/loadcrea.hpp>
|
||||||
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
|
#include "importnpcc.hpp"
|
||||||
|
#include "importcrec.hpp"
|
||||||
|
#include "importcntc.hpp"
|
||||||
|
#include "importplayer.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Context
|
||||||
|
{
|
||||||
|
// set from the TES3 header
|
||||||
|
std::string mPlayerCellName;
|
||||||
|
|
||||||
|
ESM::Player mPlayer;
|
||||||
|
ESM::NPC mPlayerBase;
|
||||||
|
std::string mCustomPlayerClassName;
|
||||||
|
|
||||||
|
ESM::DialogueState mDialogueState;
|
||||||
|
|
||||||
|
// cells which should show an explored overlay on the global map
|
||||||
|
std::set<std::pair<int, int> > mExploredCells;
|
||||||
|
|
||||||
|
ESM::GlobalMap mGlobalMapState;
|
||||||
|
|
||||||
|
int mDay, mMonth, mYear;
|
||||||
|
float mHour;
|
||||||
|
|
||||||
|
// key <refIndex, refId>
|
||||||
|
std::map<std::pair<int, std::string>, CREC> mCreatureChanges;
|
||||||
|
std::map<std::pair<int, std::string>, NPCC> mNpcChanges;
|
||||||
|
std::map<std::pair<int, std::string>, CNTC> mContainerChanges;
|
||||||
|
|
||||||
|
std::map<std::string, ESM::Creature> mCreatures;
|
||||||
|
std::map<std::string, ESM::NPC> mNpcs;
|
||||||
|
|
||||||
|
Context()
|
||||||
|
{
|
||||||
|
mPlayer.mAutoMove = 0;
|
||||||
|
ESM::CellId playerCellId;
|
||||||
|
playerCellId.mPaged = true;
|
||||||
|
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
||||||
|
mPlayer.mCellId = playerCellId;
|
||||||
|
//mPlayer.mLastKnownExteriorPosition
|
||||||
|
mPlayer.mHasMark = 0; // TODO
|
||||||
|
mPlayer.mCurrentCrimeId = 0; // TODO
|
||||||
|
mPlayer.mObject.blank();
|
||||||
|
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
|
||||||
|
|
||||||
|
mGlobalMapState.mBounds.mMinX = 0;
|
||||||
|
mGlobalMapState.mBounds.mMaxX = 0;
|
||||||
|
mGlobalMapState.mBounds.mMinY = 0;
|
||||||
|
mGlobalMapState.mBounds.mMaxY = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
29
apps/essimporter/importgame.cpp
Normal file
29
apps/essimporter/importgame.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "importgame.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void GAME::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getSubNameIs("GMDT");
|
||||||
|
esm.getSubHeader();
|
||||||
|
if (esm.getSubSize() == 92)
|
||||||
|
{
|
||||||
|
esm.getExact(&mGMDT, 92);
|
||||||
|
mGMDT.mSecundaPhase = 0;
|
||||||
|
}
|
||||||
|
else if (esm.getSubSize() == 96)
|
||||||
|
{
|
||||||
|
esm.getT(mGMDT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esm.fail("unexpected subrecord size for GAME.GMDT");
|
||||||
|
|
||||||
|
mGMDT.mWeatherTransition &= (0x000000ff);
|
||||||
|
mGMDT.mSecundaPhase &= (0x000000ff);
|
||||||
|
mGMDT.mMasserPhase &= (0x000000ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
apps/essimporter/importgame.hpp
Normal file
33
apps/essimporter/importgame.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_GAME_H
|
||||||
|
#define OPENMW_ESSIMPORT_GAME_H
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Weather data
|
||||||
|
struct GAME
|
||||||
|
{
|
||||||
|
struct GMDT
|
||||||
|
{
|
||||||
|
char mCellName[64];
|
||||||
|
int mFogColour;
|
||||||
|
float mFogDensity;
|
||||||
|
int mCurrentWeather, mNextWeather;
|
||||||
|
int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||||
|
float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition
|
||||||
|
int mMasserPhase, mSecundaPhase; // top 3 bytes may be garbage
|
||||||
|
};
|
||||||
|
|
||||||
|
GMDT mGMDT;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
14
apps/essimporter/importinfo.cpp
Normal file
14
apps/essimporter/importinfo.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "importinfo.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void INFO::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
mInfo = esm.getHNString("INAM");
|
||||||
|
mActorRefId = esm.getHNString("ACDT");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
apps/essimporter/importinfo.hpp
Normal file
24
apps/essimporter/importinfo.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTINFO_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTINFO_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct INFO
|
||||||
|
{
|
||||||
|
std::string mInfo;
|
||||||
|
std::string mActorRefId;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
68
apps/essimporter/importinventory.cpp
Normal file
68
apps/essimporter/importinventory.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include "importinventory.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/loadcont.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void Inventory::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("NPCO"))
|
||||||
|
{
|
||||||
|
ESM::ContItem contItem;
|
||||||
|
esm.getHT(contItem);
|
||||||
|
|
||||||
|
InventoryItem item;
|
||||||
|
item.mId = contItem.mItem.toString();
|
||||||
|
item.mCount = contItem.mCount;
|
||||||
|
item.mRelativeEquipmentSlot = -1;
|
||||||
|
|
||||||
|
// seems that a stack of items can have a set of subrecords for each item? rings0000.ess
|
||||||
|
// doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place?
|
||||||
|
// I guess we should double check the stacking logic in OpenMW
|
||||||
|
for (int i=0;i<std::abs(item.mCount);++i)
|
||||||
|
{
|
||||||
|
if (esm.isNextSub("XIDX")) // index in the stack?
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
item.mSCRI.load(esm);
|
||||||
|
|
||||||
|
// for XSOL and XCHG seen so far, but probably others too
|
||||||
|
item.ESM::CellRef::loadData(esm);
|
||||||
|
|
||||||
|
int charge=-1;
|
||||||
|
esm.getHNOT(charge, "XHLT");
|
||||||
|
item.mChargeInt = charge;
|
||||||
|
}
|
||||||
|
|
||||||
|
mItems.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// equipped items
|
||||||
|
while (esm.isNextSub("WIDX"))
|
||||||
|
{
|
||||||
|
// note: same item can be equipped 2 items (e.g. 2 rings)
|
||||||
|
// and will be *stacked* in the NPCO list, unlike openmw!
|
||||||
|
// this is currently not handled properly.
|
||||||
|
|
||||||
|
esm.getSubHeader();
|
||||||
|
int itemIndex; // index of the item in the NPCO list
|
||||||
|
esm.getT(itemIndex);
|
||||||
|
|
||||||
|
if (itemIndex < 0 || itemIndex >= int(mItems.size()))
|
||||||
|
esm.fail("equipment item index out of range");
|
||||||
|
|
||||||
|
// appears to be a relative index for only the *possible* slots this item can be equipped in,
|
||||||
|
// i.e. 0 most of the time
|
||||||
|
int slotIndex;
|
||||||
|
esm.getT(slotIndex);
|
||||||
|
|
||||||
|
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
apps/essimporter/importinventory.hpp
Normal file
34
apps/essimporter/importinventory.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Inventory
|
||||||
|
{
|
||||||
|
struct InventoryItem : public ESM::CellRef
|
||||||
|
{
|
||||||
|
std::string mId;
|
||||||
|
int mCount;
|
||||||
|
int mRelativeEquipmentSlot;
|
||||||
|
SCRI mSCRI;
|
||||||
|
};
|
||||||
|
std::vector<InventoryItem> mItems;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
13
apps/essimporter/importjour.cpp
Normal file
13
apps/essimporter/importjour.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "importjour.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void JOUR::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
mText = esm.getHNString("NAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
apps/essimporter/importjour.hpp
Normal file
25
apps/essimporter/importjour.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTJOUR_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTJOUR_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Journal
|
||||||
|
struct JOUR
|
||||||
|
{
|
||||||
|
// The entire journal, in HTML
|
||||||
|
std::string mText;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
22
apps/essimporter/importklst.cpp
Normal file
22
apps/essimporter/importklst.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include "importklst.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void KLST::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("KNAM"))
|
||||||
|
{
|
||||||
|
std::string refId = esm.getHString();
|
||||||
|
int count;
|
||||||
|
esm.getHNT(count, "CNAM");
|
||||||
|
mKillCounter[refId] = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWerewolfKills = 0;
|
||||||
|
esm.getHNOT(mWerewolfKills, "INTV");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
apps/essimporter/importklst.hpp
Normal file
28
apps/essimporter/importklst.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_KLST_H
|
||||||
|
#define OPENMW_ESSIMPORT_KLST_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Kill Stats
|
||||||
|
struct KLST
|
||||||
|
{
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
|
||||||
|
/// RefId, kill count
|
||||||
|
std::map<std::string, int> mKillCounter;
|
||||||
|
|
||||||
|
int mWerewolfKills;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
19
apps/essimporter/importnpcc.cpp
Normal file
19
apps/essimporter/importnpcc.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include "importnpcc.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void NPCC::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mNPDT, "NPDT");
|
||||||
|
|
||||||
|
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||||
|
|| esm.isNextSub("AI_A"))
|
||||||
|
mAiPackages.add(esm);
|
||||||
|
|
||||||
|
mInventory.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
apps/essimporter/importnpcc.hpp
Normal file
37
apps/essimporter/importnpcc.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_NPCC_H
|
||||||
|
#define OPENMW_ESSIMPORT_NPCC_H
|
||||||
|
|
||||||
|
#include <components/esm/loadcont.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/aipackage.hpp>
|
||||||
|
|
||||||
|
#include "importinventory.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NPCC
|
||||||
|
{
|
||||||
|
struct NPDT
|
||||||
|
{
|
||||||
|
unsigned char mDisposition;
|
||||||
|
unsigned char unknown;
|
||||||
|
unsigned char mReputation;
|
||||||
|
unsigned char unknown2;
|
||||||
|
int mIndex;
|
||||||
|
} mNPDT;
|
||||||
|
|
||||||
|
Inventory mInventory;
|
||||||
|
ESM::AIPackageList mAiPackages;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader &esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
85
apps/essimporter/importplayer.cpp
Normal file
85
apps/essimporter/importplayer.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#include "importplayer.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void REFR::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mRefNum.mIndex, "FRMR");
|
||||||
|
|
||||||
|
mRefID = esm.getHNString("NAME");
|
||||||
|
|
||||||
|
mActorData.load(esm);
|
||||||
|
|
||||||
|
esm.getHNOT(mPos, "DATA", 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCDT::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("DNAM"))
|
||||||
|
{
|
||||||
|
mKnownDialogueTopics.push_back(esm.getHString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esm.isNextSub("MNAM"))
|
||||||
|
esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in,
|
||||||
|
// but it's not always here, so it's kinda useless
|
||||||
|
|
||||||
|
esm.getHNT(mPNAM, "PNAM");
|
||||||
|
|
||||||
|
if (esm.isNextSub("SNAM"))
|
||||||
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("NAM9"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
mBounty = 0;
|
||||||
|
esm.getHNOT(mBounty, "CNAM");
|
||||||
|
|
||||||
|
mBirthsign = esm.getHNOString("BNAM");
|
||||||
|
|
||||||
|
// Holds the names of the last used Alchemy apparatus. Don't need to import this ATM,
|
||||||
|
// because our GUI auto-selects the best apparatus.
|
||||||
|
if (esm.isNextSub("NAM0"))
|
||||||
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("NAM1"))
|
||||||
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("NAM2"))
|
||||||
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("NAM3"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
if (esm.isNextSub("ENAM"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
if (esm.isNextSub("LNAM"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
while (esm.isNextSub("FNAM"))
|
||||||
|
{
|
||||||
|
FNAM fnam;
|
||||||
|
esm.getHT(fnam);
|
||||||
|
mFactions.push_back(fnam);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esm.isNextSub("AADT"))
|
||||||
|
esm.skipHSub(); // 44 bytes, no clue
|
||||||
|
|
||||||
|
if (esm.isNextSub("KNAM"))
|
||||||
|
esm.skipHSub(); // assigned Quick Keys, I think
|
||||||
|
|
||||||
|
if (esm.isNextSub("WERE"))
|
||||||
|
{
|
||||||
|
// some werewolf data, 152 bytes
|
||||||
|
// maybe current skills and attributes for werewolf form
|
||||||
|
esm.getSubHeader();
|
||||||
|
esm.skip(152);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsure if before or after WERE
|
||||||
|
if (esm.isNextSub("ANIS"))
|
||||||
|
esm.skipHSub();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
83
apps/essimporter/importplayer.hpp
Normal file
83
apps/essimporter/importplayer.hpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_PLAYER_H
|
||||||
|
#define OPENMW_ESSIMPORT_PLAYER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/esm/defs.hpp>
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
#include <components/esm/esmcommon.hpp>
|
||||||
|
|
||||||
|
#include "importacdt.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Player-agnostic player data
|
||||||
|
struct REFR
|
||||||
|
{
|
||||||
|
ActorData mActorData;
|
||||||
|
|
||||||
|
std::string mRefID;
|
||||||
|
ESM::Position mPos;
|
||||||
|
ESM::RefNum mRefNum;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Other player data
|
||||||
|
struct PCDT
|
||||||
|
{
|
||||||
|
int mBounty;
|
||||||
|
std::string mBirthsign;
|
||||||
|
|
||||||
|
std::vector<std::string> mKnownDialogueTopics;
|
||||||
|
|
||||||
|
enum DrawState_
|
||||||
|
{
|
||||||
|
DrawState_Weapon = 0x80,
|
||||||
|
DrawState_Spell = 0x100
|
||||||
|
};
|
||||||
|
enum CameraState
|
||||||
|
{
|
||||||
|
CameraState_FirstPerson = 0x8,
|
||||||
|
CameraState_ThirdPerson = 0xa
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct FNAM
|
||||||
|
{
|
||||||
|
unsigned char mRank;
|
||||||
|
unsigned char mUnknown1[3];
|
||||||
|
int mReputation;
|
||||||
|
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
||||||
|
unsigned char mUnknown2[3];
|
||||||
|
ESM::NAME32 mFactionName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PNAM
|
||||||
|
{
|
||||||
|
short mDrawState; // DrawState
|
||||||
|
short mCameraState; // CameraState
|
||||||
|
unsigned int mLevelProgress;
|
||||||
|
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||||
|
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||||
|
unsigned char mUnknown3[88];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
std::vector<FNAM> mFactions;
|
||||||
|
PNAM mPNAM;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
14
apps/essimporter/importques.cpp
Normal file
14
apps/essimporter/importques.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "importques.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void QUES::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("DATA"))
|
||||||
|
mInfo.push_back(esm.getHString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
apps/essimporter/importques.hpp
Normal file
28
apps/essimporter/importques.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTQUES_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTQUES_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// State for a quest
|
||||||
|
/// Presumably this record only exists when Tribunal is installed,
|
||||||
|
/// since pre-Tribunal there weren't any quest names in the data files.
|
||||||
|
struct QUES
|
||||||
|
{
|
||||||
|
std::string mName; // NAME, should be assigned from outside as usual
|
||||||
|
std::vector<std::string> mInfo; // list of journal entries for the quest
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
26
apps/essimporter/importscpt.cpp
Normal file
26
apps/essimporter/importscpt.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include "importscpt.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void SCPT::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mSCHD, "SCHD");
|
||||||
|
|
||||||
|
mSCRI.load(esm);
|
||||||
|
|
||||||
|
mRefNum = -1;
|
||||||
|
if (esm.isNextSub("RNAM"))
|
||||||
|
{
|
||||||
|
mRunning = true;
|
||||||
|
esm.getHT(mRefNum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
apps/essimporter/importscpt.hpp
Normal file
32
apps/essimporter/importscpt.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTSCPT_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTSCPT_H
|
||||||
|
|
||||||
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/loadscpt.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
// A running global script
|
||||||
|
struct SCPT
|
||||||
|
{
|
||||||
|
ESM::Script::SCHD mSCHD;
|
||||||
|
|
||||||
|
// values of local variables
|
||||||
|
SCRI mSCRI;
|
||||||
|
|
||||||
|
bool mRunning;
|
||||||
|
int mRefNum; // Targeted reference, -1: no reference
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
55
apps/essimporter/importscri.cpp
Normal file
55
apps/essimporter/importscri.cpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void SCRI::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
mScript = esm.getHNOString("SCRI");
|
||||||
|
|
||||||
|
int numShorts = 0, numLongs = 0, numFloats = 0;
|
||||||
|
if (esm.isNextSub("SLCS"))
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
esm.getT(numShorts);
|
||||||
|
esm.getT(numLongs);
|
||||||
|
esm.getT(numFloats);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esm.isNextSub("SLSD"))
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
for (int i=0; i<numShorts; ++i)
|
||||||
|
{
|
||||||
|
short val;
|
||||||
|
esm.getT(val);
|
||||||
|
mShorts.push_back(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// I haven't seen Longs in a save file yet, but SLLD would make sense for the name
|
||||||
|
// TODO: test this
|
||||||
|
if (esm.isNextSub("SLLD"))
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
for (int i=0; i<numLongs; ++i)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
esm.getT(val);
|
||||||
|
mLongs.push_back(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (esm.isNextSub("SLFD"))
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
for (int i=0; i<numFloats; ++i)
|
||||||
|
{
|
||||||
|
float val;
|
||||||
|
esm.getT(val);
|
||||||
|
mFloats.push_back(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
apps/essimporter/importscri.hpp
Normal file
30
apps/essimporter/importscri.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTSCRI_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTSCRI_H
|
||||||
|
|
||||||
|
#include <components/esm/variant.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Local variable assigments for a running script
|
||||||
|
struct SCRI
|
||||||
|
{
|
||||||
|
std::string mScript;
|
||||||
|
|
||||||
|
std::vector<short> mShorts;
|
||||||
|
std::vector<int> mLongs;
|
||||||
|
std::vector<float> mFloats;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
77
apps/essimporter/main.cpp
Normal file
77
apps/essimporter/main.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
|
||||||
|
#include "importer.hpp"
|
||||||
|
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
namespace bfs = boost::filesystem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bpo::options_description desc("Syntax: openmw-essimporter <options> infile.ess outfile.omwsave\nAllowed options");
|
||||||
|
bpo::positional_options_description p_desc;
|
||||||
|
desc.add_options()
|
||||||
|
("help,h", "produce help message")
|
||||||
|
("mwsave,m", bpo::value<std::string>(), "morrowind .ess save file")
|
||||||
|
("output,o", bpo::value<std::string>(), "output file (.omwsave)")
|
||||||
|
("compare,c", "compare two .ess files")
|
||||||
|
("encoding", boost::program_options::value<std::string>()->default_value("win1252"), "encoding of the save file")
|
||||||
|
;
|
||||||
|
p_desc.add("mwsave", 1).add("output", 1);
|
||||||
|
|
||||||
|
bpo::variables_map variables;
|
||||||
|
|
||||||
|
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
||||||
|
.options(desc)
|
||||||
|
.positional(p_desc)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
bpo::store(parsed, variables);
|
||||||
|
|
||||||
|
if(variables.count("help") || !variables.count("mwsave") || !variables.count("output")) {
|
||||||
|
std::cout << desc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpo::notify(variables);
|
||||||
|
|
||||||
|
Files::ConfigurationManager cfgManager(true);
|
||||||
|
cfgManager.readConfiguration(variables, desc);
|
||||||
|
|
||||||
|
std::string essFile = variables["mwsave"].as<std::string>();
|
||||||
|
std::string outputFile = variables["output"].as<std::string>();
|
||||||
|
std::string encoding = variables["encoding"].as<std::string>();
|
||||||
|
|
||||||
|
ESSImport::Importer importer(essFile, outputFile, encoding);
|
||||||
|
|
||||||
|
if (variables.count("compare"))
|
||||||
|
importer.compare();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const std::string& ext = ".omwsave";
|
||||||
|
if (boost::filesystem::exists(boost::filesystem::path(outputFile))
|
||||||
|
&& (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
|
||||||
|
}
|
||||||
|
importer.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -5,21 +5,16 @@ set(LAUNCHER
|
||||||
maindialog.cpp
|
maindialog.cpp
|
||||||
playpage.cpp
|
playpage.cpp
|
||||||
textslotmsgbox.cpp
|
textslotmsgbox.cpp
|
||||||
|
settingspage.cpp
|
||||||
|
|
||||||
settings/gamesettings.cpp
|
|
||||||
settings/graphicssettings.cpp
|
settings/graphicssettings.cpp
|
||||||
settings/launchersettings.cpp
|
|
||||||
|
|
||||||
utils/checkablemessagebox.cpp
|
|
||||||
utils/profilescombobox.cpp
|
utils/profilescombobox.cpp
|
||||||
utils/textinputdialog.cpp
|
utils/textinputdialog.cpp
|
||||||
utils/lineedit.cpp
|
utils/lineedit.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/files/launcher/launcher.rc
|
${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
|
||||||
)
|
)
|
||||||
if(NOT WIN32)
|
|
||||||
LIST(APPEND LAUNCHER unshieldthread.cpp)
|
|
||||||
endif(NOT WIN32)
|
|
||||||
|
|
||||||
set(LAUNCHER_HEADER
|
set(LAUNCHER_HEADER
|
||||||
datafilespage.hpp
|
datafilespage.hpp
|
||||||
|
@ -27,21 +22,14 @@ set(LAUNCHER_HEADER
|
||||||
maindialog.hpp
|
maindialog.hpp
|
||||||
playpage.hpp
|
playpage.hpp
|
||||||
textslotmsgbox.hpp
|
textslotmsgbox.hpp
|
||||||
|
settingspage.hpp
|
||||||
|
|
||||||
settings/gamesettings.hpp
|
|
||||||
settings/graphicssettings.hpp
|
settings/graphicssettings.hpp
|
||||||
settings/launchersettings.hpp
|
|
||||||
settings/settingsbase.hpp
|
|
||||||
|
|
||||||
utils/checkablemessagebox.hpp
|
|
||||||
utils/profilescombobox.hpp
|
utils/profilescombobox.hpp
|
||||||
utils/textinputdialog.hpp
|
utils/textinputdialog.hpp
|
||||||
utils/lineedit.hpp
|
utils/lineedit.hpp
|
||||||
)
|
)
|
||||||
if(NOT WIN32)
|
|
||||||
LIST(APPEND LAUNCHER_HEADER unshieldthread.hpp)
|
|
||||||
endif(NOT WIN32)
|
|
||||||
|
|
||||||
|
|
||||||
# Headers that must be pre-processed
|
# Headers that must be pre-processed
|
||||||
set(LAUNCHER_HEADER_MOC
|
set(LAUNCHER_HEADER_MOC
|
||||||
|
@ -50,25 +38,21 @@ set(LAUNCHER_HEADER_MOC
|
||||||
maindialog.hpp
|
maindialog.hpp
|
||||||
playpage.hpp
|
playpage.hpp
|
||||||
textslotmsgbox.hpp
|
textslotmsgbox.hpp
|
||||||
|
settingspage.hpp
|
||||||
|
|
||||||
utils/textinputdialog.hpp
|
utils/textinputdialog.hpp
|
||||||
utils/checkablemessagebox.hpp
|
|
||||||
utils/profilescombobox.hpp
|
utils/profilescombobox.hpp
|
||||||
utils/lineedit.hpp
|
utils/lineedit.hpp
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT WIN32)
|
|
||||||
LIST(APPEND LAUNCHER_HEADER_MOC unshieldthread.hpp)
|
|
||||||
endif(NOT WIN32)
|
|
||||||
|
|
||||||
|
|
||||||
set(LAUNCHER_UI
|
set(LAUNCHER_UI
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
|
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
|
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui
|
${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/playpage.ui
|
${CMAKE_SOURCE_DIR}/files/ui/playpage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||||
|
${CMAKE_SOURCE_DIR}/files/ui/settingspage.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
|
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
|
||||||
|
@ -90,11 +74,11 @@ QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
|
||||||
include(${QT_USE_FILE})
|
include(${QT_USE_FILE})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
include_directories(${LIBUNSHIELD_INCLUDE})
|
include_directories(${LIBUNSHIELD_INCLUDE_DIR})
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(omwlauncher
|
add_executable(openmw-launcher
|
||||||
${GUI_TYPE}
|
${GUI_TYPE}
|
||||||
${LAUNCHER}
|
${LAUNCHER}
|
||||||
${LAUNCHER_HEADER}
|
${LAUNCHER_HEADER}
|
||||||
|
@ -103,7 +87,7 @@ add_executable(omwlauncher
|
||||||
${UI_HDRS}
|
${UI_HDRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(omwlauncher
|
target_link_libraries(openmw-launcher
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
${OGRE_LIBRARIES}
|
${OGRE_LIBRARIES}
|
||||||
${OGRE_STATIC_PLUGINS}
|
${OGRE_STATIC_PLUGINS}
|
||||||
|
@ -111,16 +95,10 @@ target_link_libraries(omwlauncher
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
if(NOT WIN32)
|
|
||||||
target_link_libraries(omwlauncher
|
|
||||||
${LIBUNSHIELD_LIBRARY}
|
|
||||||
)
|
|
||||||
endif(NOT WIN32)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (BUILD_WITH_CODE_COVERAGE)
|
if (BUILD_WITH_CODE_COVERAGE)
|
||||||
add_definitions (--coverage)
|
add_definitions (--coverage)
|
||||||
target_link_libraries(omwlauncher gcov)
|
target_link_libraries(openmw-launcher gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "datafilespage.hpp"
|
#include "datafilespage.hpp"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
@ -9,18 +11,19 @@
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
|
||||||
#include <components/contentselector/model/esmfile.hpp>
|
#include <components/contentselector/model/esmfile.hpp>
|
||||||
|
|
||||||
#include <components/contentselector/model/naturalsort.hpp>
|
#include <components/contentselector/model/naturalsort.hpp>
|
||||||
|
#include <components/contentselector/view/contentselector.hpp>
|
||||||
|
|
||||||
|
#include <components/config/gamesettings.hpp>
|
||||||
|
#include <components/config/launchersettings.hpp>
|
||||||
|
|
||||||
#include "utils/textinputdialog.hpp"
|
#include "utils/textinputdialog.hpp"
|
||||||
#include "utils/profilescombobox.hpp"
|
#include "utils/profilescombobox.hpp"
|
||||||
|
|
||||||
#include "settings/gamesettings.hpp"
|
|
||||||
#include "settings/launchersettings.hpp"
|
|
||||||
|
|
||||||
#include "components/contentselector/view/contentselector.hpp"
|
const char *Launcher::DataFilesPage::mDefaultContentListName = "Default";
|
||||||
|
|
||||||
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent)
|
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent)
|
||||||
: mCfgMgr(cfg)
|
: mCfgMgr(cfg)
|
||||||
, mGameSettings(gameSettings)
|
, mGameSettings(gameSettings)
|
||||||
, mLauncherSettings(launcherSettings)
|
, mLauncherSettings(launcherSettings)
|
||||||
|
@ -30,55 +33,13 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSet
|
||||||
setObjectName ("DataFilesPage");
|
setObjectName ("DataFilesPage");
|
||||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
||||||
|
|
||||||
|
mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||||
|
|
||||||
|
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
|
||||||
|
this, SLOT(updateOkButton(QString)));
|
||||||
|
|
||||||
buildView();
|
buildView();
|
||||||
setupDataFiles();
|
loadSettings();
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::DataFilesPage::loadSettings()
|
|
||||||
{
|
|
||||||
QStringList paths = mGameSettings.getDataDirs();
|
|
||||||
paths.insert (0, mDataLocal);
|
|
||||||
PathIterator pathIterator (paths);
|
|
||||||
|
|
||||||
QString profileName = ui.profilesComboBox->currentText();
|
|
||||||
|
|
||||||
QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName, Qt::MatchExactly);
|
|
||||||
|
|
||||||
QStringList filepaths;
|
|
||||||
|
|
||||||
foreach (const QString &file, files)
|
|
||||||
{
|
|
||||||
QString filepath = pathIterator.findFirstPath (file);
|
|
||||||
|
|
||||||
if (!filepath.isEmpty())
|
|
||||||
filepaths << filepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSelector->setProfileContent (filepaths);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
|
||||||
{
|
|
||||||
QString profileName = profile;
|
|
||||||
|
|
||||||
if (profileName.isEmpty())
|
|
||||||
profileName = ui.profilesComboBox->currentText();
|
|
||||||
|
|
||||||
//retrieve the files selected for the profile
|
|
||||||
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
|
||||||
|
|
||||||
removeProfile (profileName);
|
|
||||||
|
|
||||||
mGameSettings.remove(QString("content"));
|
|
||||||
|
|
||||||
//set the value of the current profile (not necessarily the profile being saved!)
|
|
||||||
mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText());
|
|
||||||
|
|
||||||
foreach(const ContentSelectorModel::EsmFile *item, items) {
|
|
||||||
mLauncherSettings.setMultiValue(QString("Profiles/") + profileName, item->fileName());
|
|
||||||
mGameSettings.setMultiValue(QString("content"), item->fileName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::buildView()
|
void Launcher::DataFilesPage::buildView()
|
||||||
|
@ -86,12 +47,13 @@ void Launcher::DataFilesPage::buildView()
|
||||||
ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
|
ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
|
||||||
|
|
||||||
//tool buttons
|
//tool buttons
|
||||||
ui.newProfileButton->setToolTip ("Create a new profile");
|
ui.newProfileButton->setToolTip ("Create a new Content List");
|
||||||
ui.deleteProfileButton->setToolTip ("Delete an existing profile");
|
ui.deleteProfileButton->setToolTip ("Delete an existing Content List");
|
||||||
|
|
||||||
//combo box
|
//combo box
|
||||||
ui.profilesComboBox->addItem ("Default");
|
ui.profilesComboBox->addItem(mDefaultContentListName);
|
||||||
ui.profilesComboBox->setPlaceholderText (QString("Select a profile..."));
|
ui.profilesComboBox->setPlaceholderText (QString("Select a Content List..."));
|
||||||
|
ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String(mDefaultContentListName)));
|
||||||
|
|
||||||
// Add the actions to the toolbuttons
|
// Add the actions to the toolbuttons
|
||||||
ui.newProfileButton->setDefaultAction (ui.newProfileAction);
|
ui.newProfileButton->setDefaultAction (ui.newProfileAction);
|
||||||
|
@ -108,9 +70,81 @@ void Launcher::DataFilesPage::buildView()
|
||||||
this, SLOT (slotProfileChangedByUser(QString, QString)));
|
this, SLOT (slotProfileChangedByUser(QString, QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Launcher::DataFilesPage::loadSettings()
|
||||||
|
{
|
||||||
|
QStringList profiles = mLauncherSettings.getContentLists();
|
||||||
|
QString currentProfile = mLauncherSettings.getCurrentContentListName();
|
||||||
|
|
||||||
|
qDebug() << "current profile is: " << currentProfile;
|
||||||
|
|
||||||
|
foreach (const QString &item, profiles)
|
||||||
|
addProfile (item, false);
|
||||||
|
|
||||||
|
// Hack: also add the current profile
|
||||||
|
if (!currentProfile.isEmpty())
|
||||||
|
addProfile(currentProfile, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||||
|
{
|
||||||
|
QStringList paths = mGameSettings.getDataDirs();
|
||||||
|
|
||||||
|
foreach(const QString &path, paths)
|
||||||
|
mSelector->addFiles(path);
|
||||||
|
|
||||||
|
mDataLocal = mGameSettings.getDataLocal();
|
||||||
|
|
||||||
|
if (!mDataLocal.isEmpty())
|
||||||
|
mSelector->addFiles(mDataLocal);
|
||||||
|
|
||||||
|
paths.insert(0, mDataLocal);
|
||||||
|
PathIterator pathIterator(paths);
|
||||||
|
|
||||||
|
mSelector->setProfileContent(filesInProfile(contentModelName, pathIterator));
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator)
|
||||||
|
{
|
||||||
|
QStringList files = mLauncherSettings.getContentListFiles(profileName);
|
||||||
|
QStringList filepaths;
|
||||||
|
|
||||||
|
foreach(const QString& file, files)
|
||||||
|
{
|
||||||
|
QString filepath = pathIterator.findFirstPath(file);
|
||||||
|
|
||||||
|
if (!filepath.isEmpty())
|
||||||
|
filepaths << filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
||||||
|
{
|
||||||
|
QString profileName = profile;
|
||||||
|
|
||||||
|
if (profileName.isEmpty())
|
||||||
|
profileName = ui.profilesComboBox->currentText();
|
||||||
|
|
||||||
|
//retrieve the files selected for the profile
|
||||||
|
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||||
|
|
||||||
|
//set the value of the current profile (not necessarily the profile being saved!)
|
||||||
|
mLauncherSettings.setCurrentContentListName(ui.profilesComboBox->currentText());
|
||||||
|
|
||||||
|
QStringList fileNames;
|
||||||
|
foreach(const ContentSelectorModel::EsmFile *item, items) {
|
||||||
|
fileNames.append(item->fileName());
|
||||||
|
}
|
||||||
|
mLauncherSettings.setContentList(profileName, fileNames);
|
||||||
|
mGameSettings.setContentList(fileNames);
|
||||||
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::removeProfile(const QString &profile)
|
void Launcher::DataFilesPage::removeProfile(const QString &profile)
|
||||||
{
|
{
|
||||||
mLauncherSettings.remove(QString("Profiles/") + profile);
|
mLauncherSettings.removeContentList(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
|
QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
|
||||||
|
@ -127,9 +161,11 @@ void Launcher::DataFilesPage::setProfile(int index, bool savePrevious)
|
||||||
{
|
{
|
||||||
if (index >= -1 && index < ui.profilesComboBox->count())
|
if (index >= -1 && index < ui.profilesComboBox->count())
|
||||||
{
|
{
|
||||||
QString previous = ui.profilesComboBox->itemText(ui.profilesComboBox->currentIndex());
|
QString previous = mPreviousProfile;
|
||||||
QString current = ui.profilesComboBox->itemText(index);
|
QString current = ui.profilesComboBox->itemText(index);
|
||||||
|
|
||||||
|
mPreviousProfile = current;
|
||||||
|
|
||||||
setProfile (previous, current, savePrevious);
|
setProfile (previous, current, savePrevious);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +181,7 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString
|
||||||
|
|
||||||
ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current));
|
ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current));
|
||||||
|
|
||||||
loadSettings();
|
populateFileViews(current);
|
||||||
|
|
||||||
checkForDefaultProfile();
|
checkForDefaultProfile();
|
||||||
}
|
}
|
||||||
|
@ -177,68 +213,28 @@ void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const
|
||||||
|
|
||||||
void Launcher::DataFilesPage::slotProfileChanged(int index)
|
void Launcher::DataFilesPage::slotProfileChanged(int index)
|
||||||
{
|
{
|
||||||
|
// in case the event was triggered externally
|
||||||
|
if (ui.profilesComboBox->currentIndex() != index)
|
||||||
|
ui.profilesComboBox->setCurrentIndex(index);
|
||||||
|
|
||||||
setProfile (index, true);
|
setProfile (index, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::setupDataFiles()
|
|
||||||
{
|
|
||||||
QStringList paths = mGameSettings.getDataDirs();
|
|
||||||
|
|
||||||
foreach (const QString &path, paths)
|
|
||||||
mSelector->addFiles(path);
|
|
||||||
|
|
||||||
mDataLocal = mGameSettings.getDataLocal();
|
|
||||||
|
|
||||||
if (!mDataLocal.isEmpty())
|
|
||||||
mSelector->addFiles(mDataLocal);
|
|
||||||
|
|
||||||
QStringList profiles;
|
|
||||||
QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile");
|
|
||||||
|
|
||||||
foreach (QString key, mLauncherSettings.getSettings().keys())
|
|
||||||
{
|
|
||||||
if (key.contains("Profiles/"))
|
|
||||||
{
|
|
||||||
QString profile = key.mid (9);
|
|
||||||
if (profile != "currentprofile")
|
|
||||||
{
|
|
||||||
if (!profiles.contains(profile))
|
|
||||||
profiles << profile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QString &item, profiles)
|
|
||||||
addProfile (item, false);
|
|
||||||
|
|
||||||
setProfile (ui.profilesComboBox->findText(currentProfile), false);
|
|
||||||
|
|
||||||
loadSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::DataFilesPage::on_newProfileAction_triggered()
|
void Launcher::DataFilesPage::on_newProfileAction_triggered()
|
||||||
{
|
{
|
||||||
TextInputDialog newDialog (tr("New Profile"), tr("Profile name:"), this);
|
if (mProfileDialog->exec() != QDialog::Accepted)
|
||||||
|
|
||||||
if (newDialog.exec() != QDialog::Accepted)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString profile = newDialog.getText();
|
QString profile = mProfileDialog->lineEdit()->text();
|
||||||
|
|
||||||
if (profile.isEmpty())
|
if (profile.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
saveSettings();
|
saveSettings();
|
||||||
|
|
||||||
mSelector->clearCheckStates();
|
mLauncherSettings.setCurrentContentListName(profile);
|
||||||
|
|
||||||
addProfile(profile, true);
|
addProfile(profile, true);
|
||||||
|
|
||||||
mSelector->setGameFile();
|
|
||||||
|
|
||||||
saveSettings();
|
|
||||||
|
|
||||||
emit signalProfileChanged (ui.profilesComboBox->findText(profile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent)
|
void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent)
|
||||||
|
@ -246,9 +242,7 @@ void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurr
|
||||||
if (profile.isEmpty())
|
if (profile.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ui.profilesComboBox->findText (profile) != -1)
|
if (ui.profilesComboBox->findText (profile) == -1)
|
||||||
return;
|
|
||||||
|
|
||||||
ui.profilesComboBox->addItem (profile);
|
ui.profilesComboBox->addItem (profile);
|
||||||
|
|
||||||
if (setAsCurrent)
|
if (setAsCurrent)
|
||||||
|
@ -265,22 +259,35 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered()
|
||||||
if (!showDeleteMessageBox (profile))
|
if (!showDeleteMessageBox (profile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Remove the profile from the combobox
|
// this should work since the Default profile can't be deleted and is always index 0
|
||||||
ui.profilesComboBox->removeItem (ui.profilesComboBox->findText (profile));
|
int next = ui.profilesComboBox->currentIndex()-1;
|
||||||
|
|
||||||
|
// changing the profile forces a reload of plugin file views.
|
||||||
|
ui.profilesComboBox->setCurrentIndex(next);
|
||||||
|
|
||||||
removeProfile(profile);
|
removeProfile(profile);
|
||||||
|
ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile));
|
||||||
saveSettings();
|
|
||||||
|
|
||||||
loadSettings();
|
|
||||||
|
|
||||||
checkForDefaultProfile();
|
checkForDefaultProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Launcher::DataFilesPage::updateOkButton(const QString &text)
|
||||||
|
{
|
||||||
|
// We do this here because we need the profiles combobox text
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
mProfileDialog->setOkButtonEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(ui.profilesComboBox->findText(text) == -1)
|
||||||
|
? mProfileDialog->setOkButtonEnabled(true)
|
||||||
|
: mProfileDialog->setOkButtonEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::checkForDefaultProfile()
|
void Launcher::DataFilesPage::checkForDefaultProfile()
|
||||||
{
|
{
|
||||||
//don't allow deleting "Default" profile
|
//don't allow deleting "Default" profile
|
||||||
bool success = (ui.profilesComboBox->currentText() != "Default");
|
bool success = (ui.profilesComboBox->currentText() != mDefaultContentListName);
|
||||||
|
|
||||||
ui.deleteProfileAction->setEnabled (success);
|
ui.deleteProfileAction->setEnabled (success);
|
||||||
ui.profilesComboBox->setEditEnabled (success);
|
ui.profilesComboBox->setEditEnabled (success);
|
||||||
|
@ -289,10 +296,10 @@ void Launcher::DataFilesPage::checkForDefaultProfile()
|
||||||
bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
|
bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
|
||||||
{
|
{
|
||||||
QMessageBox msgBox(this);
|
QMessageBox msgBox(this);
|
||||||
msgBox.setWindowTitle(tr("Delete Profile"));
|
msgBox.setWindowTitle(tr("Delete Content List"));
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||||
msgBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(text));
|
msgBox.setText(tr("Are you sure you want to delete <b>%1</b>?").arg(text));
|
||||||
|
|
||||||
QAbstractButton *deleteButton =
|
QAbstractButton *deleteButton =
|
||||||
msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||||
|
|
|
@ -14,12 +14,12 @@ class QMenu;
|
||||||
|
|
||||||
namespace Files { struct ConfigurationManager; }
|
namespace Files { struct ConfigurationManager; }
|
||||||
namespace ContentSelectorView { class ContentSelector; }
|
namespace ContentSelectorView { class ContentSelector; }
|
||||||
|
namespace Config { class GameSettings;
|
||||||
|
class LauncherSettings; }
|
||||||
|
|
||||||
namespace Launcher
|
namespace Launcher
|
||||||
{
|
{
|
||||||
class TextInputDialog;
|
class TextInputDialog;
|
||||||
class GameSettings;
|
|
||||||
class LauncherSettings;
|
|
||||||
class ProfilesComboBox;
|
class ProfilesComboBox;
|
||||||
|
|
||||||
class DataFilesPage : public QWidget
|
class DataFilesPage : public QWidget
|
||||||
|
@ -30,8 +30,8 @@ namespace Launcher
|
||||||
Ui::DataFilesPage ui;
|
Ui::DataFilesPage ui;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DataFilesPage (Files::ConfigurationManager &cfg, GameSettings &gameSettings,
|
explicit DataFilesPage (Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||||
LauncherSettings &launcherSettings, QWidget *parent = 0);
|
Config::LauncherSettings &launcherSettings, QWidget *parent = 0);
|
||||||
|
|
||||||
QAbstractItemModel* profilesModel() const;
|
QAbstractItemModel* profilesModel() const;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace Launcher
|
||||||
|
|
||||||
//void writeConfig(QString profile = QString());
|
//void writeConfig(QString profile = QString());
|
||||||
void saveSettings(const QString &profile = "");
|
void saveSettings(const QString &profile = "");
|
||||||
void loadSettings();
|
bool loadSettings();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void signalProfileChanged (int index);
|
void signalProfileChanged (int index);
|
||||||
|
@ -53,24 +53,31 @@ namespace Launcher
|
||||||
void slotProfileRenamed(const QString &previous, const QString ¤t);
|
void slotProfileRenamed(const QString &previous, const QString ¤t);
|
||||||
void slotProfileDeleted(const QString &item);
|
void slotProfileDeleted(const QString &item);
|
||||||
|
|
||||||
|
void updateOkButton(const QString &text);
|
||||||
|
|
||||||
void on_newProfileAction_triggered();
|
void on_newProfileAction_triggered();
|
||||||
void on_deleteProfileAction_triggered();
|
void on_deleteProfileAction_triggered();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Content List that is always present
|
||||||
|
const static char *mDefaultContentListName;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QMenu *mContextMenu;
|
TextInputDialog *mProfileDialog;
|
||||||
|
|
||||||
Files::ConfigurationManager &mCfgMgr;
|
Files::ConfigurationManager &mCfgMgr;
|
||||||
|
|
||||||
GameSettings &mGameSettings;
|
Config::GameSettings &mGameSettings;
|
||||||
LauncherSettings &mLauncherSettings;
|
Config::LauncherSettings &mLauncherSettings;
|
||||||
|
|
||||||
|
QString mPreviousProfile;
|
||||||
|
|
||||||
QString mDataLocal;
|
QString mDataLocal;
|
||||||
|
|
||||||
void setPluginsCheckstates(Qt::CheckState state);
|
void setPluginsCheckstates(Qt::CheckState state);
|
||||||
|
|
||||||
void buildView();
|
void buildView();
|
||||||
void setupDataFiles();
|
|
||||||
void setupConfig();
|
void setupConfig();
|
||||||
void readConfig();
|
void readConfig();
|
||||||
void setProfile (int index, bool savePrevious);
|
void setProfile (int index, bool savePrevious);
|
||||||
|
@ -79,6 +86,7 @@ namespace Launcher
|
||||||
bool showDeleteMessageBox (const QString &text);
|
bool showDeleteMessageBox (const QString &text);
|
||||||
void addProfile (const QString &profile, bool setAsCurrent);
|
void addProfile (const QString &profile, bool setAsCurrent);
|
||||||
void checkForDefaultProfile();
|
void checkForDefaultProfile();
|
||||||
|
void populateFileViews(const QString& contentModelName);
|
||||||
|
|
||||||
class PathIterator
|
class PathIterator
|
||||||
{
|
{
|
||||||
|
@ -131,6 +139,8 @@ namespace Launcher
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
|
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
|
||||||
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
#include <OgreRoot.h>
|
||||||
|
#include <OgreRenderSystem.h>
|
||||||
|
|
||||||
#include <boost/math/common_factor.hpp>
|
#include <boost/math/common_factor.hpp>
|
||||||
|
|
||||||
|
@ -33,7 +36,11 @@ QString getAspect(int x, int y)
|
||||||
}
|
}
|
||||||
|
|
||||||
Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
|
Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
|
||||||
: mCfgMgr(cfg)
|
: mOgre(NULL)
|
||||||
|
, mSelectedRenderSystem(NULL)
|
||||||
|
, mOpenGLRenderSystem(NULL)
|
||||||
|
, mDirect3DRenderSystem(NULL)
|
||||||
|
, mCfgMgr(cfg)
|
||||||
, mGraphicsSettings(graphicsSetting)
|
, mGraphicsSettings(graphicsSetting)
|
||||||
, QWidget(parent)
|
, QWidget(parent)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +67,7 @@ bool Launcher::GraphicsPage::setupOgre()
|
||||||
}
|
}
|
||||||
catch(Ogre::Exception &ex)
|
catch(Ogre::Exception &ex)
|
||||||
{
|
{
|
||||||
QString ogreError = QString::fromStdString(ex.getFullDescription().c_str());
|
QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str());
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setWindowTitle("Error creating Ogre::Root");
|
msgBox.setWindowTitle("Error creating Ogre::Root");
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
|
@ -128,11 +135,12 @@ bool Launcher::GraphicsPage::setupSDL()
|
||||||
msgBox.setWindowTitle(tr("Error receiving number of screens"));
|
msgBox.setWindowTitle(tr("Error receiving number of screens"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
|
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
screenComboBox->clear();
|
||||||
for (int i = 0; i < displays; i++)
|
for (int i = 0; i < displays; i++)
|
||||||
{
|
{
|
||||||
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
|
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
|
||||||
|
@ -145,7 +153,7 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||||
{
|
{
|
||||||
if (!setupSDL())
|
if (!setupSDL())
|
||||||
return false;
|
return false;
|
||||||
if (!setupOgre())
|
if (!mOgre && !setupOgre())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
|
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
|
||||||
|
@ -154,6 +162,9 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||||
if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true"))
|
if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true"))
|
||||||
fullScreenCheckBox->setCheckState(Qt::Checked);
|
fullScreenCheckBox->setCheckState(Qt::Checked);
|
||||||
|
|
||||||
|
if (mGraphicsSettings.value(QString("Video/window border")) == QLatin1String("true"))
|
||||||
|
windowBorderCheckBox->setCheckState(Qt::Checked);
|
||||||
|
|
||||||
int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing")));
|
int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing")));
|
||||||
if (aaIndex != -1)
|
if (aaIndex != -1)
|
||||||
antiAliasingComboBox->setCurrentIndex(aaIndex);
|
antiAliasingComboBox->setCurrentIndex(aaIndex);
|
||||||
|
@ -188,6 +199,9 @@ void Launcher::GraphicsPage::saveSettings()
|
||||||
fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true"))
|
fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true"))
|
||||||
: mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false"));
|
: mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false"));
|
||||||
|
|
||||||
|
windowBorderCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/window border"), QString("true"))
|
||||||
|
: mGraphicsSettings.setValue(QString("Video/window border"), QString("false"));
|
||||||
|
|
||||||
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
|
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
|
||||||
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
|
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
|
||||||
|
|
||||||
|
@ -223,7 +237,7 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre
|
||||||
opt_it != i->second.possibleValues.end(); ++opt_it, ++idx)
|
opt_it != i->second.possibleValues.end(); ++opt_it, ++idx)
|
||||||
{
|
{
|
||||||
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
|
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
|
||||||
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified();
|
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,7 +266,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||||
msgBox.setWindowTitle(tr("Error receiving resolutions"));
|
msgBox.setWindowTitle(tr("Error receiving resolutions"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
|
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -265,7 +279,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||||
msgBox.setWindowTitle(tr("Error receiving resolutions"));
|
msgBox.setWindowTitle(tr("Error receiving resolutions"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(tr("<br><b>SDL_GetDisplayMode failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
|
msgBox.setText(tr("<br><b>SDL_GetDisplayMode failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -326,10 +340,12 @@ void Launcher::GraphicsPage::slotFullScreenChanged(int state)
|
||||||
customRadioButton->setEnabled(false);
|
customRadioButton->setEnabled(false);
|
||||||
customWidthSpinBox->setEnabled(false);
|
customWidthSpinBox->setEnabled(false);
|
||||||
customHeightSpinBox->setEnabled(false);
|
customHeightSpinBox->setEnabled(false);
|
||||||
|
windowBorderCheckBox->setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
customRadioButton->setEnabled(true);
|
customRadioButton->setEnabled(true);
|
||||||
customWidthSpinBox->setEnabled(true);
|
customWidthSpinBox->setEnabled(true);
|
||||||
customHeightSpinBox->setEnabled(true);
|
customHeightSpinBox->setEnabled(true);
|
||||||
|
windowBorderCheckBox->setEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,11 @@
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <OgreRoot.h>
|
|
||||||
#include <OgreRenderSystem.h>
|
|
||||||
|
|
||||||
#include <components/ogreinit/ogreinit.hpp>
|
#include <components/ogreinit/ogreinit.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include "ui_graphicspage.h"
|
#include "ui_graphicspage.h"
|
||||||
|
|
||||||
|
namespace Ogre { class Root; class RenderSystem; }
|
||||||
|
|
||||||
namespace Files { struct ConfigurationManager; }
|
namespace Files { struct ConfigurationManager; }
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
@ -14,14 +17,18 @@
|
||||||
#include "maindialog.hpp"
|
#include "maindialog.hpp"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||||
SDL_SetMainReady();
|
SDL_SetMainReady();
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||||
{
|
{
|
||||||
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
|
qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
|
||||||
|
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
@ -52,13 +59,22 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
Launcher::MainDialog mainWin;
|
Launcher::MainDialog mainWin;
|
||||||
|
|
||||||
if (mainWin.setup()) {
|
if (!mainWin.showFirstRunDialog())
|
||||||
mainWin.show();
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
// if (!mainWin.setup()) {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
mainWin.show();
|
||||||
|
|
||||||
int returnValue = app.exec();
|
int returnValue = app.exec();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,54 +5,39 @@
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QProcess>
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
#include "unshieldthread.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "textslotmsgbox.hpp"
|
|
||||||
|
|
||||||
#include "utils/checkablemessagebox.hpp"
|
|
||||||
|
|
||||||
#include "playpage.hpp"
|
#include "playpage.hpp"
|
||||||
#include "graphicspage.hpp"
|
#include "graphicspage.hpp"
|
||||||
#include "datafilespage.hpp"
|
#include "datafilespage.hpp"
|
||||||
|
#include "settingspage.hpp"
|
||||||
|
|
||||||
|
using namespace Process;
|
||||||
|
|
||||||
Launcher::MainDialog::MainDialog(QWidget *parent)
|
Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
: mGameSettings(mCfgMgr), QMainWindow (parent)
|
: mGameSettings(mCfgMgr), QMainWindow (parent)
|
||||||
{
|
{
|
||||||
// Install the stylesheet font
|
|
||||||
QFile file;
|
|
||||||
QFontDatabase fontDatabase;
|
|
||||||
|
|
||||||
const QStringList fonts = fontDatabase.families();
|
|
||||||
|
|
||||||
// Check if the font is installed
|
|
||||||
if (!fonts.contains("EB Garamond")) {
|
|
||||||
|
|
||||||
QString font = QString::fromUtf8(mCfgMgr.getGlobalDataPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf");
|
|
||||||
file.setFileName(font);
|
|
||||||
|
|
||||||
if (!file.exists()) {
|
|
||||||
font = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf");
|
|
||||||
}
|
|
||||||
|
|
||||||
fontDatabase.addApplicationFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
|
mGameInvoker = new ProcessInvoker();
|
||||||
|
mWizardInvoker = new ProcessInvoker();
|
||||||
|
|
||||||
|
connect(mWizardInvoker->getProcess(), SIGNAL(started()),
|
||||||
|
this, SLOT(wizardStarted()));
|
||||||
|
|
||||||
|
connect(mWizardInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||||
|
this, SLOT(wizardFinished(int,QProcess::ExitStatus)));
|
||||||
|
|
||||||
iconWidget->setViewMode(QListView::IconMode);
|
iconWidget->setViewMode(QListView::IconMode);
|
||||||
iconWidget->setWrapping(false);
|
iconWidget->setWrapping(false);
|
||||||
iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure
|
iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure
|
||||||
|
@ -76,16 +61,17 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
QString revision(OPENMW_VERSION_COMMITHASH);
|
QString revision(OPENMW_VERSION_COMMITHASH);
|
||||||
QString tag(OPENMW_VERSION_TAGHASH);
|
QString tag(OPENMW_VERSION_TAGHASH);
|
||||||
|
|
||||||
|
versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
if (!revision.isEmpty() && !tag.isEmpty())
|
if (!revision.isEmpty() && !tag.isEmpty())
|
||||||
{
|
{
|
||||||
if (revision == tag) {
|
if (revision == tag) {
|
||||||
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
|
versionLabel->setText(tr("OpenMW %1 release").arg(OPENMW_VERSION));
|
||||||
} else {
|
} else {
|
||||||
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
|
versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the compile date and time
|
// Add the compile date and time
|
||||||
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
||||||
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
||||||
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
||||||
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
||||||
|
@ -94,32 +80,41 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
createIcons();
|
createIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Launcher::MainDialog::~MainDialog()
|
||||||
|
{
|
||||||
|
delete mGameInvoker;
|
||||||
|
delete mWizardInvoker;
|
||||||
|
}
|
||||||
|
|
||||||
void Launcher::MainDialog::createIcons()
|
void Launcher::MainDialog::createIcons()
|
||||||
{
|
{
|
||||||
if (!QIcon::hasThemeIcon("document-new"))
|
if (!QIcon::hasThemeIcon("document-new"))
|
||||||
QIcon::setThemeName("tango");
|
QIcon::setThemeName("tango");
|
||||||
|
|
||||||
// We create a fallback icon because the default fallback doesn't work
|
|
||||||
QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png");
|
|
||||||
|
|
||||||
QListWidgetItem *playButton = new QListWidgetItem(iconWidget);
|
QListWidgetItem *playButton = new QListWidgetItem(iconWidget);
|
||||||
playButton->setIcon(QIcon(":/images/openmw.png"));
|
playButton->setIcon(QIcon(":/images/openmw.png"));
|
||||||
playButton->setText(tr("Play"));
|
playButton->setText(tr("Play"));
|
||||||
playButton->setTextAlignment(Qt::AlignCenter);
|
playButton->setTextAlignment(Qt::AlignCenter);
|
||||||
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
|
|
||||||
graphicsButton->setIcon(QIcon::fromTheme("video-display", graphicsIcon));
|
|
||||||
graphicsButton->setText(tr("Graphics"));
|
|
||||||
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
|
|
||||||
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
||||||
|
|
||||||
QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget);
|
QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget);
|
||||||
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
|
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
|
||||||
dataFilesButton->setText(tr("Data Files"));
|
dataFilesButton->setText(tr("Data Files"));
|
||||||
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
|
QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
|
||||||
|
graphicsButton->setIcon(QIcon::fromTheme("video-display"));
|
||||||
|
graphicsButton->setText(tr("Graphics"));
|
||||||
|
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
|
||||||
|
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
|
QListWidgetItem *settingsButton = new QListWidgetItem(iconWidget);
|
||||||
|
settingsButton->setIcon(QIcon::fromTheme("preferences-system"));
|
||||||
|
settingsButton->setText(tr("Settings"));
|
||||||
|
settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
|
settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
connect(iconWidget,
|
connect(iconWidget,
|
||||||
SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
|
SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
|
||||||
this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*)));
|
this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*)));
|
||||||
|
@ -129,8 +124,9 @@ void Launcher::MainDialog::createIcons()
|
||||||
void Launcher::MainDialog::createPages()
|
void Launcher::MainDialog::createPages()
|
||||||
{
|
{
|
||||||
mPlayPage = new PlayPage(this);
|
mPlayPage = new PlayPage(this);
|
||||||
mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this);
|
|
||||||
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
|
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
|
||||||
|
mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this);
|
||||||
|
mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
|
||||||
|
|
||||||
// Set the combobox of the play page to imitate the combobox on the datafilespage
|
// Set the combobox of the play page to imitate the combobox on the datafilespage
|
||||||
mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
|
mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
|
||||||
|
@ -138,8 +134,9 @@ void Launcher::MainDialog::createPages()
|
||||||
|
|
||||||
// Add the pages to the stacked widget
|
// Add the pages to the stacked widget
|
||||||
pagesWidget->addWidget(mPlayPage);
|
pagesWidget->addWidget(mPlayPage);
|
||||||
pagesWidget->addWidget(mGraphicsPage);
|
|
||||||
pagesWidget->addWidget(mDataFilesPage);
|
pagesWidget->addWidget(mDataFilesPage);
|
||||||
|
pagesWidget->addWidget(mGraphicsPage);
|
||||||
|
pagesWidget->addWidget(mSettingsPage);
|
||||||
|
|
||||||
// Select the first page
|
// Select the first page
|
||||||
iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select);
|
iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select);
|
||||||
|
@ -153,170 +150,52 @@ void Launcher::MainDialog::createPages()
|
||||||
|
|
||||||
bool Launcher::MainDialog::showFirstRunDialog()
|
bool Launcher::MainDialog::showFirstRunDialog()
|
||||||
{
|
{
|
||||||
QStringList iniPaths;
|
if (!setupLauncherSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
foreach (const QString &path, mGameSettings.getDataDirs()) {
|
if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true"))
|
||||||
QDir dir(path);
|
|
||||||
dir.setPath(dir.canonicalPath()); // Resolve symlinks
|
|
||||||
|
|
||||||
if (dir.exists(QString("Morrowind.ini")))
|
|
||||||
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (!dir.cdUp())
|
|
||||||
continue; // Cannot move from Data Files
|
|
||||||
|
|
||||||
if (dir.exists(QString("Morrowind.ini")))
|
|
||||||
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask the user where the Morrowind.ini is
|
|
||||||
if (iniPaths.empty()) {
|
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setWindowTitle(tr("Error detecting Morrowind configuration"));
|
msgBox.setWindowTitle(tr("First run"));
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
msgBox.setIcon(QMessageBox::Question);
|
||||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not find Morrowind.ini</b><br><br> \
|
msgBox.setText(tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p> \
|
||||||
OpenMW needs to import settings from this file.<br><br> \
|
<p>It is recommended to run the Installation Wizard.</p> \
|
||||||
Press \"Browse...\" to specify the location manually.<br>"));
|
<p>The Wizard will let you select an existing Morrowind installation, \
|
||||||
|
or install Morrowind for OpenMW to use.</p></body></html>"));
|
||||||
|
|
||||||
QAbstractButton *dirSelectButton =
|
QAbstractButton *wizardButton =
|
||||||
msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole);
|
msgBox.addButton(tr("Run &Installation Wizard"), QMessageBox::AcceptRole); // ActionRole doesn't work?!
|
||||||
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
QString iniFile;
|
|
||||||
if (msgBox.clickedButton() == dirSelectButton) {
|
|
||||||
iniFile = QFileDialog::getOpenFileName(
|
|
||||||
NULL,
|
|
||||||
QObject::tr("Select configuration file"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
QString(tr("Morrowind configuration file (*.ini)")));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iniFile.isEmpty())
|
|
||||||
return false; // Cancel was clicked;
|
|
||||||
|
|
||||||
QFileInfo info(iniFile);
|
|
||||||
iniPaths.clear();
|
|
||||||
iniPaths.append(info.absoluteFilePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckableMessageBox msgBox(this);
|
|
||||||
msgBox.setWindowTitle(tr("Morrowind installation detected"));
|
|
||||||
|
|
||||||
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
|
|
||||||
int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
|
|
||||||
msgBox.setIconPixmap(icon.pixmap(size, size));
|
|
||||||
|
|
||||||
QAbstractButton *importerButton =
|
|
||||||
msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?!
|
|
||||||
QAbstractButton *skipButton =
|
QAbstractButton *skipButton =
|
||||||
msgBox.addButton(tr("Skip"), QDialogButtonBox::RejectRole);
|
msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||||
|
|
||||||
Q_UNUSED(skipButton); // Surpress compiler unused warning
|
Q_UNUSED(skipButton); // Surpress compiler unused warning
|
||||||
|
|
||||||
msgBox.setStandardButtons(QDialogButtonBox::NoButton);
|
|
||||||
msgBox.setText(tr("<br><b>An existing Morrowind configuration was detected</b><br> \
|
|
||||||
<br>Would you like to import settings from Morrowind.ini?<br> \
|
|
||||||
<br><b>Warning: In most cases OpenMW needs these settings to run properly</b><br>"));
|
|
||||||
msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)"));
|
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
|
||||||
|
if (msgBox.clickedButton() == wizardButton)
|
||||||
if (msgBox.clickedButton() == importerButton) {
|
{
|
||||||
|
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) {
|
||||||
if (iniPaths.count() > 1) {
|
return false;
|
||||||
// Multiple Morrowind.ini files found
|
|
||||||
bool ok;
|
|
||||||
QString path = QInputDialog::getItem(this, tr("Multiple configurations found"),
|
|
||||||
tr("<br><b>There are multiple Morrowind.ini files found.</b><br><br> \
|
|
||||||
Please select the one you wish to import from:"), iniPaths, 0, false, &ok);
|
|
||||||
if (ok && !path.isEmpty()) {
|
|
||||||
iniPaths.clear();
|
|
||||||
iniPaths.append(path);
|
|
||||||
} else {
|
} else {
|
||||||
// Cancel was clicked
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the file if it doesn't already exist, else the importer will fail
|
|
||||||
QString path = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()) + QString("openmw.cfg");
|
|
||||||
QFile file(path);
|
|
||||||
|
|
||||||
if (!file.exists()) {
|
|
||||||
if (!file.open(QIODevice::ReadWrite)) {
|
|
||||||
// File cannot be created
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
|
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
msgBox.setText(tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
|
||||||
Please make sure you have the right permissions \
|
|
||||||
and try again.<br>").arg(file.fileName()));
|
|
||||||
msgBox.exec();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the arguments to run the importer
|
|
||||||
QStringList arguments;
|
|
||||||
|
|
||||||
if (msgBox.isChecked())
|
|
||||||
arguments.append(QString("--game-files"));
|
|
||||||
|
|
||||||
arguments.append(QString("--encoding"));
|
|
||||||
arguments.append(mGameSettings.value(QString("encoding"), QString("win1252")));
|
|
||||||
arguments.append(QString("--ini"));
|
|
||||||
arguments.append(iniPaths.first());
|
|
||||||
arguments.append(QString("--cfg"));
|
|
||||||
arguments.append(path);
|
|
||||||
|
|
||||||
if (!startProgram(QString("mwiniimport"), arguments, false))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Re-read the game settings
|
|
||||||
if (!setupGameSettings())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Add a new profile
|
|
||||||
if (msgBox.isChecked()) {
|
|
||||||
mLauncherSettings.setValue(QString("Profiles/currentprofile"), QString("Imported"));
|
|
||||||
mLauncherSettings.remove(QString("Profiles/Imported/content"));
|
|
||||||
|
|
||||||
QStringList contents = mGameSettings.values(QString("content"));
|
|
||||||
foreach (const QString &content, contents) {
|
|
||||||
mLauncherSettings.setMultiValue(QString("Profiles/Imported/content"), content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return setup();
|
||||||
|
}
|
||||||
|
|
||||||
bool Launcher::MainDialog::setup()
|
bool Launcher::MainDialog::setup()
|
||||||
{
|
{
|
||||||
if (!setupLauncherSettings())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!setupGameSettings())
|
if (!setupGameSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
mLauncherSettings.setContentList(mGameSettings);
|
||||||
|
|
||||||
if (!setupGraphicsSettings())
|
if (!setupGraphicsSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if we need to show the importer
|
|
||||||
if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true"))
|
|
||||||
{
|
|
||||||
if (!showFirstRunDialog())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now create the pages as they need the settings
|
// Now create the pages as they need the settings
|
||||||
createPages();
|
createPages();
|
||||||
|
|
||||||
|
@ -325,6 +204,32 @@ bool Launcher::MainDialog::setup()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Launcher::MainDialog::reloadSettings()
|
||||||
|
{
|
||||||
|
if (!setupLauncherSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!setupGameSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mLauncherSettings.setContentList(mGameSettings);
|
||||||
|
|
||||||
|
if (!setupGraphicsSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mSettingsPage->loadSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mDataFilesPage->loadSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mGraphicsPage->loadSettings())
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,24 +239,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem
|
||||||
current = previous;
|
current = previous;
|
||||||
|
|
||||||
int currentIndex = iconWidget->row(current);
|
int currentIndex = iconWidget->row(current);
|
||||||
int previousIndex = iconWidget->row(previous);
|
|
||||||
|
|
||||||
pagesWidget->setCurrentIndex(currentIndex);
|
pagesWidget->setCurrentIndex(currentIndex);
|
||||||
|
mSettingsPage->resetProgressBar();
|
||||||
DataFilesPage *previousPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(previousIndex));
|
|
||||||
DataFilesPage *currentPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(currentIndex));
|
|
||||||
|
|
||||||
//special call to update/save data files page list view when it's displayed/hidden.
|
|
||||||
if (previousPage)
|
|
||||||
{
|
|
||||||
if (previousPage->objectName() == "DataFilesPage")
|
|
||||||
previousPage->saveSettings();
|
|
||||||
}
|
|
||||||
else if (currentPage)
|
|
||||||
{
|
|
||||||
if (currentPage->objectName() == "DataFilesPage")
|
|
||||||
currentPage->loadSettings();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Launcher::MainDialog::setupLauncherSettings()
|
bool Launcher::MainDialog::setupLauncherSettings()
|
||||||
|
@ -361,8 +250,8 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||||
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
||||||
|
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
paths.append(QString("launcher.cfg"));
|
paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName));
|
||||||
paths.append(userPath + QString("launcher.cfg"));
|
paths.append(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName));
|
||||||
|
|
||||||
foreach (const QString &path, paths) {
|
foreach (const QString &path, paths) {
|
||||||
qDebug() << "Loading config file:" << qPrintable(path);
|
qDebug() << "Loading config file:" << qPrintable(path);
|
||||||
|
@ -373,7 +262,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||||
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
|
msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||||
Please make sure you have the right permissions \
|
Please make sure you have the right permissions \
|
||||||
and try again.<br>").arg(file.fileName()));
|
and try again.<br>").arg(file.fileName()));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
@ -390,78 +279,6 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
bool Launcher::expansions(Launcher::UnshieldThread& cd)
|
|
||||||
{
|
|
||||||
if(cd.BloodmoonDone())
|
|
||||||
{
|
|
||||||
cd.Done();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMessageBox expansionsBox;
|
|
||||||
expansionsBox.setText(QObject::tr("<br>Would you like to install expansions now ? (make sure you have the disc)<br> \
|
|
||||||
If you want to install both Bloodmoon and Tribunal, you have to install Tribunal first.<br>"));
|
|
||||||
|
|
||||||
QAbstractButton* tribunalButton = NULL;
|
|
||||||
if(!cd.TribunalDone())
|
|
||||||
tribunalButton = expansionsBox.addButton(QObject::tr("&Tribunal"), QMessageBox::ActionRole);
|
|
||||||
|
|
||||||
QAbstractButton* bloodmoonButton = expansionsBox.addButton(QObject::tr("&Bloodmoon"), QMessageBox::ActionRole);
|
|
||||||
QAbstractButton* noneButton = expansionsBox.addButton(QObject::tr("&None"), QMessageBox::ActionRole);
|
|
||||||
|
|
||||||
expansionsBox.exec();
|
|
||||||
|
|
||||||
if(expansionsBox.clickedButton() == noneButton)
|
|
||||||
{
|
|
||||||
cd.Done();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if(expansionsBox.clickedButton() == tribunalButton)
|
|
||||||
{
|
|
||||||
|
|
||||||
TextSlotMsgBox cdbox;
|
|
||||||
cdbox.setStandardButtons(QMessageBox::Cancel);
|
|
||||||
|
|
||||||
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&)));
|
|
||||||
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
|
|
||||||
|
|
||||||
cd.SetTribunalPath(
|
|
||||||
QFileDialog::getOpenFileName(
|
|
||||||
NULL,
|
|
||||||
QObject::tr("Select data1.hdr from Tribunal Installation CD (Tribunal/data1.hdr on GOTY CDs)"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
QString(QObject::tr("Installshield hdr file (*.hdr)"))).toUtf8().constData());
|
|
||||||
|
|
||||||
cd.start();
|
|
||||||
cdbox.exec();
|
|
||||||
}
|
|
||||||
else if(expansionsBox.clickedButton() == bloodmoonButton)
|
|
||||||
{
|
|
||||||
|
|
||||||
TextSlotMsgBox cdbox;
|
|
||||||
cdbox.setStandardButtons(QMessageBox::Cancel);
|
|
||||||
|
|
||||||
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&)));
|
|
||||||
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
|
|
||||||
|
|
||||||
cd.SetBloodmoonPath(
|
|
||||||
QFileDialog::getOpenFileName(
|
|
||||||
NULL,
|
|
||||||
QObject::tr("Select data1.hdr from Bloodmoon Installation CD (Bloodmoon/data1.hdr on GOTY CDs)"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
QString(QObject::tr("Installshield hdr file (*.hdr)"))).toUtf8().constData());
|
|
||||||
|
|
||||||
cd.start();
|
|
||||||
cdbox.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif // WIN32
|
|
||||||
|
|
||||||
bool Launcher::MainDialog::setupGameSettings()
|
bool Launcher::MainDialog::setupGameSettings()
|
||||||
{
|
{
|
||||||
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
||||||
|
@ -480,7 +297,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
|
msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||||
Please make sure you have the right permissions \
|
Please make sure you have the right permissions \
|
||||||
and try again.<br>").arg(file.fileName()));
|
and try again.<br>").arg(file.fileName()));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
@ -508,7 +325,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
|
msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||||
Please make sure you have the right permissions \
|
Please make sure you have the right permissions \
|
||||||
and try again.<br>").arg(file.fileName()));
|
and try again.<br>").arg(file.fileName()));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
@ -540,72 +357,22 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
msgBox.setWindowTitle(tr("Error detecting Morrowind installation"));
|
msgBox.setWindowTitle(tr("Error detecting Morrowind installation"));
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not find the Data Files location</b><br><br> \
|
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
|
||||||
The directory containing the data files was not found.<br><br> \
|
The directory containing the data files was not found."));
|
||||||
Press \"Browse...\" to specify the location manually.<br>"));
|
|
||||||
|
|
||||||
QAbstractButton *dirSelectButton =
|
|
||||||
msgBox.addButton(QObject::tr("Browse to &Install..."), QMessageBox::ActionRole);
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
QAbstractButton *cdSelectButton =
|
|
||||||
msgBox.addButton(QObject::tr("Browse to &CD..."), QMessageBox::ActionRole);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
QAbstractButton *wizardButton =
|
||||||
|
msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
|
||||||
|
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
|
||||||
QString selectedFile;
|
if (msgBox.clickedButton() == wizardButton)
|
||||||
if (msgBox.clickedButton() == dirSelectButton) {
|
|
||||||
selectedFile = QFileDialog::getOpenFileName(
|
|
||||||
NULL,
|
|
||||||
QObject::tr("Select master file"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
QString(tr("Morrowind master file (*.esm)")));
|
|
||||||
}
|
|
||||||
#ifndef WIN32
|
|
||||||
else if(msgBox.clickedButton() == cdSelectButton) {
|
|
||||||
UnshieldThread cd;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
TextSlotMsgBox cdbox;
|
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) {
|
||||||
cdbox.setStandardButtons(QMessageBox::Cancel);
|
return false;
|
||||||
|
} else {
|
||||||
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&)));
|
return true;
|
||||||
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
|
|
||||||
|
|
||||||
cd.SetMorrowindPath(
|
|
||||||
QFileDialog::getOpenFileName(
|
|
||||||
NULL,
|
|
||||||
QObject::tr("Select data1.hdr from Morrowind Installation CD"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
QString(tr("Installshield hdr file (*.hdr)"))).toUtf8().constData());
|
|
||||||
|
|
||||||
cd.SetOutputPath(
|
|
||||||
QFileDialog::getExistingDirectory(
|
|
||||||
NULL,
|
|
||||||
QObject::tr("Select where to extract files to"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks).toUtf8().constData());
|
|
||||||
|
|
||||||
cd.start();
|
|
||||||
cdbox.exec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while(expansions(cd));
|
|
||||||
|
|
||||||
selectedFile = QString::fromUtf8(cd.GetMWEsmPath().c_str());
|
|
||||||
}
|
}
|
||||||
#endif // WIN32
|
|
||||||
|
|
||||||
if (selectedFile.isEmpty())
|
|
||||||
return false; // Cancel was clicked;
|
|
||||||
|
|
||||||
QFileInfo info(selectedFile);
|
|
||||||
|
|
||||||
// Add the new dir to the settings file and to the data dir container
|
|
||||||
mGameSettings.setMultiValue(QString("data"), info.absolutePath());
|
|
||||||
mGameSettings.addDataDir(info.absolutePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -626,7 +393,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
||||||
msgBox.setWindowTitle(tr("Error reading OpenMW configuration file"));
|
msgBox.setWindowTitle(tr("Error reading OpenMW configuration file"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not find settings-default.cfg</b><br><br> \
|
msgBox.setText(tr("<br><b>Could not find settings-default.cfg</b><br><br> \
|
||||||
The problem may be due to an incomplete installation of OpenMW.<br> \
|
The problem may be due to an incomplete installation of OpenMW.<br> \
|
||||||
Reinstalling OpenMW may resolve the problem."));
|
Reinstalling OpenMW may resolve the problem."));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
@ -648,7 +415,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
||||||
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
|
msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||||
Please make sure you have the right permissions \
|
Please make sure you have the right permissions \
|
||||||
and try again.<br>").arg(file.fileName()));
|
and try again.<br>").arg(file.fileName()));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
@ -699,8 +466,9 @@ bool Launcher::MainDialog::writeSettings()
|
||||||
{
|
{
|
||||||
// Now write all config files
|
// Now write all config files
|
||||||
saveSettings();
|
saveSettings();
|
||||||
mGraphicsPage->saveSettings();
|
|
||||||
mDataFilesPage->saveSettings();
|
mDataFilesPage->saveSettings();
|
||||||
|
mGraphicsPage->saveSettings();
|
||||||
|
mSettingsPage->saveSettings();
|
||||||
|
|
||||||
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
||||||
QDir dir(userPath);
|
QDir dir(userPath);
|
||||||
|
@ -764,7 +532,7 @@ bool Launcher::MainDialog::writeSettings()
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
// Launcher settings
|
// Launcher settings
|
||||||
file.setFileName(userPath + QString("launcher.cfg"));
|
file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName));
|
||||||
|
|
||||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
|
||||||
// File cannot be opened or created
|
// File cannot be opened or created
|
||||||
|
@ -794,12 +562,27 @@ void Launcher::MainDialog::closeEvent(QCloseEvent *event)
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Launcher::MainDialog::wizardStarted()
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::MainDialog::wizardFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
|
||||||
|
return qApp->quit();
|
||||||
|
|
||||||
|
// HACK: Ensure the pages are created, else segfault
|
||||||
|
setup();
|
||||||
|
|
||||||
|
if (reloadSettings())
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
void Launcher::MainDialog::play()
|
void Launcher::MainDialog::play()
|
||||||
{
|
{
|
||||||
if (!writeSettings()) {
|
if (!writeSettings())
|
||||||
qApp->quit();
|
return qApp->quit();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mGameSettings.hasMaster()) {
|
if (!mGameSettings.hasMaster()) {
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
|
@ -813,103 +596,7 @@ void Launcher::MainDialog::play()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch the game detached
|
// Launch the game detached
|
||||||
startProgram(QString("openmw"), true);
|
|
||||||
qApp->quit();
|
if (mGameInvoker->startProcess(QLatin1String("openmw"), true))
|
||||||
}
|
return qApp->quit();
|
||||||
|
|
||||||
bool Launcher::MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached)
|
|
||||||
{
|
|
||||||
QString path = name;
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
path.append(QString(".exe"));
|
|
||||||
#elif defined(Q_OS_MAC)
|
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
|
||||||
path = dir.absoluteFilePath(name);
|
|
||||||
#else
|
|
||||||
path.prepend(QString("./"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QFile file(path);
|
|
||||||
|
|
||||||
QProcess process;
|
|
||||||
QFileInfo info(file);
|
|
||||||
|
|
||||||
if (!file.exists()) {
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(tr("Error starting executable"));
|
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
msgBox.setText(tr("<br><b>Could not find %1</b><br><br> \
|
|
||||||
The application is not found.<br> \
|
|
||||||
Please make sure OpenMW is installed correctly and try again.<br>").arg(info.fileName()));
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.isExecutable()) {
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(tr("Error starting executable"));
|
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
|
|
||||||
The application is not executable.<br> \
|
|
||||||
Please make sure you have the right permissions and try again.<br>").arg(info.fileName()));
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the executable
|
|
||||||
if (detached) {
|
|
||||||
if (!process.startDetached(path, arguments)) {
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(tr("Error starting executable"));
|
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
|
|
||||||
An error occurred while starting %1.<br><br> \
|
|
||||||
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
|
|
||||||
msgBox.setDetailedText(process.errorString());
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
process.start(path, arguments);
|
|
||||||
if (!process.waitForFinished()) {
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(tr("Error starting executable"));
|
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
|
|
||||||
An error occurred while starting %1.<br><br> \
|
|
||||||
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
|
|
||||||
msgBox.setDetailedText(process.errorString());
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit) {
|
|
||||||
QString error(process.readAllStandardError());
|
|
||||||
error.append(tr("\nArguments:\n"));
|
|
||||||
error.append(arguments.join(" "));
|
|
||||||
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(tr("Error running executable"));
|
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
msgBox.setText(tr("<br><b>Executable %1 returned an error</b><br><br> \
|
|
||||||
An error occurred while running %1.<br><br> \
|
|
||||||
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
|
|
||||||
msgBox.setDetailedText(error);
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,26 @@
|
||||||
#define MAINDIALOG_H
|
#define MAINDIALOG_H
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
#ifndef Q_MOC_RUN
|
#ifndef Q_MOC_RUN
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#endif
|
#endif
|
||||||
#include "settings/gamesettings.hpp"
|
|
||||||
|
#include <components/process/processinvoker.hpp>
|
||||||
|
|
||||||
|
#include <components/config/gamesettings.hpp>
|
||||||
|
#include <components/config/launchersettings.hpp>
|
||||||
|
|
||||||
#include "settings/graphicssettings.hpp"
|
#include "settings/graphicssettings.hpp"
|
||||||
#include "settings/launchersettings.hpp"
|
|
||||||
|
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
class QListWidgetItem;
|
class QListWidgetItem;
|
||||||
|
class QStackedWidget;
|
||||||
|
class QStringList;
|
||||||
|
class QStringListModel;
|
||||||
|
class QString;
|
||||||
|
|
||||||
namespace Launcher
|
namespace Launcher
|
||||||
{
|
{
|
||||||
|
@ -19,6 +29,7 @@ namespace Launcher
|
||||||
class GraphicsPage;
|
class GraphicsPage;
|
||||||
class DataFilesPage;
|
class DataFilesPage;
|
||||||
class UnshieldThread;
|
class UnshieldThread;
|
||||||
|
class SettingsPage;
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
bool expansions(Launcher::UnshieldThread& cd);
|
bool expansions(Launcher::UnshieldThread& cd);
|
||||||
|
@ -30,13 +41,22 @@ namespace Launcher
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MainDialog(QWidget *parent = 0);
|
explicit MainDialog(QWidget *parent = 0);
|
||||||
|
~MainDialog();
|
||||||
|
|
||||||
bool setup();
|
bool setup();
|
||||||
bool showFirstRunDialog();
|
bool showFirstRunDialog();
|
||||||
|
|
||||||
|
bool reloadSettings();
|
||||||
|
bool writeSettings();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
|
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
|
||||||
void play();
|
void play();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void wizardStarted();
|
||||||
|
void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createIcons();
|
void createIcons();
|
||||||
void createPages();
|
void createPages();
|
||||||
|
@ -47,7 +67,6 @@ namespace Launcher
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
bool writeSettings();
|
|
||||||
|
|
||||||
inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); }
|
inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); }
|
||||||
bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
|
bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
|
||||||
|
@ -57,12 +76,16 @@ namespace Launcher
|
||||||
PlayPage *mPlayPage;
|
PlayPage *mPlayPage;
|
||||||
GraphicsPage *mGraphicsPage;
|
GraphicsPage *mGraphicsPage;
|
||||||
DataFilesPage *mDataFilesPage;
|
DataFilesPage *mDataFilesPage;
|
||||||
|
SettingsPage *mSettingsPage;
|
||||||
|
|
||||||
|
Process::ProcessInvoker *mGameInvoker;
|
||||||
|
Process::ProcessInvoker *mWizardInvoker;
|
||||||
|
|
||||||
Files::ConfigurationManager mCfgMgr;
|
Files::ConfigurationManager mCfgMgr;
|
||||||
|
|
||||||
GameSettings mGameSettings;
|
Config::GameSettings mGameSettings;
|
||||||
GraphicsSettings mGraphicsSettings;
|
GraphicsSettings mGraphicsSettings;
|
||||||
LauncherSettings mLauncherSettings;
|
Config::LauncherSettings mLauncherSettings;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#ifndef GRAPHICSSETTINGS_HPP
|
#ifndef GRAPHICSSETTINGS_HPP
|
||||||
#define GRAPHICSSETTINGS_HPP
|
#define GRAPHICSSETTINGS_HPP
|
||||||
|
|
||||||
#include "settingsbase.hpp"
|
#include <components/config/settingsbase.hpp>
|
||||||
|
|
||||||
namespace Launcher
|
namespace Launcher
|
||||||
{
|
{
|
||||||
class GraphicsSettings : public SettingsBase<QMap<QString, QString> >
|
class GraphicsSettings : public Config::SettingsBase<QMap<QString, QString> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GraphicsSettings();
|
GraphicsSettings();
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
#include "launchersettings.hpp"
|
|
||||||
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <QString>
|
|
||||||
#include <QRegExp>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
Launcher::LauncherSettings::LauncherSettings()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Launcher::LauncherSettings::~LauncherSettings()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList Launcher::LauncherSettings::values(const QString &key, Qt::MatchFlags flags)
|
|
||||||
{
|
|
||||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
|
||||||
|
|
||||||
if (flags == Qt::MatchExactly)
|
|
||||||
return settings.values(key);
|
|
||||||
|
|
||||||
QStringList result;
|
|
||||||
|
|
||||||
if (flags == Qt::MatchStartsWith) {
|
|
||||||
QStringList keys = settings.keys();
|
|
||||||
|
|
||||||
foreach (const QString ¤tKey, keys) {
|
|
||||||
if (currentKey.startsWith(key))
|
|
||||||
result.append(settings.value(currentKey));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList Launcher::LauncherSettings::subKeys(const QString &key)
|
|
||||||
{
|
|
||||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
|
||||||
QStringList keys = settings.uniqueKeys();
|
|
||||||
|
|
||||||
QRegExp keyRe("(.+)/");
|
|
||||||
|
|
||||||
QStringList result;
|
|
||||||
|
|
||||||
foreach (const QString ¤tKey, keys) {
|
|
||||||
if (keyRe.indexIn(currentKey) != -1) {
|
|
||||||
QString prefixedKey = keyRe.cap(1);
|
|
||||||
if(prefixedKey.startsWith(key)) {
|
|
||||||
QString subKey = prefixedKey.remove(key);
|
|
||||||
if (!subKey.isEmpty())
|
|
||||||
result.append(subKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.removeDuplicates();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::LauncherSettings::writeFile(QTextStream &stream)
|
|
||||||
{
|
|
||||||
QString sectionPrefix;
|
|
||||||
QRegExp sectionRe("([^/]+)/(.+)$");
|
|
||||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
|
||||||
|
|
||||||
QMapIterator<QString, QString> i(settings);
|
|
||||||
i.toBack();
|
|
||||||
|
|
||||||
while (i.hasPrevious()) {
|
|
||||||
i.previous();
|
|
||||||
|
|
||||||
QString prefix;
|
|
||||||
QString key;
|
|
||||||
|
|
||||||
if (sectionRe.exactMatch(i.key())) {
|
|
||||||
prefix = sectionRe.cap(1);
|
|
||||||
key = sectionRe.cap(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get rid of legacy settings
|
|
||||||
if (key.contains(QChar('\\')))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (key == QLatin1String("CurrentProfile"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sectionPrefix != prefix) {
|
|
||||||
sectionPrefix = prefix;
|
|
||||||
stream << "\n[" << prefix << "]\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << key << "=" << i.value() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#ifndef LAUNCHERSETTINGS_HPP
|
|
||||||
#define LAUNCHERSETTINGS_HPP
|
|
||||||
|
|
||||||
#include "settingsbase.hpp"
|
|
||||||
|
|
||||||
namespace Launcher
|
|
||||||
{
|
|
||||||
class LauncherSettings : public SettingsBase<QMap<QString, QString> >
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LauncherSettings();
|
|
||||||
~LauncherSettings();
|
|
||||||
|
|
||||||
QStringList subKeys(const QString &key);
|
|
||||||
QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly);
|
|
||||||
|
|
||||||
bool writeFile(QTextStream &stream);
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif // LAUNCHERSETTINGS_HPP
|
|
275
apps/launcher/settingspage.cpp
Normal file
275
apps/launcher/settingspage.cpp
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
#include "settingspage.hpp"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
|
||||||
|
#include <components/config/gamesettings.hpp>
|
||||||
|
#include <components/config/launchersettings.hpp>
|
||||||
|
|
||||||
|
#include "utils/textinputdialog.hpp"
|
||||||
|
#include "datafilespage.hpp"
|
||||||
|
|
||||||
|
using namespace Process;
|
||||||
|
|
||||||
|
Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||||
|
Config::GameSettings &gameSettings,
|
||||||
|
Config::LauncherSettings &launcherSettings, MainDialog *parent)
|
||||||
|
: mCfgMgr(cfg)
|
||||||
|
, mGameSettings(gameSettings)
|
||||||
|
, mLauncherSettings(launcherSettings)
|
||||||
|
, QWidget(parent)
|
||||||
|
, mMain(parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
|
||||||
|
QStringList languages;
|
||||||
|
languages << QLatin1String("English")
|
||||||
|
<< QLatin1String("French")
|
||||||
|
<< QLatin1String("German")
|
||||||
|
<< QLatin1String("Italian")
|
||||||
|
<< QLatin1String("Polish")
|
||||||
|
<< QLatin1String("Russian")
|
||||||
|
<< QLatin1String("Spanish");
|
||||||
|
|
||||||
|
languageComboBox->addItems(languages);
|
||||||
|
|
||||||
|
mWizardInvoker = new ProcessInvoker();
|
||||||
|
mImporterInvoker = new ProcessInvoker();
|
||||||
|
resetProgressBar();
|
||||||
|
|
||||||
|
connect(mWizardInvoker->getProcess(), SIGNAL(started()),
|
||||||
|
this, SLOT(wizardStarted()));
|
||||||
|
|
||||||
|
connect(mWizardInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||||
|
this, SLOT(wizardFinished(int,QProcess::ExitStatus)));
|
||||||
|
|
||||||
|
connect(mImporterInvoker->getProcess(), SIGNAL(started()),
|
||||||
|
this, SLOT(importerStarted()));
|
||||||
|
|
||||||
|
connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||||
|
this, SLOT(importerFinished(int,QProcess::ExitStatus)));
|
||||||
|
|
||||||
|
mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||||
|
|
||||||
|
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
|
||||||
|
this, SLOT(updateOkButton(QString)));
|
||||||
|
|
||||||
|
// Detect Morrowind configuration files
|
||||||
|
QStringList iniPaths;
|
||||||
|
|
||||||
|
foreach (const QString &path, mGameSettings.getDataDirs()) {
|
||||||
|
QDir dir(path);
|
||||||
|
dir.setPath(dir.canonicalPath()); // Resolve symlinks
|
||||||
|
|
||||||
|
if (dir.exists(QString("Morrowind.ini")))
|
||||||
|
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!dir.cdUp())
|
||||||
|
continue; // Cannot move from Data Files
|
||||||
|
|
||||||
|
if (dir.exists(QString("Morrowind.ini")))
|
||||||
|
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iniPaths.isEmpty()) {
|
||||||
|
settingsComboBox->addItems(iniPaths);
|
||||||
|
importerButton->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
importerButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
Launcher::SettingsPage::~SettingsPage()
|
||||||
|
{
|
||||||
|
delete mWizardInvoker;
|
||||||
|
delete mImporterInvoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::on_wizardButton_clicked()
|
||||||
|
{
|
||||||
|
mMain->writeSettings();
|
||||||
|
|
||||||
|
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::on_importerButton_clicked()
|
||||||
|
{
|
||||||
|
mMain->writeSettings();
|
||||||
|
|
||||||
|
// Create the file if it doesn't already exist, else the importer will fail
|
||||||
|
QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()));
|
||||||
|
path.append(QLatin1String("openmw.cfg"));
|
||||||
|
QFile file(path);
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
if (!file.open(QIODevice::ReadWrite)) {
|
||||||
|
// File cannot be created
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
|
||||||
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
|
msgBox.setText(tr("<html><head/><body><p><b>Could not open or create %1 for writing </b></p> \
|
||||||
|
<p>Please make sure you have the right permissions \
|
||||||
|
and try again.</p></body></html>").arg(file.fileName()));
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the arguments to run the importer
|
||||||
|
QStringList arguments;
|
||||||
|
|
||||||
|
if (addonsCheckBox->isChecked())
|
||||||
|
arguments.append(QString("--game-files"));
|
||||||
|
|
||||||
|
arguments.append(QString("--encoding"));
|
||||||
|
arguments.append(mGameSettings.value(QString("encoding"), QString("win1252")));
|
||||||
|
arguments.append(QString("--ini"));
|
||||||
|
arguments.append(settingsComboBox->currentText());
|
||||||
|
arguments.append(QString("--cfg"));
|
||||||
|
arguments.append(path);
|
||||||
|
|
||||||
|
qDebug() << "arguments " << arguments;
|
||||||
|
|
||||||
|
// start the progress bar as a "bouncing ball"
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
progressBar->setValue(0);
|
||||||
|
if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false))
|
||||||
|
{
|
||||||
|
resetProgressBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::on_browseButton_clicked()
|
||||||
|
{
|
||||||
|
QString iniFile = QFileDialog::getOpenFileName(
|
||||||
|
this,
|
||||||
|
QObject::tr("Select configuration file"),
|
||||||
|
QDir::currentPath(),
|
||||||
|
QString(tr("Morrowind configuration file (*.ini)")));
|
||||||
|
|
||||||
|
|
||||||
|
if (iniFile.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFileInfo info(iniFile);
|
||||||
|
|
||||||
|
if (!info.exists() || !info.isReadable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString path(QDir::toNativeSeparators(info.absoluteFilePath()));
|
||||||
|
|
||||||
|
if (settingsComboBox->findText(path) == -1) {
|
||||||
|
settingsComboBox->addItem(path);
|
||||||
|
settingsComboBox->setCurrentIndex(settingsComboBox->findText(path));
|
||||||
|
importerButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::wizardStarted()
|
||||||
|
{
|
||||||
|
mMain->hide(); // Hide the launcher
|
||||||
|
|
||||||
|
wizardButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::wizardFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
|
||||||
|
return qApp->quit();
|
||||||
|
|
||||||
|
mMain->reloadSettings();
|
||||||
|
wizardButton->setEnabled(true);
|
||||||
|
|
||||||
|
mMain->show(); // Show the launcher again
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::importerStarted()
|
||||||
|
{
|
||||||
|
importerButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
|
||||||
|
{
|
||||||
|
resetProgressBar();
|
||||||
|
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(tr("Importer finished"));
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
|
msgBox.setText(tr("Failed to import settings from INI file."));
|
||||||
|
msgBox.exec();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// indicate progress finished
|
||||||
|
progressBar->setMaximum(1);
|
||||||
|
progressBar->setValue(1);
|
||||||
|
|
||||||
|
// Importer may have changed settings, so refresh
|
||||||
|
mMain->reloadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
importerButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::resetProgressBar()
|
||||||
|
{
|
||||||
|
// set progress bar to 0 %
|
||||||
|
progressBar->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::updateOkButton(const QString &text)
|
||||||
|
{
|
||||||
|
// We do this here because we need to access the profiles
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
mProfileDialog->setOkButtonEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList profiles(mLauncherSettings.getContentLists());
|
||||||
|
|
||||||
|
(profiles.contains(text))
|
||||||
|
? mProfileDialog->setOkButtonEnabled(false)
|
||||||
|
: mProfileDialog->setOkButtonEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::saveSettings()
|
||||||
|
{
|
||||||
|
QString language(languageComboBox->currentText());
|
||||||
|
|
||||||
|
mLauncherSettings.setValue(QLatin1String("Settings/language"), language);
|
||||||
|
|
||||||
|
if (language == QLatin1String("Polish")) {
|
||||||
|
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1250"));
|
||||||
|
} else if (language == QLatin1String("Russian")) {
|
||||||
|
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1251"));
|
||||||
|
} else {
|
||||||
|
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Launcher::SettingsPage::loadSettings()
|
||||||
|
{
|
||||||
|
QString language(mLauncherSettings.value(QLatin1String("Settings/language")));
|
||||||
|
|
||||||
|
int index = languageComboBox->findText(language);
|
||||||
|
|
||||||
|
if (index != -1)
|
||||||
|
languageComboBox->setCurrentIndex(index);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
66
apps/launcher/settingspage.hpp
Normal file
66
apps/launcher/settingspage.hpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef SETTINGSPAGE_HPP
|
||||||
|
#define SETTINGSPAGE_HPP
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
#include <components/process/processinvoker.hpp>
|
||||||
|
|
||||||
|
#include "ui_settingspage.h"
|
||||||
|
|
||||||
|
#include "maindialog.hpp"
|
||||||
|
|
||||||
|
namespace Files { struct ConfigurationManager; }
|
||||||
|
namespace Config { class GameSettings;
|
||||||
|
class LauncherSettings; }
|
||||||
|
|
||||||
|
namespace Launcher
|
||||||
|
{
|
||||||
|
class TextInputDialog;
|
||||||
|
|
||||||
|
class SettingsPage : public QWidget, private Ui::SettingsPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SettingsPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||||
|
Config::LauncherSettings &launcherSettings, MainDialog *parent = 0);
|
||||||
|
~SettingsPage();
|
||||||
|
|
||||||
|
void saveSettings();
|
||||||
|
bool loadSettings();
|
||||||
|
|
||||||
|
/// set progress bar on page to 0%
|
||||||
|
void resetProgressBar();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void on_wizardButton_clicked();
|
||||||
|
void on_importerButton_clicked();
|
||||||
|
void on_browseButton_clicked();
|
||||||
|
|
||||||
|
void wizardStarted();
|
||||||
|
void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
|
||||||
|
void importerStarted();
|
||||||
|
void importerFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
|
||||||
|
void updateOkButton(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Process::ProcessInvoker *mWizardInvoker;
|
||||||
|
Process::ProcessInvoker *mImporterInvoker;
|
||||||
|
|
||||||
|
Files::ConfigurationManager &mCfgMgr;
|
||||||
|
|
||||||
|
Config::GameSettings &mGameSettings;
|
||||||
|
Config::LauncherSettings &mLauncherSettings;
|
||||||
|
|
||||||
|
MainDialog *mMain;
|
||||||
|
TextInputDialog *mProfileDialog;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SETTINGSPAGE_HPP
|
|
@ -1,521 +0,0 @@
|
||||||
#include "unshieldthread.hpp"
|
|
||||||
|
|
||||||
#include <boost/filesystem/fstream.hpp>
|
|
||||||
#include <components/misc/stringops.hpp>
|
|
||||||
|
|
||||||
namespace bfs = boost::filesystem;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
static bool make_sure_directory_exists(bfs::path directory)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(!bfs::exists(directory))
|
|
||||||
{
|
|
||||||
bfs::create_directories(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bfs::exists(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill_path(bfs::path& path, const std::string& name)
|
|
||||||
{
|
|
||||||
size_t start = 0;
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
for(i = 0; i < name.length(); i++)
|
|
||||||
{
|
|
||||||
switch(name[i])
|
|
||||||
{
|
|
||||||
case '\\':
|
|
||||||
path /= name.substr(start, i-start);
|
|
||||||
start = i+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path /= name.substr(start, i-start);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_setting(const std::string& category, const std::string& setting, const std::string& inx)
|
|
||||||
{
|
|
||||||
size_t start = inx.find(category);
|
|
||||||
start = inx.find(setting, start) + setting.length() + 3;
|
|
||||||
|
|
||||||
size_t end = inx.find("!", start);
|
|
||||||
|
|
||||||
return inx.substr(start, end-start);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string read_to_string(const bfs::path& path)
|
|
||||||
{
|
|
||||||
bfs::ifstream strstream(path, std::ios::in | std::ios::binary);
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
strstream.seekg(0, std::ios::end);
|
|
||||||
str.resize(strstream.tellg());
|
|
||||||
strstream.seekg(0, std::ios::beg);
|
|
||||||
strstream.read(&str[0], str.size());
|
|
||||||
strstream.close();
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_setting(const std::string& category, const std::string& setting, const std::string& val, std::string& ini)
|
|
||||||
{
|
|
||||||
size_t loc;
|
|
||||||
loc = ini.find("[" + category + "]");
|
|
||||||
|
|
||||||
// If category is not found, create it
|
|
||||||
if(loc == std::string::npos)
|
|
||||||
{
|
|
||||||
loc = ini.size() + 2;
|
|
||||||
ini += ("\r\n[" + category + "]\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc += category.length() +2 +2;
|
|
||||||
ini.insert(loc, setting + "=" + val + "\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FIX(setting) add_setting(category, setting, get_setting(category, setting, inx), ini)
|
|
||||||
|
|
||||||
void bloodmoon_fix_ini(std::string& ini, const bfs::path inxPath)
|
|
||||||
{
|
|
||||||
std::string inx = read_to_string(inxPath);
|
|
||||||
|
|
||||||
// Remove this one setting (the only one actually changed by bloodmoon, as opposed to just adding new ones)
|
|
||||||
size_t start = ini.find("[Weather Blight]");
|
|
||||||
start = ini.find("Ambient Loop Sound ID", start);
|
|
||||||
size_t end = ini.find("\r\n", start) +2;
|
|
||||||
ini.erase(start, end-start);
|
|
||||||
|
|
||||||
std::string category;
|
|
||||||
|
|
||||||
category = "General";
|
|
||||||
{
|
|
||||||
FIX("Werewolf FOV");
|
|
||||||
}
|
|
||||||
category = "Moons";
|
|
||||||
{
|
|
||||||
FIX("Script Color");
|
|
||||||
}
|
|
||||||
category = "Weather";
|
|
||||||
{
|
|
||||||
FIX("Snow Ripples");
|
|
||||||
FIX("Snow Ripple Radius");
|
|
||||||
FIX("Snow Ripples Per Flake");
|
|
||||||
FIX("Snow Ripple Scale");
|
|
||||||
FIX("Snow Ripple Speed");
|
|
||||||
FIX("Snow Gravity Scale");
|
|
||||||
FIX("Snow High Kill");
|
|
||||||
FIX("Snow Low Kill");
|
|
||||||
}
|
|
||||||
category = "Weather Blight";
|
|
||||||
{
|
|
||||||
FIX("Ambient Loop Sound ID");
|
|
||||||
}
|
|
||||||
category = "Weather Snow";
|
|
||||||
{
|
|
||||||
FIX("Sky Sunrise Color");
|
|
||||||
FIX("Sky Day Color");
|
|
||||||
FIX("Sky Sunset Color");
|
|
||||||
FIX("Sky Night Color");
|
|
||||||
FIX("Fog Sunrise Color");
|
|
||||||
FIX("Fog Day Color");
|
|
||||||
FIX("Fog Sunset Color");
|
|
||||||
FIX("Fog Night Color");
|
|
||||||
FIX("Ambient Sunrise Color");
|
|
||||||
FIX("Ambient Day Color");
|
|
||||||
FIX("Ambient Sunset Color");
|
|
||||||
FIX("Ambient Night Color");
|
|
||||||
FIX("Sun Sunrise Color");
|
|
||||||
FIX("Sun Day Color");
|
|
||||||
FIX("Sun Sunset Color");
|
|
||||||
FIX("Sun Night Color");
|
|
||||||
FIX("Sun Disc Sunset Color");
|
|
||||||
FIX("Transition Delta");
|
|
||||||
FIX("Land Fog Day Depth");
|
|
||||||
FIX("Land Fog Night Depth");
|
|
||||||
FIX("Clouds Maximum Percent");
|
|
||||||
FIX("Wind Speed");
|
|
||||||
FIX("Cloud Speed");
|
|
||||||
FIX("Glare View");
|
|
||||||
FIX("Cloud Texture");
|
|
||||||
FIX("Ambient Loop Sound ID");
|
|
||||||
FIX("Snow Threshold");
|
|
||||||
FIX("Snow Diameter");
|
|
||||||
FIX("Snow Height Min");
|
|
||||||
FIX("Snow Height Max");
|
|
||||||
FIX("Snow Entrance Speed");
|
|
||||||
FIX("Max Snowflakes");
|
|
||||||
}
|
|
||||||
category = "Weather Blizzard";
|
|
||||||
{
|
|
||||||
FIX("Sky Sunrise Color");
|
|
||||||
FIX("Sky Day Color");
|
|
||||||
FIX("Sky Sunset Color");
|
|
||||||
FIX("Sky Night Color");
|
|
||||||
FIX("Fog Sunrise Color");
|
|
||||||
FIX("Fog Day Color");
|
|
||||||
FIX("Fog Sunset Color");
|
|
||||||
FIX("Fog Night Color");
|
|
||||||
FIX("Ambient Sunrise Color");
|
|
||||||
FIX("Ambient Day Color");
|
|
||||||
FIX("Ambient Sunset Color");
|
|
||||||
FIX("Ambient Night Color");
|
|
||||||
FIX("Sun Sunrise Color");
|
|
||||||
FIX("Sun Day Color");
|
|
||||||
FIX("Sun Sunset Color");
|
|
||||||
FIX("Sun Night Color");
|
|
||||||
FIX("Sun Disc Sunset Color");
|
|
||||||
FIX("Transition Delta");
|
|
||||||
FIX("Land Fog Day Depth");
|
|
||||||
FIX("Land Fog Night Depth");
|
|
||||||
FIX("Clouds Maximum Percent");
|
|
||||||
FIX("Wind Speed");
|
|
||||||
FIX("Cloud Speed");
|
|
||||||
FIX("Glare View");
|
|
||||||
FIX("Cloud Texture");
|
|
||||||
FIX("Ambient Loop Sound ID");
|
|
||||||
FIX("Storm Threshold");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void fix_ini(const bfs::path& output_dir, bfs::path cdPath, bool tribunal, bool bloodmoon)
|
|
||||||
{
|
|
||||||
bfs::path ini_path = output_dir;
|
|
||||||
ini_path /= "Morrowind.ini";
|
|
||||||
|
|
||||||
std::string ini = read_to_string(ini_path.string());
|
|
||||||
|
|
||||||
if(tribunal)
|
|
||||||
{
|
|
||||||
add_setting("Game Files", "GameFile1", "Tribunal.esm", ini);
|
|
||||||
add_setting("Archives", "Archive 0", "Tribunal.bsa", ini);
|
|
||||||
}
|
|
||||||
if(bloodmoon)
|
|
||||||
{
|
|
||||||
bloodmoon_fix_ini(ini, cdPath / "setup.inx");
|
|
||||||
add_setting("Game Files", "GameFile2", "Bloodmoon.esm", ini);
|
|
||||||
add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini);
|
|
||||||
}
|
|
||||||
|
|
||||||
bfs::ofstream inistream((ini_path));
|
|
||||||
inistream << ini;
|
|
||||||
inistream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void installToPath(const bfs::path& from, const bfs::path& to, bool copy = false)
|
|
||||||
{
|
|
||||||
make_sure_directory_exists(to);
|
|
||||||
|
|
||||||
for ( bfs::directory_iterator end, dir(from); dir != end; ++dir )
|
|
||||||
{
|
|
||||||
if(bfs::is_directory(dir->path()))
|
|
||||||
installToPath(dir->path(), to / dir->path().filename(), copy);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(copy)
|
|
||||||
{
|
|
||||||
bfs::path dest = to / dir->path().filename();
|
|
||||||
if(bfs::exists(dest))
|
|
||||||
bfs::remove_all(dest);
|
|
||||||
bfs::copy_file(dir->path(), dest);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
bfs::rename(dir->path(), to / dir->path().filename());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bfs::path findFile(const bfs::path& in, std::string filename, bool recursive = true)
|
|
||||||
{
|
|
||||||
if(recursive)
|
|
||||||
{
|
|
||||||
for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir )
|
|
||||||
{
|
|
||||||
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
|
|
||||||
return dir->path();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for ( bfs::directory_iterator end, dir(in); dir != end; ++dir )
|
|
||||||
{
|
|
||||||
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
|
|
||||||
return dir->path();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(const bfs::path& in, std::string filename)
|
|
||||||
{
|
|
||||||
for(bfs::directory_iterator end, dir(in); dir != end; ++dir)
|
|
||||||
{
|
|
||||||
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t getTime(const char* time)
|
|
||||||
{
|
|
||||||
struct tm tms;
|
|
||||||
memset(&tms, 0, sizeof(struct tm));
|
|
||||||
strptime(time, "%d %B %Y", &tms);
|
|
||||||
return mktime(&tms);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some cds have cab files which have the Data Files subfolders outside the Data Files folder
|
|
||||||
void install_dfiles_outside(const bfs::path& from, const bfs::path& dFiles)
|
|
||||||
{
|
|
||||||
bfs::path fonts = findFile(from, "fonts", false);
|
|
||||||
if(fonts.string() != "")
|
|
||||||
installToPath(fonts, dFiles / "Fonts");
|
|
||||||
|
|
||||||
bfs::path music = findFile(from, "music", false);
|
|
||||||
if(music.string() != "")
|
|
||||||
installToPath(music, dFiles / "Music");
|
|
||||||
|
|
||||||
bfs::path sound = findFile(from, "sound", false);
|
|
||||||
if(sound.string() != "")
|
|
||||||
installToPath(sound, dFiles / "Sound");
|
|
||||||
|
|
||||||
bfs::path splash = findFile(from, "splash", false);
|
|
||||||
if(splash.string() != "")
|
|
||||||
installToPath(splash, dFiles / "Splash");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::SetMorrowindPath(const std::string& path)
|
|
||||||
{
|
|
||||||
mMorrowindPath = path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::SetTribunalPath(const std::string& path)
|
|
||||||
{
|
|
||||||
mTribunalPath = path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::SetBloodmoonPath(const std::string& path)
|
|
||||||
{
|
|
||||||
mBloodmoonPath = path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::UnshieldThread::SetOutputPath(const std::string& path)
|
|
||||||
{
|
|
||||||
mOutputPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, const char* prefix, int index)
|
|
||||||
{
|
|
||||||
bool success;
|
|
||||||
bfs::path dirname;
|
|
||||||
bfs::path filename;
|
|
||||||
int directory = unshield_file_directory(unshield, index);
|
|
||||||
|
|
||||||
dirname = output_dir;
|
|
||||||
|
|
||||||
if (prefix && prefix[0])
|
|
||||||
dirname /= prefix;
|
|
||||||
|
|
||||||
if (directory >= 0)
|
|
||||||
{
|
|
||||||
const char* tmp = unshield_directory_name(unshield, directory);
|
|
||||||
if (tmp && tmp[0])
|
|
||||||
fill_path(dirname, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
make_sure_directory_exists(dirname);
|
|
||||||
|
|
||||||
filename = dirname;
|
|
||||||
filename /= unshield_file_name(unshield, index);
|
|
||||||
|
|
||||||
emit signalGUI(QString("Extracting: ") + QString(filename.c_str()));
|
|
||||||
|
|
||||||
success = unshield_file_save(unshield, index, filename.c_str());
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
bfs::remove(filename);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::UnshieldThread::extract_cab(const bfs::path& cab, const bfs::path& output_dir, bool extract_ini)
|
|
||||||
{
|
|
||||||
Unshield * unshield;
|
|
||||||
unshield = unshield_open(cab.c_str());
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < unshield_file_group_count(unshield); i++)
|
|
||||||
{
|
|
||||||
UnshieldFileGroup* file_group = unshield_file_group_get(unshield, i);
|
|
||||||
|
|
||||||
for (size_t j = file_group->first_file; j <= file_group->last_file; j++)
|
|
||||||
{
|
|
||||||
if (unshield_file_is_valid(unshield, j))
|
|
||||||
extract_file(unshield, output_dir, file_group->name, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unshield_close(unshield);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::extract()
|
|
||||||
{
|
|
||||||
bfs::path outputDataFilesDir = mOutputPath;
|
|
||||||
outputDataFilesDir /= "Data Files";
|
|
||||||
bfs::path extractPath = mOutputPath;
|
|
||||||
extractPath /= "extract-temp";
|
|
||||||
|
|
||||||
if(!mMorrowindDone && mMorrowindPath.string().length() > 0)
|
|
||||||
{
|
|
||||||
mMorrowindDone = true;
|
|
||||||
|
|
||||||
bfs::path mwExtractPath = extractPath / "morrowind";
|
|
||||||
extract_cab(mMorrowindPath, mwExtractPath, true);
|
|
||||||
|
|
||||||
bfs::path dFilesDir = findFile(mwExtractPath, "morrowind.esm").parent_path();
|
|
||||||
|
|
||||||
installToPath(dFilesDir, outputDataFilesDir);
|
|
||||||
|
|
||||||
install_dfiles_outside(mwExtractPath, outputDataFilesDir);
|
|
||||||
|
|
||||||
// Videos are often kept uncompressed on the cd
|
|
||||||
bfs::path videosPath = findFile(mMorrowindPath.parent_path(), "video", false);
|
|
||||||
if(videosPath.string() != "")
|
|
||||||
{
|
|
||||||
emit signalGUI(QString("Installing Videos..."));
|
|
||||||
installToPath(videosPath, outputDataFilesDir / "Video", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bfs::path cdDFiles = findFile(mMorrowindPath.parent_path(), "data files", false);
|
|
||||||
if(cdDFiles.string() != "")
|
|
||||||
{
|
|
||||||
emit signalGUI(QString("Installing Uncompressed Data files from CD..."));
|
|
||||||
installToPath(cdDFiles, outputDataFilesDir, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bfs::rename(findFile(mwExtractPath, "morrowind.ini"), outputDataFilesDir / "Morrowind.ini");
|
|
||||||
|
|
||||||
mTribunalDone = contains(outputDataFilesDir, "tribunal.esm");
|
|
||||||
mBloodmoonDone = contains(outputDataFilesDir, "bloodmoon.esm");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(!mTribunalDone && mTribunalPath.string().length() > 0)
|
|
||||||
{
|
|
||||||
mTribunalDone = true;
|
|
||||||
|
|
||||||
bfs::path tbExtractPath = extractPath / "tribunal";
|
|
||||||
extract_cab(mTribunalPath, tbExtractPath, true);
|
|
||||||
|
|
||||||
bfs::path dFilesDir = findFile(tbExtractPath, "tribunal.esm").parent_path();
|
|
||||||
|
|
||||||
installToPath(dFilesDir, outputDataFilesDir);
|
|
||||||
|
|
||||||
install_dfiles_outside(tbExtractPath, outputDataFilesDir);
|
|
||||||
|
|
||||||
// Mt GOTY CD has Sounds in a seperate folder from the rest of the data files
|
|
||||||
bfs::path soundsPath = findFile(tbExtractPath, "sounds", false);
|
|
||||||
if(soundsPath.string() != "")
|
|
||||||
installToPath(soundsPath, outputDataFilesDir / "Sounds");
|
|
||||||
|
|
||||||
bfs::path cdDFiles = findFile(mTribunalPath.parent_path(), "data files", false);
|
|
||||||
if(cdDFiles.string() != "")
|
|
||||||
{
|
|
||||||
emit signalGUI(QString("Installing Uncompressed Data files from CD..."));
|
|
||||||
installToPath(cdDFiles, outputDataFilesDir, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBloodmoonDone = contains(outputDataFilesDir, "bloodmoon.esm");
|
|
||||||
|
|
||||||
fix_ini(outputDataFilesDir, bfs::path(mTribunalPath).parent_path(), mTribunalDone, mBloodmoonDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(!mBloodmoonDone && mBloodmoonPath.string().length() > 0)
|
|
||||||
{
|
|
||||||
mBloodmoonDone = true;
|
|
||||||
|
|
||||||
bfs::path bmExtractPath = extractPath / "bloodmoon";
|
|
||||||
extract_cab(mBloodmoonPath, bmExtractPath, true);
|
|
||||||
|
|
||||||
bfs::path dFilesDir = findFile(bmExtractPath, "bloodmoon.esm").parent_path();
|
|
||||||
|
|
||||||
installToPath(dFilesDir, outputDataFilesDir);
|
|
||||||
|
|
||||||
install_dfiles_outside(bmExtractPath, outputDataFilesDir);
|
|
||||||
|
|
||||||
// My GOTY CD contains a folder within cab files called Tribunal patch,
|
|
||||||
// which contains Tribunal.esm
|
|
||||||
bfs::path tbPatchPath = findFile(bmExtractPath, "tribunal.esm");
|
|
||||||
if(tbPatchPath.string() != "")
|
|
||||||
bfs::rename(tbPatchPath, outputDataFilesDir / "Tribunal.esm");
|
|
||||||
|
|
||||||
bfs::path cdDFiles = findFile(mBloodmoonPath.parent_path(), "data files", false);
|
|
||||||
if(cdDFiles.string() != "")
|
|
||||||
{
|
|
||||||
emit signalGUI(QString("Installing Uncompressed Data files from CD..."));
|
|
||||||
installToPath(cdDFiles, outputDataFilesDir, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
fix_ini(outputDataFilesDir, bfs::path(mBloodmoonPath).parent_path(), false, mBloodmoonDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::UnshieldThread::Done()
|
|
||||||
{
|
|
||||||
// Get rid of unnecessary files
|
|
||||||
bfs::remove_all(mOutputPath / "extract-temp");
|
|
||||||
|
|
||||||
// Set modified time to release dates, to preserve load order
|
|
||||||
if(mMorrowindDone)
|
|
||||||
bfs::last_write_time(findFile(mOutputPath, "morrowind.esm"), getTime("1 May 2002"));
|
|
||||||
|
|
||||||
if(mTribunalDone)
|
|
||||||
bfs::last_write_time(findFile(mOutputPath, "tribunal.esm"), getTime("6 November 2002"));
|
|
||||||
|
|
||||||
if(mBloodmoonDone)
|
|
||||||
bfs::last_write_time(findFile(mOutputPath, "bloodmoon.esm"), getTime("3 June 2003"));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Launcher::UnshieldThread::GetMWEsmPath()
|
|
||||||
{
|
|
||||||
return findFile(mOutputPath / "Data Files", "morrowind.esm").string();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::TribunalDone()
|
|
||||||
{
|
|
||||||
return mTribunalDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::UnshieldThread::BloodmoonDone()
|
|
||||||
{
|
|
||||||
return mBloodmoonDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::UnshieldThread::run()
|
|
||||||
{
|
|
||||||
extract();
|
|
||||||
emit close();
|
|
||||||
}
|
|
||||||
|
|
||||||
Launcher::UnshieldThread::UnshieldThread()
|
|
||||||
{
|
|
||||||
unshield_set_log_level(0);
|
|
||||||
mMorrowindDone = false;
|
|
||||||
mTribunalDone = false;
|
|
||||||
mBloodmoonDone = false;
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
#ifndef UNSHIELD_THREAD_H
|
|
||||||
#define UNSHIELD_THREAD_H
|
|
||||||
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#include <libunshield.h>
|
|
||||||
|
|
||||||
namespace Launcher
|
|
||||||
{
|
|
||||||
class UnshieldThread : public QThread
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool SetMorrowindPath(const std::string& path);
|
|
||||||
bool SetTribunalPath(const std::string& path);
|
|
||||||
bool SetBloodmoonPath(const std::string& path);
|
|
||||||
|
|
||||||
void SetOutputPath(const std::string& path);
|
|
||||||
|
|
||||||
bool extract();
|
|
||||||
|
|
||||||
bool TribunalDone();
|
|
||||||
bool BloodmoonDone();
|
|
||||||
|
|
||||||
void Done();
|
|
||||||
|
|
||||||
std::string GetMWEsmPath();
|
|
||||||
|
|
||||||
UnshieldThread();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void extract_cab(const boost::filesystem::path& cab, const boost::filesystem::path& output_dir, bool extract_ini = false);
|
|
||||||
bool extract_file(Unshield* unshield, boost::filesystem::path output_dir, const char* prefix, int index);
|
|
||||||
|
|
||||||
boost::filesystem::path mMorrowindPath;
|
|
||||||
boost::filesystem::path mTribunalPath;
|
|
||||||
boost::filesystem::path mBloodmoonPath;
|
|
||||||
|
|
||||||
bool mMorrowindDone;
|
|
||||||
bool mTribunalDone;
|
|
||||||
bool mBloodmoonDone;
|
|
||||||
|
|
||||||
boost::filesystem::path mOutputPath;
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void signalGUI(QString);
|
|
||||||
void close();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,258 +0,0 @@
|
||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "checkablemessagebox.hpp"
|
|
||||||
|
|
||||||
#include <QVariant>
|
|
||||||
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QAction>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QButtonGroup>
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QDialog>
|
|
||||||
#include <QDialogButtonBox>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QHeaderView>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QSpacerItem>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\class Utils::CheckableMessageBox
|
|
||||||
|
|
||||||
\brief A messagebox suitable for questions with a
|
|
||||||
"Do not ask me again" checkbox.
|
|
||||||
|
|
||||||
Emulates the QMessageBox API with
|
|
||||||
static conveniences. The message label can open external URLs.
|
|
||||||
*/
|
|
||||||
Launcher::CheckableMessageBoxPrivate::CheckableMessageBoxPrivate(QDialog *q)
|
|
||||||
: clickedButton(0)
|
|
||||||
{
|
|
||||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
|
||||||
|
|
||||||
pixmapLabel = new QLabel(q);
|
|
||||||
sizePolicy.setHorizontalStretch(0);
|
|
||||||
sizePolicy.setVerticalStretch(0);
|
|
||||||
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
|
|
||||||
pixmapLabel->setSizePolicy(sizePolicy);
|
|
||||||
pixmapLabel->setVisible(false);
|
|
||||||
|
|
||||||
QSpacerItem *pixmapSpacer =
|
|
||||||
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
|
||||||
|
|
||||||
messageLabel = new QLabel(q);
|
|
||||||
messageLabel->setMinimumSize(QSize(300, 0));
|
|
||||||
messageLabel->setWordWrap(true);
|
|
||||||
messageLabel->setOpenExternalLinks(true);
|
|
||||||
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
|
|
||||||
|
|
||||||
QSpacerItem *checkBoxRightSpacer =
|
|
||||||
new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
|
||||||
QSpacerItem *buttonSpacer =
|
|
||||||
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
|
|
||||||
checkBox = new QCheckBox(q);
|
|
||||||
checkBox->setText(Launcher::CheckableMessageBox::tr("Do not ask again"));
|
|
||||||
|
|
||||||
buttonBox = new QDialogButtonBox(q);
|
|
||||||
buttonBox->setOrientation(Qt::Horizontal);
|
|
||||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
|
||||||
|
|
||||||
QVBoxLayout *verticalLayout = new QVBoxLayout();
|
|
||||||
verticalLayout->addWidget(pixmapLabel);
|
|
||||||
verticalLayout->addItem(pixmapSpacer);
|
|
||||||
|
|
||||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
|
||||||
horizontalLayout_2->addLayout(verticalLayout);
|
|
||||||
horizontalLayout_2->addWidget(messageLabel);
|
|
||||||
|
|
||||||
QHBoxLayout *horizontalLayout = new QHBoxLayout();
|
|
||||||
horizontalLayout->addWidget(checkBox);
|
|
||||||
horizontalLayout->addItem(checkBoxRightSpacer);
|
|
||||||
|
|
||||||
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
|
|
||||||
verticalLayout_2->addLayout(horizontalLayout_2);
|
|
||||||
verticalLayout_2->addLayout(horizontalLayout);
|
|
||||||
verticalLayout_2->addItem(buttonSpacer);
|
|
||||||
verticalLayout_2->addWidget(buttonBox);
|
|
||||||
}
|
|
||||||
|
|
||||||
Launcher::CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
|
|
||||||
QDialog(parent),
|
|
||||||
d(new Launcher::CheckableMessageBoxPrivate(this))
|
|
||||||
{
|
|
||||||
setModal(true);
|
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
||||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
|
||||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
|
||||||
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
|
|
||||||
SLOT(slotClicked(QAbstractButton*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Launcher::CheckableMessageBox::~CheckableMessageBox()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::slotClicked(QAbstractButton *b)
|
|
||||||
{
|
|
||||||
d->clickedButton = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
QAbstractButton *Launcher::CheckableMessageBox::clickedButton() const
|
|
||||||
{
|
|
||||||
return d->clickedButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDialogButtonBox::StandardButton Launcher::CheckableMessageBox::clickedStandardButton() const
|
|
||||||
{
|
|
||||||
if (d->clickedButton)
|
|
||||||
return d->buttonBox->standardButton(d->clickedButton);
|
|
||||||
return QDialogButtonBox::NoButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Launcher::CheckableMessageBox::text() const
|
|
||||||
{
|
|
||||||
return d->messageLabel->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setText(const QString &t)
|
|
||||||
{
|
|
||||||
d->messageLabel->setText(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap Launcher::CheckableMessageBox::iconPixmap() const
|
|
||||||
{
|
|
||||||
if (const QPixmap *p = d->pixmapLabel->pixmap())
|
|
||||||
return QPixmap(*p);
|
|
||||||
return QPixmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setIconPixmap(const QPixmap &p)
|
|
||||||
{
|
|
||||||
d->pixmapLabel->setPixmap(p);
|
|
||||||
d->pixmapLabel->setVisible(!p.isNull());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::CheckableMessageBox::isChecked() const
|
|
||||||
{
|
|
||||||
return d->checkBox->isChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setChecked(bool s)
|
|
||||||
{
|
|
||||||
d->checkBox->setChecked(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Launcher::CheckableMessageBox::checkBoxText() const
|
|
||||||
{
|
|
||||||
return d->checkBox->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setCheckBoxText(const QString &t)
|
|
||||||
{
|
|
||||||
d->checkBox->setText(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::CheckableMessageBox::isCheckBoxVisible() const
|
|
||||||
{
|
|
||||||
return d->checkBox->isVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setCheckBoxVisible(bool v)
|
|
||||||
{
|
|
||||||
d->checkBox->setVisible(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDialogButtonBox::StandardButtons Launcher::CheckableMessageBox::standardButtons() const
|
|
||||||
{
|
|
||||||
return d->buttonBox->standardButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
|
|
||||||
{
|
|
||||||
d->buttonBox->setStandardButtons(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton *Launcher::CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
|
|
||||||
{
|
|
||||||
return d->buttonBox->button(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton *Launcher::CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
|
|
||||||
{
|
|
||||||
return d->buttonBox->addButton(text, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDialogButtonBox::StandardButton Launcher::CheckableMessageBox::defaultButton() const
|
|
||||||
{
|
|
||||||
foreach (QAbstractButton *b, d->buttonBox->buttons())
|
|
||||||
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
|
|
||||||
if (pb->isDefault())
|
|
||||||
return d->buttonBox->standardButton(pb);
|
|
||||||
return QDialogButtonBox::NoButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
|
|
||||||
{
|
|
||||||
if (QPushButton *b = d->buttonBox->button(s)) {
|
|
||||||
b->setDefault(true);
|
|
||||||
b->setFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QDialogButtonBox::StandardButton
|
|
||||||
Launcher::CheckableMessageBox::question(QWidget *parent,
|
|
||||||
const QString &title,
|
|
||||||
const QString &question,
|
|
||||||
const QString &checkBoxText,
|
|
||||||
bool *checkBoxSetting,
|
|
||||||
QDialogButtonBox::StandardButtons buttons,
|
|
||||||
QDialogButtonBox::StandardButton defaultButton)
|
|
||||||
{
|
|
||||||
CheckableMessageBox mb(parent);
|
|
||||||
mb.setWindowTitle(title);
|
|
||||||
mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
|
|
||||||
mb.setText(question);
|
|
||||||
mb.setCheckBoxText(checkBoxText);
|
|
||||||
mb.setChecked(*checkBoxSetting);
|
|
||||||
mb.setStandardButtons(buttons);
|
|
||||||
mb.setDefaultButton(defaultButton);
|
|
||||||
mb.exec();
|
|
||||||
*checkBoxSetting = mb.isChecked();
|
|
||||||
return mb.clickedStandardButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMessageBox::StandardButton Launcher::CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
|
|
||||||
{
|
|
||||||
return static_cast<QMessageBox::StandardButton>(int(db));
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef CHECKABLEMESSAGEBOX_HPP
|
|
||||||
#define CHECKABLEMESSAGEBOX_HPP
|
|
||||||
|
|
||||||
#include <QDialogButtonBox>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QDialog>
|
|
||||||
|
|
||||||
class QCheckBox;
|
|
||||||
|
|
||||||
namespace Launcher
|
|
||||||
{
|
|
||||||
class CheckableMessageBoxPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
QLabel *pixmapLabel;
|
|
||||||
QLabel *messageLabel;
|
|
||||||
QCheckBox *checkBox;
|
|
||||||
QDialogButtonBox *buttonBox;
|
|
||||||
QAbstractButton *clickedButton;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CheckableMessageBoxPrivate(QDialog *q);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CheckableMessageBox : public QDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(QString text READ text WRITE setText)
|
|
||||||
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
|
|
||||||
Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
|
|
||||||
Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
|
|
||||||
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
|
|
||||||
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CheckableMessageBox(QWidget *parent);
|
|
||||||
virtual ~CheckableMessageBox();
|
|
||||||
|
|
||||||
static QDialogButtonBox::StandardButton
|
|
||||||
question(QWidget *parent,
|
|
||||||
const QString &title,
|
|
||||||
const QString &question,
|
|
||||||
const QString &checkBoxText,
|
|
||||||
bool *checkBoxSetting,
|
|
||||||
QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No,
|
|
||||||
QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No);
|
|
||||||
|
|
||||||
QString text() const;
|
|
||||||
void setText(const QString &);
|
|
||||||
|
|
||||||
bool isChecked() const;
|
|
||||||
void setChecked(bool s);
|
|
||||||
|
|
||||||
QString checkBoxText() const;
|
|
||||||
void setCheckBoxText(const QString &);
|
|
||||||
|
|
||||||
bool isCheckBoxVisible() const;
|
|
||||||
void setCheckBoxVisible(bool);
|
|
||||||
|
|
||||||
QDialogButtonBox::StandardButtons standardButtons() const;
|
|
||||||
void setStandardButtons(QDialogButtonBox::StandardButtons s);
|
|
||||||
QPushButton *button(QDialogButtonBox::StandardButton b) const;
|
|
||||||
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
|
|
||||||
|
|
||||||
QDialogButtonBox::StandardButton defaultButton() const;
|
|
||||||
void setDefaultButton(QDialogButtonBox::StandardButton s);
|
|
||||||
|
|
||||||
// See static QMessageBox::standardPixmap()
|
|
||||||
QPixmap iconPixmap() const;
|
|
||||||
void setIconPixmap (const QPixmap &p);
|
|
||||||
|
|
||||||
// Query the result
|
|
||||||
QAbstractButton *clickedButton() const;
|
|
||||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
|
||||||
|
|
||||||
// Conversion convenience
|
|
||||||
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotClicked(QAbstractButton *b);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CheckableMessageBoxPrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif // CHECKABLEMESSAGEBOX_HPP
|
|
|
@ -47,13 +47,13 @@ void ProfilesComboBox::setEditEnabled(bool editable)
|
||||||
|
|
||||||
void ProfilesComboBox::slotTextChanged(const QString &text)
|
void ProfilesComboBox::slotTextChanged(const QString &text)
|
||||||
{
|
{
|
||||||
QPalette *palette = new QPalette();
|
QPalette palette;
|
||||||
palette->setColor(QPalette::Text,Qt::red);
|
palette.setColor(QPalette::Text,Qt::red);
|
||||||
|
|
||||||
int index = findText(text);
|
int index = findText(text);
|
||||||
|
|
||||||
if (text.isEmpty() || (index != -1 && index != currentIndex())) {
|
if (text.isEmpty() || (index != -1 && index != currentIndex())) {
|
||||||
lineEdit()->setPalette(*palette);
|
lineEdit()->setPalette(palette);
|
||||||
} else {
|
} else {
|
||||||
lineEdit()->setPalette(QApplication::palette());
|
lineEdit()->setPalette(QApplication::palette());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,15 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
|
||||||
mButtonBox->addButton(QDialogButtonBox::Cancel);
|
mButtonBox->addButton(QDialogButtonBox::Cancel);
|
||||||
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
|
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
|
||||||
|
|
||||||
// Line edit
|
|
||||||
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
|
||||||
mLineEdit = new DialogLineEdit(this);
|
|
||||||
mLineEdit->setValidator(validator);
|
|
||||||
mLineEdit->setCompleter(0);
|
|
||||||
|
|
||||||
QLabel *label = new QLabel(this);
|
QLabel *label = new QLabel(this);
|
||||||
label->setText(text);
|
label->setText(text);
|
||||||
|
|
||||||
|
// Line edit
|
||||||
|
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||||
|
mLineEdit = new LineEdit(this);
|
||||||
|
mLineEdit->setValidator(validator);
|
||||||
|
mLineEdit->setCompleter(0);
|
||||||
|
|
||||||
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
|
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
|
||||||
dialogLayout->addWidget(label);
|
dialogLayout->addWidget(label);
|
||||||
dialogLayout->addWidget(mLineEdit);
|
dialogLayout->addWidget(mLineEdit);
|
||||||
|
@ -41,8 +41,10 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
|
||||||
|
|
||||||
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||||
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||||
connect(mLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateOkButton(QString)));
|
}
|
||||||
|
|
||||||
|
Launcher::TextInputDialog::~TextInputDialog()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int Launcher::TextInputDialog::exec()
|
int Launcher::TextInputDialog::exec()
|
||||||
|
@ -52,36 +54,18 @@ int Launcher::TextInputDialog::exec()
|
||||||
return QDialog::exec();
|
return QDialog::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Launcher::TextInputDialog::getText() const
|
void Launcher::TextInputDialog::setOkButtonEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
return mLineEdit->text();
|
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
||||||
}
|
okButton->setEnabled(enabled);
|
||||||
|
|
||||||
void Launcher::TextInputDialog::slotUpdateOkButton(QString text)
|
QPalette palette;
|
||||||
{
|
palette.setColor(QPalette::Text, Qt::red);
|
||||||
bool enabled = !(text.isEmpty());
|
|
||||||
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(enabled);
|
|
||||||
|
|
||||||
if (enabled)
|
if (enabled) {
|
||||||
mLineEdit->setPalette(QApplication::palette());
|
mLineEdit->setPalette(QApplication::palette());
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
// Existing profile name, make the text red
|
// Existing profile name, make the text red
|
||||||
QPalette *palette = new QPalette();
|
mLineEdit->setPalette(palette);
|
||||||
palette->setColor(QPalette::Text,Qt::red);
|
|
||||||
mLineEdit->setPalette(*palette);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Launcher::TextInputDialog::DialogLineEdit::DialogLineEdit (QWidget *parent) :
|
|
||||||
LineEdit (parent)
|
|
||||||
{
|
|
||||||
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
|
||||||
|
|
||||||
setObjectName(QString("LineEdit"));
|
|
||||||
setStyleSheet(QString("LineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
|
|
||||||
QSize msz = minimumSizeHint();
|
|
||||||
setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2),
|
|
||||||
qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,26 +13,20 @@ namespace Launcher
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
class DialogLineEdit : public LineEdit
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit DialogLineEdit (QWidget *parent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogLineEdit *mLineEdit;
|
|
||||||
QDialogButtonBox *mButtonBox;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0);
|
explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0);
|
||||||
~TextInputDialog () {}
|
~TextInputDialog ();
|
||||||
|
|
||||||
QString getText() const;
|
inline LineEdit *lineEdit() { return mLineEdit; }
|
||||||
|
void setOkButtonEnabled(bool enabled);
|
||||||
|
|
||||||
int exec();
|
int exec();
|
||||||
|
|
||||||
private slots:
|
private:
|
||||||
void slotUpdateOkButton(QString text);
|
|
||||||
|
QDialogButtonBox *mButtonBox;
|
||||||
|
LineEdit *mLineEdit;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,16 @@ set(MWINIIMPORT_HEADER
|
||||||
|
|
||||||
source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER})
|
source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER})
|
||||||
|
|
||||||
add_executable(mwiniimport
|
add_executable(openmw-iniimporter
|
||||||
${MWINIIMPORT}
|
${MWINIIMPORT}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(mwiniimport
|
target_link_libraries(openmw-iniimporter
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BUILD_WITH_CODE_COVERAGE)
|
if (BUILD_WITH_CODE_COVERAGE)
|
||||||
add_definitions (--coverage)
|
add_definitions (--coverage)
|
||||||
target_link_libraries(mwiniimport gcov)
|
target_link_libraries(openmw-iniimporter gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -8,13 +8,15 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/version.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
namespace bfs = boost::filesystem;
|
namespace bfs = boost::filesystem;
|
||||||
|
|
||||||
MwIniImporter::MwIniImporter()
|
MwIniImporter::MwIniImporter()
|
||||||
: mVerbose(false)
|
: mVerbose(false)
|
||||||
|
, mEncoding(ToUTF8::WINDOWS_1250)
|
||||||
{
|
{
|
||||||
const char *map[][2] =
|
const char *map[][2] =
|
||||||
{
|
{
|
||||||
|
@ -659,7 +661,7 @@ std::string MwIniImporter::numberToString(int n) {
|
||||||
return str.str();
|
return str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const {
|
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const {
|
||||||
std::cout << "load ini file: " << filename << std::endl;
|
std::cout << "load ini file: " << filename << std::endl;
|
||||||
|
|
||||||
std::string section("");
|
std::string section("");
|
||||||
|
@ -709,8 +711,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
multistrmap::iterator it;
|
if(map.find(key) == map.end()) {
|
||||||
if((it = map.find(key)) == map.end()) {
|
|
||||||
map.insert( std::make_pair (key, std::vector<std::string>() ) );
|
map.insert( std::make_pair (key, std::vector<std::string>() ) );
|
||||||
}
|
}
|
||||||
map[key].push_back(value);
|
map[key].push_back(value);
|
||||||
|
@ -719,7 +720,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) {
|
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) {
|
||||||
std::cout << "load cfg file: " << filename << std::endl;
|
std::cout << "load cfg file: " << filename << std::endl;
|
||||||
|
|
||||||
MwIniImporter::multistrmap map;
|
MwIniImporter::multistrmap map;
|
||||||
|
@ -746,8 +747,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filenam
|
||||||
std::string key(line.substr(0,pos));
|
std::string key(line.substr(0,pos));
|
||||||
std::string value(line.substr(pos+1));
|
std::string value(line.substr(pos+1));
|
||||||
|
|
||||||
multistrmap::iterator it;
|
if(map.find(key) == map.end()) {
|
||||||
if((it = map.find(key)) == map.end()) {
|
|
||||||
map.insert( std::make_pair (key, std::vector<std::string>() ) );
|
map.insert( std::make_pair (key, std::vector<std::string>() ) );
|
||||||
}
|
}
|
||||||
map[key].push_back(value);
|
map[key].push_back(value);
|
||||||
|
@ -826,10 +826,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const {
|
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const {
|
||||||
std::vector<std::string> contentFiles;
|
std::vector<std::pair<std::time_t, std::string> > contentFiles;
|
||||||
std::string baseGameFile("Game Files:GameFile");
|
std::string baseGameFile("Game Files:GameFile");
|
||||||
std::string gameFile("");
|
std::string gameFile("");
|
||||||
|
std::time_t defaultTime = 0;
|
||||||
|
|
||||||
|
// assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini
|
||||||
|
const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files");
|
||||||
|
|
||||||
multistrmap::const_iterator it = ini.begin();
|
multistrmap::const_iterator it = ini.begin();
|
||||||
for(int i=0; it != ini.end(); i++) {
|
for(int i=0; it != ini.end(); i++) {
|
||||||
|
@ -846,18 +850,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co
|
||||||
Misc::StringUtils::toLower(filetype);
|
Misc::StringUtils::toLower(filetype);
|
||||||
|
|
||||||
if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) {
|
if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) {
|
||||||
contentFiles.push_back(*entry);
|
boost::filesystem::path filepath(gameFilesDir);
|
||||||
|
filepath /= *entry;
|
||||||
|
contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gameFile = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.erase("content");
|
cfg.erase("content");
|
||||||
cfg.insert( std::make_pair("content", std::vector<std::string>() ) );
|
cfg.insert( std::make_pair("content", std::vector<std::string>() ) );
|
||||||
|
|
||||||
for(std::vector<std::string>::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
|
// this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed.
|
||||||
cfg["content"].push_back(*it);
|
sort(contentFiles.begin(), contentFiles.end());
|
||||||
|
for(std::vector<std::pair<std::time_t, std::string> >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
|
||||||
|
cfg["content"].push_back(it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,3 +880,27 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding)
|
||||||
{
|
{
|
||||||
mEncoding = encoding;
|
mEncoding = encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime)
|
||||||
|
{
|
||||||
|
std::time_t writeTime(defaultTime);
|
||||||
|
if (boost::filesystem::exists(filename))
|
||||||
|
{
|
||||||
|
// FixMe: remove #if when Boost dependency for Linux builds updated
|
||||||
|
// This allows Linux to build until then
|
||||||
|
#if (BOOST_VERSION >= 104800)
|
||||||
|
// need to resolve any symlinks so that we get time of file, not symlink
|
||||||
|
boost::filesystem::path resolved = boost::filesystem::canonical(filename);
|
||||||
|
#else
|
||||||
|
boost::filesystem::path resolved = filename;
|
||||||
|
#endif
|
||||||
|
writeTime = boost::filesystem::last_write_time(resolved);
|
||||||
|
std::cout << "content file: " << resolved << " timestamp = (" << writeTime <<
|
||||||
|
") " << asctime(localtime(&writeTime)) << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "content file: " << filename << " not found" << std::endl;
|
||||||
|
}
|
||||||
|
return writeTime;
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
|
@ -17,17 +18,22 @@ class MwIniImporter {
|
||||||
MwIniImporter();
|
MwIniImporter();
|
||||||
void setInputEncoding(const ToUTF8::FromType& encoding);
|
void setInputEncoding(const ToUTF8::FromType& encoding);
|
||||||
void setVerbose(bool verbose);
|
void setVerbose(bool verbose);
|
||||||
multistrmap loadIniFile(const std::string& filename) const;
|
multistrmap loadIniFile(const boost::filesystem::path& filename) const;
|
||||||
static multistrmap loadCfgFile(const std::string& filename);
|
static multistrmap loadCfgFile(const boost::filesystem::path& filename);
|
||||||
void merge(multistrmap &cfg, const multistrmap &ini) const;
|
void merge(multistrmap &cfg, const multistrmap &ini) const;
|
||||||
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
|
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
|
||||||
void importGameFiles(multistrmap &cfg, const multistrmap &ini) const;
|
void importGameFiles(multistrmap &cfg, const multistrmap &ini,
|
||||||
|
const boost::filesystem::path& iniFilename) const;
|
||||||
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
|
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
|
||||||
static void writeToFile(std::ostream &out, const multistrmap &cfg);
|
static void writeToFile(std::ostream &out, const multistrmap &cfg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
|
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
|
||||||
static std::string numberToString(int n);
|
static std::string numberToString(int n);
|
||||||
|
|
||||||
|
/// \return file's "last modified time", used in original MW to determine plug-in load order
|
||||||
|
static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime);
|
||||||
|
|
||||||
bool mVerbose;
|
bool mVerbose;
|
||||||
strmap mMergeMap;
|
strmap mMergeMap;
|
||||||
std::vector<std::string> mMergeFallback;
|
std::vector<std::string> mMergeFallback;
|
||||||
|
|
|
@ -37,6 +37,8 @@ public:
|
||||||
char **get() const { return const_cast<char **>(argv); }
|
char **get() const { return const_cast<char **>(argv); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
utf8argv(const utf8argv&);
|
||||||
|
utf8argv& operator=(const utf8argv&);
|
||||||
|
|
||||||
const char **argv;
|
const char **argv;
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
@ -54,7 +56,10 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||||
char **argv = converter.get();
|
char **argv = converter.get();
|
||||||
boost::filesystem::path::imbue(boost::locale::generator().generate(""));
|
boost::filesystem::path::imbue(boost::locale::generator().generate(""));
|
||||||
#endif
|
#endif
|
||||||
bpo::options_description desc("Syntax: mwiniimporter <options> inifile configfile\nAllowed options");
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bpo::options_description desc("Syntax: openmw-iniimporter <options> inifile configfile\nAllowed options");
|
||||||
bpo::positional_options_description p_desc;
|
bpo::positional_options_description p_desc;
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help,h", "produce help message")
|
("help,h", "produce help message")
|
||||||
|
@ -74,25 +79,12 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||||
|
|
||||||
bpo::variables_map vm;
|
bpo::variables_map vm;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
||||||
.options(desc)
|
.options(desc)
|
||||||
.positional(p_desc)
|
.positional(p_desc)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
bpo::store(parsed, vm);
|
bpo::store(parsed, vm);
|
||||||
}
|
|
||||||
catch(boost::program_options::unknown_option & x)
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch(boost::program_options::invalid_command_line_syntax & x)
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
|
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
|
||||||
std::cout << desc;
|
std::cout << desc;
|
||||||
|
@ -101,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||||
|
|
||||||
bpo::notify(vm);
|
bpo::notify(vm);
|
||||||
|
|
||||||
std::string iniFile = vm["ini"].as<std::string>();
|
boost::filesystem::path iniFile(vm["ini"].as<std::string>());
|
||||||
std::string cfgFile = vm["cfg"].as<std::string>();
|
boost::filesystem::path cfgFile(vm["cfg"].as<std::string>());
|
||||||
|
|
||||||
// if no output is given, write back to cfg file
|
// if no output is given, write back to cfg file
|
||||||
std::string outputFile(vm["output"].as<std::string>());
|
std::string outputFile(vm["output"].as<std::string>());
|
||||||
|
@ -131,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||||
importer.mergeFallback(cfg, ini);
|
importer.mergeFallback(cfg, ini);
|
||||||
|
|
||||||
if(vm.count("game-files")) {
|
if(vm.count("game-files")) {
|
||||||
importer.importGameFiles(cfg, ini);
|
importer.importGameFiles(cfg, ini, iniFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!vm.count("no-archives")) {
|
if(!vm.count("no-archives")) {
|
||||||
|
@ -141,6 +133,10 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||||
std::cout << "write to: " << outputFile << std::endl;
|
std::cout << "write to: " << outputFile << std::endl;
|
||||||
bfs::ofstream file((bfs::path(outputFile)));
|
bfs::ofstream file((bfs::path(outputFile)));
|
||||||
importer.writeToFile(file, cfg);
|
importer.writeToFile(file, cfg);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
set (OPENCS_SRC main.cpp)
|
set (OPENCS_SRC main.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/files/windows/opencs.rc
|
||||||
|
)
|
||||||
|
|
||||||
opencs_units (. editor)
|
opencs_units (. editor)
|
||||||
|
|
||||||
set (CMAKE_BUILD_TYPE DEBUG)
|
|
||||||
|
|
||||||
opencs_units (model/doc
|
opencs_units (model/doc
|
||||||
document operation saving documentmanager loader
|
document operation saving documentmanager loader runner
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/doc
|
opencs_units_noqt (model/doc
|
||||||
stage savingstate savingstages
|
stage savingstate savingstages blacklist messages
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (model/doc
|
opencs_hdrs_noqt (model/doc
|
||||||
|
@ -24,13 +24,13 @@ opencs_units (model/world
|
||||||
|
|
||||||
|
|
||||||
opencs_units_noqt (model/world
|
opencs_units_noqt (model/world
|
||||||
nestedtablewrapper universalid record commands columnbase scriptcontext cell refidcollection
|
universalid record commands columnbase scriptcontext cell refidcollection
|
||||||
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection
|
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
|
||||||
tablemimedata cellcoordinates cellselection resources resourcesmanager nestedadaptors
|
pathgrid landtexture land nestedtablewrapper nestedadaptors
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (model/world
|
opencs_hdrs_noqt (model/world
|
||||||
columnimp idcollection collection info
|
columnimp idcollection collection info subcellcollection
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,13 +40,13 @@ opencs_units (model/tools
|
||||||
|
|
||||||
opencs_units_noqt (model/tools
|
opencs_units_noqt (model/tools
|
||||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||||
birthsigncheck spellcheck referenceablecheck scriptcheck
|
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
opencs_units (view/doc
|
opencs_units (view/doc
|
||||||
viewmanager view operations operation subview startup filedialog newgame
|
viewmanager view operations operation subview startup filedialog newgame
|
||||||
filewidget adjusterwidget loader
|
filewidget adjusterwidget loader globaldebugprofilemenu runlogsubview
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,25 +67,31 @@ opencs_units (view/world
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
||||||
scripthighlighter idvalidator dialoguecreator
|
scripthighlighter idvalidator dialoguecreator physicssystem
|
||||||
|
)
|
||||||
|
|
||||||
|
opencs_units (view/widget
|
||||||
|
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
|
||||||
|
scenetooltoggle2
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units (view/render
|
opencs_units (view/render
|
||||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||||
previewwidget
|
previewwidget editmode
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/render
|
opencs_units_noqt (view/render
|
||||||
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
|
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
|
||||||
lightingbright object cell
|
lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units (view/widget
|
opencs_hdrs_noqt (view/render
|
||||||
scenetoolbar scenetool scenetoolmode pushbutton
|
elements
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
opencs_units (view/tools
|
opencs_units (view/tools
|
||||||
reportsubview
|
reportsubview reporttable
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/tools
|
opencs_units_noqt (view/tools
|
||||||
|
@ -123,12 +129,8 @@ opencs_units_noqt (model/filter
|
||||||
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
|
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (model/filter
|
|
||||||
filter
|
|
||||||
)
|
|
||||||
|
|
||||||
opencs_units (view/filter
|
opencs_units (view/filter
|
||||||
filtercreator filterbox recordfilterbox editwidget
|
filterbox recordfilterbox editwidget
|
||||||
)
|
)
|
||||||
|
|
||||||
set (OPENCS_US
|
set (OPENCS_US
|
||||||
|
@ -143,7 +145,7 @@ set (OPENCS_UI
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui
|
${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR})
|
source_group (openmw-cs FILES ${OPENCS_SRC} ${OPENCS_HDR})
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(QT_USE_QTMAIN TRUE)
|
set(QT_USE_QTMAIN TRUE)
|
||||||
|
@ -163,16 +165,17 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
|
||||||
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
|
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
|
||||||
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
|
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS})
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns)
|
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns)
|
||||||
else()
|
else()
|
||||||
set (OPENCS_MAC_ICON "")
|
set (OPENCS_MAC_ICON "")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
add_executable(opencs
|
add_executable(openmw-cs
|
||||||
MACOSX_BUNDLE
|
MACOSX_BUNDLE
|
||||||
|
${OENGINE_BULLET}
|
||||||
${OPENCS_SRC}
|
${OPENCS_SRC}
|
||||||
${OPENCS_UI_HDR}
|
${OPENCS_UI_HDR}
|
||||||
${OPENCS_MOC_SRC}
|
${OPENCS_MOC_SRC}
|
||||||
|
@ -181,10 +184,10 @@ add_executable(opencs
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set_target_properties(opencs PROPERTIES
|
set_target_properties(openmw-cs PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
||||||
OUTPUT_NAME "OpenCS"
|
OUTPUT_NAME "OpenMW-CS"
|
||||||
MACOSX_BUNDLE_ICON_FILE "opencs.icns"
|
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
||||||
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
||||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
||||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION}
|
MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION}
|
||||||
|
@ -195,15 +198,17 @@ if(APPLE)
|
||||||
MACOSX_PACKAGE_LOCATION Resources)
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
target_link_libraries(opencs
|
target_link_libraries(openmw-cs
|
||||||
${OGRE_LIBRARIES}
|
${OGRE_LIBRARIES}
|
||||||
|
${OGRE_Overlay_LIBRARIES}
|
||||||
${OGRE_STATIC_PLUGINS}
|
${OGRE_STATIC_PLUGINS}
|
||||||
${SHINY_LIBRARIES}
|
${SHINY_LIBRARIES}
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
|
${BULLET_LIBRARIES}
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
|
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
#include "editor.hpp"
|
#include "editor.hpp"
|
||||||
|
|
||||||
|
#include <openengine/bullet/BulletShapeLoader.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
|
@ -13,15 +15,16 @@
|
||||||
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
|
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
|
||||||
|
|
||||||
#include <components/ogreinit/ogreinit.hpp>
|
#include <components/ogreinit/ogreinit.hpp>
|
||||||
|
#include <components/nifogre/ogrenifloader.hpp>
|
||||||
#include <components/bsa/resources.hpp>
|
#include <components/bsa/resources.hpp>
|
||||||
|
|
||||||
#include "model/doc/document.hpp"
|
#include "model/doc/document.hpp"
|
||||||
#include "model/world/data.hpp"
|
#include "model/world/data.hpp"
|
||||||
|
|
||||||
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||||
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
|
: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr),
|
||||||
mIpcServerName ("org.openmw.OpenCS")
|
mViewManager (mDocumentManager),
|
||||||
|
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL), mPid(""), mLock()
|
||||||
{
|
{
|
||||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||||
|
|
||||||
|
@ -32,6 +35,10 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||||
|
|
||||||
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
|
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
|
||||||
|
|
||||||
|
NifOgre::Loader::setShowMarkers(true);
|
||||||
|
|
||||||
|
mOverlaySystem.reset (new CSVRender::OverlaySystem);
|
||||||
|
|
||||||
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
|
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
|
||||||
mFsStrict);
|
mFsStrict);
|
||||||
|
|
||||||
|
@ -65,6 +72,18 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||||
this, SLOT (createNewGame (const boost::filesystem::path&)));
|
this, SLOT (createNewGame (const boost::filesystem::path&)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CS::Editor::~Editor ()
|
||||||
|
{
|
||||||
|
mPidFile.close();
|
||||||
|
|
||||||
|
if(mServer && boost::filesystem::exists(mPid))
|
||||||
|
static_cast<void> ( // silence coverity warning
|
||||||
|
remove(mPid.string().c_str())); // ignore any error
|
||||||
|
|
||||||
|
// cleanup global resources used by OEngine
|
||||||
|
delete OEngine::Physic::BulletShapeManager::getSingletonPtr();
|
||||||
|
}
|
||||||
|
|
||||||
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
|
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
|
||||||
{
|
{
|
||||||
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
||||||
|
@ -77,16 +96,20 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
|
||||||
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig()
|
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig()
|
||||||
{
|
{
|
||||||
boost::program_options::variables_map variables;
|
boost::program_options::variables_map variables;
|
||||||
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
|
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
|
||||||
|
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
|
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing())
|
||||||
("data-local", boost::program_options::value<std::string>()->default_value(""))
|
("data-local", boost::program_options::value<std::string>()->default_value(""))
|
||||||
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
||||||
("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
|
("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
|
||||||
("resources", boost::program_options::value<std::string>()->default_value("resources"))
|
("resources", boost::program_options::value<std::string>()->default_value("resources"))
|
||||||
("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
|
("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
|
||||||
default_value(std::vector<std::string>(), "fallback-archive")->multitoken());
|
default_value(std::vector<std::string>(), "fallback-archive")->multitoken())
|
||||||
|
("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "")
|
||||||
|
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
|
||||||
|
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
|
||||||
|
->default_value(true), "enable script blacklisting");
|
||||||
|
|
||||||
boost::program_options::notify(variables);
|
boost::program_options::notify(variables);
|
||||||
|
|
||||||
|
@ -97,6 +120,10 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||||
|
|
||||||
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
|
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
|
||||||
|
|
||||||
|
if (variables["script-blacklist-use"].as<bool>())
|
||||||
|
mDocumentManager.setBlacklistedScripts (
|
||||||
|
variables["script-blacklist"].as<std::vector<std::string> >());
|
||||||
|
|
||||||
mFsStrict = variables["fs-strict"].as<bool>();
|
mFsStrict = variables["fs-strict"].as<bool>();
|
||||||
|
|
||||||
Files::PathContainer dataDirs, dataLocal;
|
Files::PathContainer dataDirs, dataLocal;
|
||||||
|
@ -181,7 +208,7 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
|
||||||
files.push_back(path.toUtf8().constData());
|
files.push_back(path.toUtf8().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
files.push_back(mFileDialog.filename().toUtf8().constData());
|
files.push_back (savePath);
|
||||||
|
|
||||||
mDocumentManager.addDocument (files, savePath, true);
|
mDocumentManager.addDocument (files, savePath, true);
|
||||||
|
|
||||||
|
@ -212,14 +239,61 @@ void CS::Editor::showSettings()
|
||||||
if (mSettings.isHidden())
|
if (mSettings.isHidden())
|
||||||
mSettings.show();
|
mSettings.show();
|
||||||
|
|
||||||
|
mSettings.move (QCursor::pos());
|
||||||
mSettings.raise();
|
mSettings.raise();
|
||||||
mSettings.activateWindow();
|
mSettings.activateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CS::Editor::makeIPCServer()
|
bool CS::Editor::makeIPCServer()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mPid = boost::filesystem::temp_directory_path();
|
||||||
|
mPid /= "openmw-cs.pid";
|
||||||
|
bool pidExists = boost::filesystem::exists(mPid);
|
||||||
|
|
||||||
|
mPidFile.open(mPid);
|
||||||
|
|
||||||
|
mLock = boost::interprocess::file_lock(mPid.string().c_str());
|
||||||
|
if(!mLock.try_lock())
|
||||||
|
{
|
||||||
|
std::cerr << "OpenCS already running." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
mPidFile << GetCurrentProcessId() << std::endl;
|
||||||
|
#else
|
||||||
|
mPidFile << getpid() << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
mServer = new QLocalServer(this);
|
mServer = new QLocalServer(this);
|
||||||
|
|
||||||
|
if(pidExists)
|
||||||
|
{
|
||||||
|
// hack to get the temp directory path
|
||||||
|
mServer->listen("dummy");
|
||||||
|
QString fullPath = mServer->fullServerName();
|
||||||
|
mServer->close();
|
||||||
|
fullPath.remove(QRegExp("dummy$"));
|
||||||
|
fullPath += mIpcServerName;
|
||||||
|
if(boost::filesystem::exists(fullPath.toStdString().c_str()))
|
||||||
|
{
|
||||||
|
// TODO: compare pid of the current process with that in the file
|
||||||
|
std::cout << "Detected unclean shutdown." << std::endl;
|
||||||
|
// delete the stale file
|
||||||
|
if(remove(fullPath.toStdString().c_str()))
|
||||||
|
std::cerr << "ERROR removing stale connection file" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch(const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR " << e.what() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(mServer->listen(mIpcServerName))
|
if(mServer->listen(mIpcServerName))
|
||||||
{
|
{
|
||||||
connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup()));
|
connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup()));
|
||||||
|
@ -227,6 +301,7 @@ bool CS::Editor::makeIPCServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
mServer->close();
|
mServer->close();
|
||||||
|
mServer = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,26 +326,49 @@ int CS::Editor::run()
|
||||||
|
|
||||||
std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
|
std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
|
||||||
{
|
{
|
||||||
// TODO: setting
|
std::string renderer =
|
||||||
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
|
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
|
||||||
|
"Direct3D9 Rendering Subsystem";
|
||||||
|
#else
|
||||||
|
"OpenGL Rendering Subsystem";
|
||||||
|
#endif
|
||||||
|
std::string renderSystem = mUserSettings.setting("Video/render system", renderer.c_str()).toStdString();
|
||||||
|
|
||||||
|
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName(renderSystem));
|
||||||
|
|
||||||
|
// Initialise Ogre::OverlaySystem after Ogre::Root but before initialisation
|
||||||
|
mOverlaySystem.get();
|
||||||
|
|
||||||
Ogre::Root::getSingleton().initialise(false);
|
Ogre::Root::getSingleton().initialise(false);
|
||||||
|
|
||||||
// Create a hidden background window to keep resources
|
// Create a hidden background window to keep resources
|
||||||
Ogre::NameValuePairList params;
|
Ogre::NameValuePairList params;
|
||||||
params.insert(std::make_pair("title", ""));
|
params.insert(std::make_pair("title", ""));
|
||||||
params.insert(std::make_pair("FSAA", "0"));
|
|
||||||
|
std::string antialiasing = mUserSettings.settingValue("Video/antialiasing").toStdString();
|
||||||
|
if(antialiasing == "MSAA 16") antialiasing = "16";
|
||||||
|
else if(antialiasing == "MSAA 8") antialiasing = "8";
|
||||||
|
else if(antialiasing == "MSAA 4") antialiasing = "4";
|
||||||
|
else if(antialiasing == "MSAA 2") antialiasing = "2";
|
||||||
|
else antialiasing = "0";
|
||||||
|
params.insert(std::make_pair("FSAA", antialiasing));
|
||||||
|
|
||||||
params.insert(std::make_pair("vsync", "false"));
|
params.insert(std::make_pair("vsync", "false"));
|
||||||
params.insert(std::make_pair("hidden", "true"));
|
params.insert(std::make_pair("hidden", "true"));
|
||||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||||
params.insert(std::make_pair("macAPI", "cocoa"));
|
params.insert(std::make_pair("macAPI", "cocoa"));
|
||||||
#endif
|
#endif
|
||||||
|
// NOTE: fullscreen mode not supported (doesn't really make sense for opencs)
|
||||||
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
||||||
hiddenWindow->setActive(false);
|
hiddenWindow->setActive(false);
|
||||||
|
|
||||||
sh::OgrePlatform* platform =
|
sh::OgrePlatform* platform =
|
||||||
new sh::OgrePlatform ("General", (mResources / "materials").string());
|
new sh::OgrePlatform ("General", (mResources / "materials").string());
|
||||||
|
|
||||||
|
// for font used in overlays
|
||||||
|
Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(),
|
||||||
|
"FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
|
||||||
|
|
||||||
if (!boost::filesystem::exists (mCfgMgr.getCachePath()))
|
if (!boost::filesystem::exists (mCfgMgr.getCachePath()))
|
||||||
boost::filesystem::create_directories (mCfgMgr.getCachePath());
|
boost::filesystem::create_directories (mCfgMgr.getCachePath());
|
||||||
|
|
||||||
|
@ -278,7 +376,28 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
|
||||||
|
|
||||||
std::auto_ptr<sh::Factory> factory (new sh::Factory (platform));
|
std::auto_ptr<sh::Factory> factory (new sh::Factory (platform));
|
||||||
|
|
||||||
factory->setCurrentLanguage (sh::Language_GLSL); /// \todo make this configurable
|
QString shLang = mUserSettings.settingValue("General/shader mode");
|
||||||
|
QString rend = renderSystem.c_str();
|
||||||
|
bool openGL = rend.contains(QRegExp("^OpenGL", Qt::CaseInsensitive));
|
||||||
|
bool glES = rend.contains(QRegExp("^OpenGL ES", Qt::CaseInsensitive));
|
||||||
|
|
||||||
|
// force shader language based on render system
|
||||||
|
if(shLang == ""
|
||||||
|
|| (openGL && shLang == "hlsl")
|
||||||
|
|| (!openGL && shLang == "glsl")
|
||||||
|
|| (glES && shLang != "glsles"))
|
||||||
|
{
|
||||||
|
shLang = openGL ? (glES ? "glsles" : "glsl") : "hlsl";
|
||||||
|
//no group means "General" group in the "ini" file standard
|
||||||
|
mUserSettings.setDefinitions("shader mode", (QStringList() << shLang));
|
||||||
|
}
|
||||||
|
enum sh::Language lang;
|
||||||
|
if(shLang == "glsl") lang = sh::Language_GLSL;
|
||||||
|
else if(shLang == "glsles") lang = sh::Language_GLSLES;
|
||||||
|
else if(shLang == "hlsl") lang = sh::Language_HLSL;
|
||||||
|
else lang = sh::Language_CG;
|
||||||
|
|
||||||
|
factory->setCurrentLanguage (lang);
|
||||||
factory->setWriteSourceCache (true);
|
factory->setWriteSourceCache (true);
|
||||||
factory->setReadSourceCache (true);
|
factory->setReadSourceCache (true);
|
||||||
factory->setReadMicrocodeCache (true);
|
factory->setReadMicrocodeCache (true);
|
||||||
|
@ -286,16 +405,27 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
|
||||||
|
|
||||||
factory->loadAllFiles();
|
factory->loadAllFiles();
|
||||||
|
|
||||||
sh::Factory::getInstance().setGlobalSetting ("fog", "true");
|
bool shaders = mUserSettings.setting("3d-render/shaders", QString("true")) == "true" ? true : false;
|
||||||
|
sh::Factory::getInstance ().setShadersEnabled (shaders);
|
||||||
|
|
||||||
sh::Factory::getInstance().setGlobalSetting ("shadows", "false");
|
std::string fog = mUserSettings.setting("Shader/fog", QString("true")).toStdString();
|
||||||
sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", "false");
|
sh::Factory::getInstance().setGlobalSetting ("fog", fog);
|
||||||
|
|
||||||
sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false");
|
|
||||||
|
|
||||||
|
std::string shadows = mUserSettings.setting("Shader/shadows", QString("false")).toStdString();
|
||||||
|
sh::Factory::getInstance().setGlobalSetting ("shadows", shadows);
|
||||||
|
|
||||||
|
std::string shadows_pssm = mUserSettings.setting("Shader/shadows_pssm", QString("false")).toStdString();
|
||||||
|
sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", shadows_pssm);
|
||||||
|
|
||||||
|
std::string render_refraction = mUserSettings.setting("Shader/render_refraction", QString("false")).toStdString();
|
||||||
|
sh::Factory::getInstance ().setGlobalSetting ("render_refraction", render_refraction);
|
||||||
|
|
||||||
|
// internal setting - may be switched on or off by the use of shader configurations
|
||||||
sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false");
|
sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false");
|
||||||
|
|
||||||
sh::Factory::getInstance ().setGlobalSetting ("num_lights", "8");
|
std::string num_lights = mUserSettings.setting("3d-render-adv/num_lights", QString("8")).toStdString();
|
||||||
|
sh::Factory::getInstance ().setGlobalSetting ("num_lights", num_lights);
|
||||||
|
|
||||||
/// \todo add more configurable shiny settings
|
/// \todo add more configurable shiny settings
|
||||||
|
|
||||||
|
@ -309,5 +439,5 @@ void CS::Editor::documentAdded (CSMDoc::Document *document)
|
||||||
|
|
||||||
void CS::Editor::lastDocumentDeleted()
|
void CS::Editor::lastDocumentDeleted()
|
||||||
{
|
{
|
||||||
exit (0);
|
QApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <boost/interprocess/sync/file_lock.hpp>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
|
@ -16,6 +19,8 @@
|
||||||
|
|
||||||
#include <components/files/multidircollection.hpp>
|
#include <components/files/multidircollection.hpp>
|
||||||
|
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
|
|
||||||
#include "model/settings/usersettings.hpp"
|
#include "model/settings/usersettings.hpp"
|
||||||
#include "model/doc/documentmanager.hpp"
|
#include "model/doc/documentmanager.hpp"
|
||||||
|
|
||||||
|
@ -25,6 +30,7 @@
|
||||||
#include "view/doc/newgame.hpp"
|
#include "view/doc/newgame.hpp"
|
||||||
|
|
||||||
#include "view/settings/dialog.hpp"
|
#include "view/settings/dialog.hpp"
|
||||||
|
#include "view/render/overlaysystem.hpp"
|
||||||
|
|
||||||
namespace OgreInit
|
namespace OgreInit
|
||||||
{
|
{
|
||||||
|
@ -37,8 +43,10 @@ namespace CS
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
Nif::Cache mNifCache;
|
||||||
Files::ConfigurationManager mCfgMgr;
|
Files::ConfigurationManager mCfgMgr;
|
||||||
CSMSettings::UserSettings mUserSettings;
|
CSMSettings::UserSettings mUserSettings;
|
||||||
|
std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem;
|
||||||
CSMDoc::DocumentManager mDocumentManager;
|
CSMDoc::DocumentManager mDocumentManager;
|
||||||
CSVDoc::ViewManager mViewManager;
|
CSVDoc::ViewManager mViewManager;
|
||||||
CSVDoc::StartupDialogue mStartup;
|
CSVDoc::StartupDialogue mStartup;
|
||||||
|
@ -47,6 +55,9 @@ namespace CS
|
||||||
CSVDoc::FileDialog mFileDialog;
|
CSVDoc::FileDialog mFileDialog;
|
||||||
boost::filesystem::path mLocal;
|
boost::filesystem::path mLocal;
|
||||||
boost::filesystem::path mResources;
|
boost::filesystem::path mResources;
|
||||||
|
boost::filesystem::path mPid;
|
||||||
|
boost::interprocess::file_lock mLock;
|
||||||
|
boost::filesystem::ofstream mPidFile;
|
||||||
bool mFsStrict;
|
bool mFsStrict;
|
||||||
|
|
||||||
void setupDataFiles (const Files::PathContainer& dataDirs);
|
void setupDataFiles (const Files::PathContainer& dataDirs);
|
||||||
|
@ -61,6 +72,7 @@ namespace CS
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Editor (OgreInit::OgreInit& ogreInit);
|
Editor (OgreInit::OgreInit& ogreInit);
|
||||||
|
~Editor ();
|
||||||
|
|
||||||
bool makeIPCServer();
|
bool makeIPCServer();
|
||||||
void connectToIPCServer();
|
void connectToIPCServer();
|
||||||
|
|
|
@ -45,6 +45,8 @@ class Application : public QApplication
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE (resources);
|
Q_INIT_RESOURCE (resources);
|
||||||
|
|
||||||
|
@ -76,17 +78,23 @@ int main(int argc, char *argv[])
|
||||||
application.setLibraryPaths(libraryPaths);
|
application.setLibraryPaths(libraryPaths);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
application.setWindowIcon (QIcon (":./opencs.png"));
|
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
||||||
|
|
||||||
CS::Editor editor (ogreInit);
|
CS::Editor editor (ogreInit);
|
||||||
|
|
||||||
if(!editor.makeIPCServer())
|
if(!editor.makeIPCServer())
|
||||||
{
|
{
|
||||||
editor.connectToIPCServer();
|
editor.connectToIPCServer();
|
||||||
// return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
shinyFactory = editor.setupGraphics();
|
shinyFactory = editor.setupGraphics();
|
||||||
|
|
||||||
return editor.run();
|
return editor.run();
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
31
apps/opencs/model/doc/blacklist.cpp
Normal file
31
apps/opencs/model/doc/blacklist.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
#include "blacklist.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
bool CSMDoc::Blacklist::isBlacklisted (const CSMWorld::UniversalId& id) const
|
||||||
|
{
|
||||||
|
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> >::const_iterator iter =
|
||||||
|
mIds.find (id.getType());
|
||||||
|
|
||||||
|
if (iter==mIds.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return std::binary_search (iter->second.begin(), iter->second.end(),
|
||||||
|
Misc::StringUtils::lowerCase (id.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
|
||||||
|
const std::vector<std::string>& ids)
|
||||||
|
{
|
||||||
|
std::vector<std::string>& list = mIds[type];
|
||||||
|
|
||||||
|
int size = list.size();
|
||||||
|
|
||||||
|
list.resize (size+ids.size());
|
||||||
|
|
||||||
|
std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase);
|
||||||
|
std::sort (list.begin(), list.end());
|
||||||
|
}
|
25
apps/opencs/model/doc/blacklist.hpp
Normal file
25
apps/opencs/model/doc/blacklist.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef CSM_DOC_BLACKLIST_H
|
||||||
|
#define CSM_DOC_BLACKLIST_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../world/universalid.hpp"
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
/// \brief ID blacklist sorted by UniversalId type
|
||||||
|
class Blacklist
|
||||||
|
{
|
||||||
|
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> > mIds;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
|
||||||
|
|
||||||
|
void add (CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -10,6 +10,8 @@
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../../view/world/physicssystem.hpp"
|
||||||
|
|
||||||
void CSMDoc::Document::addGmsts()
|
void CSMDoc::Document::addGmsts()
|
||||||
{
|
{
|
||||||
static const char *gmstFloats[] =
|
static const char *gmstFloats[] =
|
||||||
|
@ -2024,6 +2026,7 @@ void CSMDoc::Document::addOptionalGmsts()
|
||||||
{
|
{
|
||||||
ESM::GameSetting gmst;
|
ESM::GameSetting gmst;
|
||||||
gmst.mId = sFloats[i];
|
gmst.mId = sFloats[i];
|
||||||
|
gmst.blank();
|
||||||
gmst.mValue.setType (ESM::VT_Float);
|
gmst.mValue.setType (ESM::VT_Float);
|
||||||
addOptionalGmst (gmst);
|
addOptionalGmst (gmst);
|
||||||
}
|
}
|
||||||
|
@ -2032,6 +2035,7 @@ void CSMDoc::Document::addOptionalGmsts()
|
||||||
{
|
{
|
||||||
ESM::GameSetting gmst;
|
ESM::GameSetting gmst;
|
||||||
gmst.mId = sIntegers[i];
|
gmst.mId = sIntegers[i];
|
||||||
|
gmst.blank();
|
||||||
gmst.mValue.setType (ESM::VT_Int);
|
gmst.mValue.setType (ESM::VT_Int);
|
||||||
addOptionalGmst (gmst);
|
addOptionalGmst (gmst);
|
||||||
}
|
}
|
||||||
|
@ -2040,6 +2044,7 @@ void CSMDoc::Document::addOptionalGmsts()
|
||||||
{
|
{
|
||||||
ESM::GameSetting gmst;
|
ESM::GameSetting gmst;
|
||||||
gmst.mId = sStrings[i];
|
gmst.mId = sStrings[i];
|
||||||
|
gmst.blank();
|
||||||
gmst.mValue.setType (ESM::VT_String);
|
gmst.mValue.setType (ESM::VT_String);
|
||||||
gmst.mValue.setString ("<no text>");
|
gmst.mValue.setString ("<no text>");
|
||||||
addOptionalGmst (gmst);
|
addOptionalGmst (gmst);
|
||||||
|
@ -2060,6 +2065,7 @@ void CSMDoc::Document::addOptionalGlobals()
|
||||||
{
|
{
|
||||||
ESM::Global global;
|
ESM::Global global;
|
||||||
global.mId = sGlobals[i];
|
global.mId = sGlobals[i];
|
||||||
|
global.blank();
|
||||||
global.mValue.setType (ESM::VT_Long);
|
global.mValue.setType (ESM::VT_Long);
|
||||||
|
|
||||||
if (i==0)
|
if (i==0)
|
||||||
|
@ -2069,6 +2075,19 @@ void CSMDoc::Document::addOptionalGlobals()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::addOptionalMagicEffects()
|
||||||
|
{
|
||||||
|
for (int i=ESM::MagicEffect::SummonFabricant; i<=ESM::MagicEffect::SummonCreature05; ++i)
|
||||||
|
{
|
||||||
|
ESM::MagicEffect effect;
|
||||||
|
effect.mIndex = i;
|
||||||
|
effect.mId = ESM::MagicEffect::indexToId (i);
|
||||||
|
effect.blank();
|
||||||
|
|
||||||
|
addOptionalMagicEffect (effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
|
void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
|
||||||
{
|
{
|
||||||
if (getData().getGmsts().searchId (gmst.mId)==-1)
|
if (getData().getGmsts().searchId (gmst.mId)==-1)
|
||||||
|
@ -2091,6 +2110,17 @@ void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::addOptionalMagicEffect (const ESM::MagicEffect& magicEffect)
|
||||||
|
{
|
||||||
|
if (getData().getMagicEffects().searchId (magicEffect.mId)==-1)
|
||||||
|
{
|
||||||
|
CSMWorld::Record<ESM::MagicEffect> record;
|
||||||
|
record.mBase = magicEffect;
|
||||||
|
record.mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||||
|
getData().getMagicEffects().appendRecord (record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::createBase()
|
void CSMDoc::Document::createBase()
|
||||||
{
|
{
|
||||||
static const char *sGlobals[] =
|
static const char *sGlobals[] =
|
||||||
|
@ -2202,17 +2232,31 @@ void CSMDoc::Document::createBase()
|
||||||
|
|
||||||
getData().getTopics().add (record);
|
getData().getTopics().add (record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<ESM::MagicEffect::Length; ++i)
|
||||||
|
{
|
||||||
|
ESM::MagicEffect record;
|
||||||
|
|
||||||
|
record.mIndex = i;
|
||||||
|
record.mId = ESM::MagicEffect::indexToId (i);
|
||||||
|
|
||||||
|
record.blank();
|
||||||
|
|
||||||
|
getData().getMagicEffects().add (record);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||||
const std::vector< boost::filesystem::path >& files, bool new_,
|
const std::vector< boost::filesystem::path >& files, bool new_,
|
||||||
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
||||||
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager)
|
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
|
||||||
|
const std::vector<std::string>& blacklistedScripts)
|
||||||
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
|
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
|
||||||
mTools (mData), mResDir(resDir),
|
mTools (*this), mResDir(resDir),
|
||||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||||
(savePath.filename().string() + ".project")),
|
(savePath.filename().string() + ".project")),
|
||||||
mSaving (*this, mProjectPath, encoding)
|
mSaving (*this, mProjectPath, encoding),
|
||||||
|
mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>())
|
||||||
{
|
{
|
||||||
if (mContentFiles.empty())
|
if (mContentFiles.empty())
|
||||||
throw std::runtime_error ("Empty content file sequence");
|
throw std::runtime_error ("Empty content file sequence");
|
||||||
|
@ -2222,14 +2266,15 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||||
boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
|
boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
|
||||||
customFiltersPath /= "defaultfilters";
|
customFiltersPath /= "defaultfilters";
|
||||||
|
|
||||||
std::ofstream dst(mProjectPath.c_str(), std::ios::binary);
|
std::ofstream destination (mProjectPath.string().c_str(), std::ios::binary);
|
||||||
|
|
||||||
if (boost::filesystem::exists (customFiltersPath))
|
if (boost::filesystem::exists (customFiltersPath))
|
||||||
{
|
{
|
||||||
dst<<std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf();
|
destination << std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
dst<<std::ifstream(std::string(mResDir.string() + "/defaultfilters").c_str(), std::ios::binary).rdbuf();
|
destination << std::ifstream(std::string(mResDir.string() + "/defaultfilters").c_str(), std::ios::binary).rdbuf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2242,20 +2287,25 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||||
createBase();
|
createBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mBlacklist.add (CSMWorld::UniversalId::Type_Script, blacklistedScripts);
|
||||||
|
|
||||||
addOptionalGmsts();
|
addOptionalGmsts();
|
||||||
addOptionalGlobals();
|
addOptionalGlobals();
|
||||||
|
addOptionalMagicEffects();
|
||||||
|
|
||||||
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
|
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
|
||||||
|
|
||||||
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
||||||
connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int)));
|
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
|
||||||
|
|
||||||
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
||||||
connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (int)));
|
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
|
||||||
|
|
||||||
connect (
|
connect (
|
||||||
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
|
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
|
||||||
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)));
|
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
|
||||||
|
|
||||||
|
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMDoc::Document::~Document()
|
CSMDoc::Document::~Document()
|
||||||
|
@ -2277,6 +2327,9 @@ int CSMDoc::Document::getState() const
|
||||||
if (mSaving.isRunning())
|
if (mSaving.isRunning())
|
||||||
state |= State_Locked | State_Saving | State_Operation;
|
state |= State_Locked | State_Saving | State_Operation;
|
||||||
|
|
||||||
|
if (mRunner.isRunning())
|
||||||
|
state |= State_Locked | State_Running;
|
||||||
|
|
||||||
if (int operations = mTools.getRunningOperations())
|
if (int operations = mTools.getRunningOperations())
|
||||||
state |= State_Locked | State_Operation | operations;
|
state |= State_Locked | State_Operation | operations;
|
||||||
|
|
||||||
|
@ -2335,13 +2388,13 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
|
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
|
||||||
int type)
|
const std::string& hint, int type)
|
||||||
{
|
{
|
||||||
/// \todo find a better way to get these messages to the user.
|
/// \todo find a better way to get these messages to the user.
|
||||||
std::cout << message << std::endl;
|
std::cout << message << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::operationDone (int type)
|
void CSMDoc::Document::operationDone (int type, bool failed)
|
||||||
{
|
{
|
||||||
emit stateChanged (getState(), this);
|
emit stateChanged (getState(), this);
|
||||||
}
|
}
|
||||||
|
@ -2361,7 +2414,64 @@ CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId&
|
||||||
return mTools.getReport (id);
|
return mTools.getReport (id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return mBlacklist.isBlacklisted (id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::startRunning (const std::string& profile,
|
||||||
|
const std::string& startupInstruction)
|
||||||
|
{
|
||||||
|
std::vector<std::string> contentFiles;
|
||||||
|
|
||||||
|
for (std::vector<boost::filesystem::path>::const_iterator iter (mContentFiles.begin());
|
||||||
|
iter!=mContentFiles.end(); ++iter)
|
||||||
|
contentFiles.push_back (iter->filename().string());
|
||||||
|
|
||||||
|
mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles,
|
||||||
|
startupInstruction);
|
||||||
|
|
||||||
|
int state = getState();
|
||||||
|
|
||||||
|
if (state & State_Modified)
|
||||||
|
{
|
||||||
|
// need to save first
|
||||||
|
mRunner.start (true);
|
||||||
|
|
||||||
|
new SaveWatcher (&mRunner, &mSaving); // no, that is not a memory leak. Qt is weird.
|
||||||
|
|
||||||
|
if (!(state & State_Saving))
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mRunner.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::stopRunning()
|
||||||
|
{
|
||||||
|
mRunner.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextDocument *CSMDoc::Document::getRunLog()
|
||||||
|
{
|
||||||
|
return mRunner.getLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::runStateChanged()
|
||||||
|
{
|
||||||
|
emit stateChanged (getState(), this);
|
||||||
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::progress (int current, int max, int type)
|
void CSMDoc::Document::progress (int current, int max, int type)
|
||||||
{
|
{
|
||||||
emit progress (current, max, type, 1, this);
|
emit progress (current, max, type, 1, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<CSVWorld::PhysicsSystem> CSMDoc::Document::getPhysics ()
|
||||||
|
{
|
||||||
|
if(!mPhysics)
|
||||||
|
mPhysics = boost::shared_ptr<CSVWorld::PhysicsSystem> (new CSVWorld::PhysicsSystem());
|
||||||
|
|
||||||
|
return mPhysics;
|
||||||
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue