mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
Merge remote-tracking branch 'upstream/master'
Conflicts: apps/openmw/mwgui/settingswindow.cpp extern/oics/ICSInputControlSystem_joystick.cpp files/mygui/openmw_settings_window.layout
This commit is contained in:
commit
97cc2522c0
504 changed files with 12728 additions and 6272 deletions
18
.travis.yml
18
.travis.yml
|
@ -5,7 +5,23 @@ language: cpp
|
||||||
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:
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
|
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
|
||||||
|
@ -14,7 +30,7 @@ before_script:
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
|
||||||
script:
|
script:
|
||||||
- cd ./build
|
- cd ./build
|
||||||
- make -j4
|
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi
|
||||||
after_script:
|
after_script:
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||||
notifications:
|
notifications:
|
||||||
|
|
204
AUTHORS.md
Normal file
204
AUTHORS.md
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
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
|
||||||
|
dteviot
|
||||||
|
Edmondo Tommasina (edmondo)
|
||||||
|
Eduard Cot (trombonecot)
|
||||||
|
Eli2
|
||||||
|
Emanuel Guével (potatoesmaster)
|
||||||
|
eroen
|
||||||
|
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
|
||||||
|
Narmo
|
||||||
|
Nathan Jeffords (blunted2night)
|
||||||
|
Nikolay Kasyanov (corristo)
|
||||||
|
nobrakal
|
||||||
|
Nolan Poe (nopoe)
|
||||||
|
Paul McElroy (Greendogo)
|
||||||
|
Pieter van der Kloet (pvdk)
|
||||||
|
Radu-Marius Popovici (rpopovici)
|
||||||
|
riothamus
|
||||||
|
Robert MacGregor (Ragora)
|
||||||
|
Rohit Nirmal
|
||||||
|
Roman Melnik (Kromgart)
|
||||||
|
Roman Proskuryakov (humbug)
|
||||||
|
sandstranger
|
||||||
|
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.
|
1498
CHANGELOG.md
Normal file
1498
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load diff
|
@ -6,4 +6,4 @@ export CC=clang
|
||||||
brew tap openmw/openmw
|
brew tap openmw/openmw
|
||||||
brew update
|
brew update
|
||||||
brew unlink boost
|
brew unlink boost
|
||||||
brew install cmake openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg pkg-config qt unshield
|
brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield
|
||||||
|
|
|
@ -12,37 +12,21 @@ 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 33)
|
set(OPENMW_VERSION_MINOR 34)
|
||||||
set(OPENMW_VERSION_RELEASE 1)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
set(OPENMW_VERSION_TAGHASH "")
|
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)
|
||||||
|
@ -67,6 +51,8 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie
|
||||||
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
|
||||||
|
@ -74,10 +60,11 @@ 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_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 and GMock frameworks" OFF)
|
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
||||||
option(BUILD_NIFTEST "build nif file tester" OFF)
|
option(BUILD_NIFTEST "build nif file tester" OFF)
|
||||||
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
||||||
|
|
||||||
|
@ -117,7 +104,7 @@ set(OENGINE_OGRE
|
||||||
set(OENGINE_GUI
|
set(OENGINE_GUI
|
||||||
${LIBS_DIR}/openengine/gui/loglistener.cpp
|
${LIBS_DIR}/openengine/gui/loglistener.cpp
|
||||||
${LIBS_DIR}/openengine/gui/manager.cpp
|
${LIBS_DIR}/openengine/gui/manager.cpp
|
||||||
${LIBS_DIR}/openengine/gui/layout.hpp
|
${LIBS_DIR}/openengine/gui/layout.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(OENGINE_BULLET
|
set(OENGINE_BULLET
|
||||||
|
@ -338,8 +325,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}")
|
||||||
|
@ -385,6 +374,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/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/openmw-mimeinfo.xml
|
||||||
|
"${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop
|
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop
|
||||||
"${OpenMW_BINARY_DIR}/opencs.desktop")
|
"${OpenMW_BINARY_DIR}/opencs.desktop")
|
||||||
endif()
|
endif()
|
||||||
|
@ -431,6 +422,9 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
IF(BUILD_MWINIIMPORTER)
|
IF(BUILD_MWINIIMPORTER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" 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}/opencs" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
@ -450,6 +444,7 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
|
|
||||||
# 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" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ 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}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ 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}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs")
|
||||||
|
@ -474,8 +469,9 @@ 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"
|
||||||
|
@ -490,6 +486,9 @@ if(WIN32)
|
||||||
IF(BUILD_MWINIIMPORTER)
|
IF(BUILD_MWINIIMPORTER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" DESTINATION ".")
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.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/opencs.exe" DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
|
||||||
|
@ -520,13 +519,13 @@ if(WIN32)
|
||||||
IF(BUILD_WIZARD)
|
IF(BUILD_WIZARD)
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard")
|
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard")
|
||||||
ENDIF(BUILD_WIZARD)
|
ENDIF(BUILD_WIZARD)
|
||||||
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'")
|
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")
|
||||||
|
@ -600,6 +599,10 @@ 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()
|
||||||
|
@ -876,4 +879,3 @@ if (DOXYGEN_FOUND)
|
||||||
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
||||||
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
98
README.md
Normal file
98
README.md
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
OpenMW
|
||||||
|
======
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](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.34.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
|
||||||
|
--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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -150,33 +150,32 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info);
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
Arguments info;
|
|
||||||
if(!parseOptions (argc, argv, info))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// Open file
|
|
||||||
Bsa::BSAFile bsa;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bsa.open(info.filename);
|
Arguments info;
|
||||||
}
|
if(!parseOptions (argc, argv, info))
|
||||||
catch(std::exception &e)
|
return 1;
|
||||||
{
|
|
||||||
std::cout << "ERROR reading BSA archive '" << info.filename
|
|
||||||
<< "'\nDetails:\n" << e.what() << std::endl;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.mode == "list")
|
// Open file
|
||||||
return list(bsa, info);
|
Bsa::BSAFile bsa;
|
||||||
else if (info.mode == "extract")
|
bsa.open(info.filename);
|
||||||
return extract(bsa, info);
|
|
||||||
else if (info.mode == "extractall")
|
if (info.mode == "list")
|
||||||
return extractAll(bsa, info);
|
return list(bsa, info);
|
||||||
else
|
else if (info.mode == "extract")
|
||||||
|
return extract(bsa, info);
|
||||||
|
else if (info.mode == "extractall")
|
||||||
|
return extractAll(bsa, info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
std::cerr << "ERROR reading BSA archive\nDetails:\n" << e.what() << std::endl;
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -177,10 +177,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>();
|
||||||
|
@ -203,19 +203,27 @@ int comp(Arguments& info);
|
||||||
|
|
||||||
int main(int argc, char**argv)
|
int main(int argc, char**argv)
|
||||||
{
|
{
|
||||||
Arguments info;
|
try
|
||||||
if(!parseOptions (argc, argv, info))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (info.mode == "dump")
|
|
||||||
return load(info);
|
|
||||||
else if (info.mode == "clone")
|
|
||||||
return clone(info);
|
|
||||||
else if (info.mode == "comp")
|
|
||||||
return comp(info);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl;
|
Arguments info;
|
||||||
|
if(!parseOptions (argc, argv, info))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (info.mode == "dump")
|
||||||
|
return load(info);
|
||||||
|
else if (info.mode == "clone")
|
||||||
|
return clone(info);
|
||||||
|
else if (info.mode == "comp")
|
||||||
|
return comp(info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +261,7 @@ 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;
|
||||||
|
@ -273,8 +281,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,7 +430,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 +501,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 +511,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,14 +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)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 26)
|
if (idx >= 0 && idx <= 26)
|
||||||
{
|
{
|
||||||
const char *bodyPartLabels[] = {
|
static const char *bodyPartLabels[] = {
|
||||||
"Head",
|
"Head",
|
||||||
"Hair",
|
"Hair",
|
||||||
"Neck",
|
"Neck",
|
||||||
|
@ -59,7 +58,7 @@ std::string meshPartLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail)
|
if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail)
|
||||||
{
|
{
|
||||||
const char *meshPartLabels[] = {
|
static const char *meshPartLabels[] = {
|
||||||
"Head",
|
"Head",
|
||||||
"Hair",
|
"Hair",
|
||||||
"Neck",
|
"Neck",
|
||||||
|
@ -86,7 +85,7 @@ std::string meshTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor)
|
if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor)
|
||||||
{
|
{
|
||||||
const char *meshTypeLabels[] = {
|
static const char *meshTypeLabels[] = {
|
||||||
"Skin",
|
"Skin",
|
||||||
"Clothing",
|
"Clothing",
|
||||||
"Armor"
|
"Armor"
|
||||||
|
@ -101,7 +100,7 @@ std::string clothingTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 9)
|
if (idx >= 0 && idx <= 9)
|
||||||
{
|
{
|
||||||
const char *clothingTypeLabels[] = {
|
static const char *clothingTypeLabels[] = {
|
||||||
"Pants",
|
"Pants",
|
||||||
"Shoes",
|
"Shoes",
|
||||||
"Shirt",
|
"Shirt",
|
||||||
|
@ -123,7 +122,7 @@ std::string armorTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 10)
|
if (idx >= 0 && idx <= 10)
|
||||||
{
|
{
|
||||||
const char *armorTypeLabels[] = {
|
static const char *armorTypeLabels[] = {
|
||||||
"Helmet",
|
"Helmet",
|
||||||
"Cuirass",
|
"Cuirass",
|
||||||
"Left Pauldron",
|
"Left Pauldron",
|
||||||
|
@ -146,7 +145,7 @@ std::string dialogTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 4)
|
if (idx >= 0 && idx <= 4)
|
||||||
{
|
{
|
||||||
const char *dialogTypeLabels[] = {
|
static const char *dialogTypeLabels[] = {
|
||||||
"Topic",
|
"Topic",
|
||||||
"Voice",
|
"Voice",
|
||||||
"Greeting",
|
"Greeting",
|
||||||
|
@ -165,7 +164,7 @@ std::string questStatusLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 4)
|
if (idx >= 0 && idx <= 4)
|
||||||
{
|
{
|
||||||
const char *questStatusLabels[] = {
|
static const char *questStatusLabels[] = {
|
||||||
"None",
|
"None",
|
||||||
"Name",
|
"Name",
|
||||||
"Finished",
|
"Finished",
|
||||||
|
@ -182,7 +181,7 @@ std::string creatureTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 3)
|
if (idx >= 0 && idx <= 3)
|
||||||
{
|
{
|
||||||
const char *creatureTypeLabels[] = {
|
static const char *creatureTypeLabels[] = {
|
||||||
"Creature",
|
"Creature",
|
||||||
"Daedra",
|
"Daedra",
|
||||||
"Undead",
|
"Undead",
|
||||||
|
@ -198,7 +197,7 @@ std::string soundTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 7)
|
if (idx >= 0 && idx <= 7)
|
||||||
{
|
{
|
||||||
const char *soundTypeLabels[] = {
|
static const char *soundTypeLabels[] = {
|
||||||
"Left Foot",
|
"Left Foot",
|
||||||
"Right Foot",
|
"Right Foot",
|
||||||
"Swim Left",
|
"Swim Left",
|
||||||
|
@ -218,7 +217,7 @@ std::string weaponTypeLabel(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 13)
|
if (idx >= 0 && idx <= 13)
|
||||||
{
|
{
|
||||||
const char *weaponTypeLabels[] = {
|
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",
|
||||||
|
|
|
@ -25,7 +25,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 +33,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 +89,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 +111,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;
|
||||||
|
@ -430,7 +432,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;
|
||||||
|
@ -816,7 +818,7 @@ void Record<ESM::Land>::print()
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
|
@ -999,7 +1001,7 @@ 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;
|
||||||
|
@ -1021,7 +1023,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;
|
||||||
|
@ -1123,9 +1125,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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
41
apps/essimporter/CMakeLists.txt
Normal file
41
apps/essimporter/CMakeLists.txt
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
46
apps/essimporter/convertacdt.cpp
Normal file
46
apps/essimporter/convertacdt.cpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
apps/essimporter/convertacdt.hpp
Normal file
22
apps/essimporter/convertacdt.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#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 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
|
322
apps/essimporter/converter.cpp
Normal file
322
apps/essimporter/converter.cpp
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
#include "converter.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <OgreImage.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());
|
||||||
|
convertImage(&data[0], data.size(), maph.size, maph.size, Ogre::PF_BYTE_RGB, "map.tga");
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
// probably need more micromanagement here so we don't overwrite values
|
||||||
|
// from the ESM with default values
|
||||||
|
convertACDT(cellref.mACDT, 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;
|
||||||
|
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||||
|
// probably need more micromanagement here so we don't overwrite values
|
||||||
|
// from the ESM with default values
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
esm.startRecord(ESM::REC_GMAP);
|
||||||
|
mContext->mGlobalMapState.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_GMAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
478
apps/essimporter/converter.hpp
Normal file
478
apps/essimporter/converter.hpp
Normal file
|
@ -0,0 +1,478 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CONVERTER_H
|
||||||
|
#define OPENMW_ESSIMPORT_CONVERTER_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 "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"
|
||||||
|
|
||||||
|
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")
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
// this should handle 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.
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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)).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
PCDT pcdt;
|
||||||
|
pcdt.load(esm);
|
||||||
|
|
||||||
|
mContext->mPlayer.mBirthsign = pcdt.mBirthsign;
|
||||||
|
mContext->mPlayer.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;
|
||||||
|
faction.mRank = it->mRank;
|
||||||
|
faction.mReputation = it->mReputation;
|
||||||
|
mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction;
|
||||||
|
}
|
||||||
|
for (int i=0; i<8; ++i)
|
||||||
|
mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
|
||||||
|
mContext->mPlayer.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
||||||
|
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
||||||
|
{
|
||||||
|
mContext->mDialogueState.mKnownTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
|
||||||
|
{
|
||||||
|
if (esm.retSubName().toString() == "FNAM")
|
||||||
|
{
|
||||||
|
std::string factionid = esm.getHString();
|
||||||
|
mFactionStolenItems.insert(std::make_pair(itemid, factionid));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string ownerid = esm.getHString();
|
||||||
|
mStolenItems.insert(std::make_pair(itemid, ownerid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::multimap<std::string, std::string> mStolenItems;
|
||||||
|
std::multimap<std::string, std::string> mFactionStolenItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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 (probably have to adjust OpenMW format) -
|
||||||
|
/// - 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
GAME game;
|
||||||
|
game.load(esm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Running global script
|
||||||
|
class ConvertSCPT : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
SCPT script;
|
||||||
|
script.load(esm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
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
|
95
apps/essimporter/importacdt.cpp
Normal file
95
apps/essimporter/importacdt.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#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);
|
||||||
|
|
||||||
|
// FIXME: not all actors have this, add flag
|
||||||
|
esm.getHNOT(mACDT, "ACDT");
|
||||||
|
|
||||||
|
ACSC acsc;
|
||||||
|
esm.getHNOT(acsc, "ACSC");
|
||||||
|
esm.getHNOT(acsc, "ACSL");
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// unsure at which point between LSTN and CHRD
|
||||||
|
if (esm.isNextSub("APUD"))
|
||||||
|
esm.skipHSub(); // 40 bytes, starts with string "ancestor guardian". maybe spellcasting in progress?
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
apps/essimporter/importacdt.hpp
Normal file
71
apps/essimporter/importacdt.hpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_ACDT_H
|
||||||
|
#define OPENMW_ESSIMPORT_ACDT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
|
||||||
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ACDTFlags
|
||||||
|
{
|
||||||
|
TalkedToPlayer = 0x4
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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 char mFlags; // ACDTFlags
|
||||||
|
unsigned char mUnknown1[3];
|
||||||
|
float mBreathMeter; // Seconds left before drowning
|
||||||
|
unsigned char mUnknown2[20];
|
||||||
|
float mDynamic[3][2];
|
||||||
|
unsigned char mUnknown3[16];
|
||||||
|
float mAttributes[8][2];
|
||||||
|
unsigned char mUnknown4[112];
|
||||||
|
unsigned int mGoldPool;
|
||||||
|
unsigned char mUnknown5[4];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct ActorData : public ESM::CellRef
|
||||||
|
{
|
||||||
|
ACDT mACDT;
|
||||||
|
|
||||||
|
int mSkills[27][2];
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Unknown, shared by (at least) REFR and CellRef
|
||||||
|
struct ACSC
|
||||||
|
{
|
||||||
|
unsigned char unknown[112];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 leveled 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 leveled 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");
|
||||||
|
|
||||||
|
// FIXME: use AiPackageList, need to fix getSubName()
|
||||||
|
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||||
|
|| esm.isNextSub("AI_A"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
mInventory.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
apps/essimporter/importcrec.hpp
Normal file
26
apps/essimporter/importcrec.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_CREC_H
|
||||||
|
#define OPENMW_ESSIMPORT_CREC_H
|
||||||
|
|
||||||
|
#include "importinventory.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Creature changes
|
||||||
|
struct CREC
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
|
||||||
|
Inventory mInventory;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
struct ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct DIAL
|
||||||
|
{
|
||||||
|
int mIndex; // Journal index
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
358
apps/essimporter/importer.cpp
Normal file
358
apps/essimporter/importer.cpp
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
#include "importer.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 "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)
|
||||||
|
: mEssFile(essfile)
|
||||||
|
, mOutFile(outfile)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)sub.mData[k] << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Data 2:" << std::endl;
|
||||||
|
for (unsigned int k=0; k<sub2.mData.size(); ++k)
|
||||||
|
{
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)sub2.mData[k] << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Importer::run()
|
||||||
|
{
|
||||||
|
// construct Ogre::Root to gain access to image codecs
|
||||||
|
Ogre::LogManager logman;
|
||||||
|
Ogre::Root root;
|
||||||
|
|
||||||
|
// TODO: set up encoding on ESMReader based on openmw.cfg / --encoding switch
|
||||||
|
|
||||||
|
ESM::ESMReader esm;
|
||||||
|
esm.open(mEssFile);
|
||||||
|
|
||||||
|
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 = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize);
|
||||||
|
int cellY = 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
25
apps/essimporter/importer.hpp
Normal file
25
apps/essimporter/importer.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#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);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
void compare();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mEssFile;
|
||||||
|
std::string mOutFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
0
apps/essimporter/importercontext.cpp
Normal file
0
apps/essimporter/importercontext.cpp
Normal file
64
apps/essimporter/importercontext.hpp
Normal file
64
apps/essimporter/importercontext.hpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#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 "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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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
|
13
apps/essimporter/importgame.cpp
Normal file
13
apps/essimporter/importgame.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "importgame.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void GAME::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mGMDT, "GMDT");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
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 masserPhase, secundaPhase; // 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
|
||||||
|
{
|
||||||
|
struct 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
|
||||||
|
{
|
||||||
|
struct 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
|
||||||
|
{
|
||||||
|
struct ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Kill Stats
|
||||||
|
struct KLST
|
||||||
|
{
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
|
||||||
|
/// RefId, kill count
|
||||||
|
std::map<std::string, int> mKillCounter;
|
||||||
|
|
||||||
|
int mWerewolfKills;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
20
apps/essimporter/importnpcc.cpp
Normal file
20
apps/essimporter/importnpcc.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "importnpcc.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void NPCC::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mNPDT, "NPDT");
|
||||||
|
|
||||||
|
// FIXME: use AiPackageList, need to fix getSubName()
|
||||||
|
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||||
|
|| esm.isNextSub("AI_A"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
mInventory.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
apps/essimporter/importnpcc.hpp
Normal file
36
apps/essimporter/importnpcc.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
apps/essimporter/importplayer.hpp
Normal file
70
apps/essimporter/importplayer.hpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#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;
|
||||||
|
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
unsigned char mUnknown1[4];
|
||||||
|
unsigned char mLevelProgress;
|
||||||
|
unsigned char mUnknown2[111];
|
||||||
|
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
|
||||||
|
{
|
||||||
|
struct 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
|
20
apps/essimporter/importscpt.cpp
Normal file
20
apps/essimporter/importscpt.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "importscpt.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void SCPT::load(ESM::ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mSCHD, "SCHD");
|
||||||
|
|
||||||
|
mSCRI.load(esm);
|
||||||
|
|
||||||
|
mRNAM = -1;
|
||||||
|
esm.getHNOT(mRNAM, "RNAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
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
|
||||||
|
// TODO: test how targeted scripts are saved
|
||||||
|
struct SCPT
|
||||||
|
{
|
||||||
|
ESM::Script::SCHD mSCHD;
|
||||||
|
|
||||||
|
// values of local variables
|
||||||
|
SCRI mSCRI;
|
||||||
|
|
||||||
|
int mRNAM; // unknown, seems to be -1 for some scripts, some huge integer for others
|
||||||
|
|
||||||
|
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
|
70
apps/essimporter/main.cpp
Normal file
70
apps/essimporter/main.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <boost/filesystem/fstream.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")
|
||||||
|
;
|
||||||
|
p_desc.add("mwsave", 1).add("output", 1);
|
||||||
|
|
||||||
|
bpo::variables_map vm;
|
||||||
|
|
||||||
|
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
||||||
|
.options(desc)
|
||||||
|
.positional(p_desc)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
bpo::store(parsed, vm);
|
||||||
|
|
||||||
|
if(vm.count("help") || !vm.count("mwsave") || !vm.count("output")) {
|
||||||
|
std::cout << desc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpo::notify(vm);
|
||||||
|
|
||||||
|
std::string essFile = vm["mwsave"].as<std::string>();
|
||||||
|
std::string outputFile = vm["output"].as<std::string>();
|
||||||
|
|
||||||
|
ESSImport::Importer importer(essFile, outputFile);
|
||||||
|
|
||||||
|
if (vm.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;
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
|
||||||
setObjectName ("DataFilesPage");
|
setObjectName ("DataFilesPage");
|
||||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
||||||
|
|
||||||
mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
|
mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||||
|
|
||||||
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
|
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
|
||||||
this, SLOT(updateOkButton(QString)));
|
this, SLOT(updateOkButton(QString)));
|
||||||
|
@ -44,12 +44,12 @@ 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 ("Default");
|
||||||
ui.profilesComboBox->setPlaceholderText (QString("Select a profile..."));
|
ui.profilesComboBox->setPlaceholderText (QString("Select a Content List..."));
|
||||||
ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default")));
|
ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default")));
|
||||||
|
|
||||||
// Add the actions to the toolbuttons
|
// Add the actions to the toolbuttons
|
||||||
|
@ -82,8 +82,8 @@ bool Launcher::DataFilesPage::loadSettings()
|
||||||
paths.insert (0, mDataLocal);
|
paths.insert (0, mDataLocal);
|
||||||
PathIterator pathIterator (paths);
|
PathIterator pathIterator (paths);
|
||||||
|
|
||||||
QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/"));
|
QStringList profiles = mLauncherSettings.getContentLists();
|
||||||
QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile");
|
QString currentProfile = mLauncherSettings.getCurrentContentListName();
|
||||||
|
|
||||||
qDebug() << "current profile is: " << currentProfile;
|
qDebug() << "current profile is: " << currentProfile;
|
||||||
|
|
||||||
|
@ -94,20 +94,25 @@ bool Launcher::DataFilesPage::loadSettings()
|
||||||
if (!currentProfile.isEmpty())
|
if (!currentProfile.isEmpty())
|
||||||
addProfile(currentProfile, true);
|
addProfile(currentProfile, true);
|
||||||
|
|
||||||
QStringList files = mLauncherSettings.values(QString("Profiles/") + currentProfile + QString("/content"), Qt::MatchExactly);
|
mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator)
|
||||||
|
{
|
||||||
|
QStringList files = mLauncherSettings.getContentListFiles(profileName);
|
||||||
QStringList filepaths;
|
QStringList filepaths;
|
||||||
|
|
||||||
foreach (const QString &file, files)
|
foreach(const QString& file, files)
|
||||||
{
|
{
|
||||||
QString filepath = pathIterator.findFirstPath (file);
|
QString filepath = pathIterator.findFirstPath(file);
|
||||||
|
|
||||||
if (!filepath.isEmpty())
|
if (!filepath.isEmpty())
|
||||||
filepaths << filepath;
|
filepaths << filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSelector->setProfileContent (filepaths);
|
return filepaths;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
||||||
|
@ -120,24 +125,20 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
||||||
//retrieve the files selected for the profile
|
//retrieve the files selected for the profile
|
||||||
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||||
|
|
||||||
removeProfile (profileName);
|
|
||||||
|
|
||||||
mGameSettings.remove(QString("content"));
|
|
||||||
|
|
||||||
//set the value of the current profile (not necessarily the profile being saved!)
|
//set the value of the current profile (not necessarily the profile being saved!)
|
||||||
mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText());
|
mLauncherSettings.setCurrentContentListName(ui.profilesComboBox->currentText());
|
||||||
|
|
||||||
|
QStringList fileNames;
|
||||||
foreach(const ContentSelectorModel::EsmFile *item, items) {
|
foreach(const ContentSelectorModel::EsmFile *item, items) {
|
||||||
mLauncherSettings.setMultiValue(QString("Profiles/") + profileName + QString("/content"), item->fileName());
|
fileNames.append(item->fileName());
|
||||||
mGameSettings.setMultiValue(QString("content"), 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);
|
||||||
mLauncherSettings.remove(QString("Profiles/") + profile + QString("/content"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
|
QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
|
||||||
|
@ -154,9 +155,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,9 +170,6 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString
|
||||||
if (previous == current)
|
if (previous == current)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (previous.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!previous.isEmpty() && savePrevious)
|
if (!previous.isEmpty() && savePrevious)
|
||||||
saveSettings (previous);
|
saveSettings (previous);
|
||||||
|
|
||||||
|
@ -207,12 +207,16 @@ 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::on_newProfileAction_triggered()
|
void Launcher::DataFilesPage::on_newProfileAction_triggered()
|
||||||
{
|
{
|
||||||
if (!mProfileDialog->exec() == QDialog::Accepted)
|
if (mProfileDialog->exec() != QDialog::Accepted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString profile = mProfileDialog->lineEdit()->text();
|
QString profile = mProfileDialog->lineEdit()->text();
|
||||||
|
@ -222,9 +226,10 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered()
|
||||||
|
|
||||||
saveSettings();
|
saveSettings();
|
||||||
|
|
||||||
mSelector->clearCheckStates();
|
mLauncherSettings.setCurrentContentListName(profile);
|
||||||
|
|
||||||
addProfile(profile, true);
|
addProfile(profile, true);
|
||||||
|
mSelector->clearCheckStates();
|
||||||
|
|
||||||
mSelector->setGameFile();
|
mSelector->setGameFile();
|
||||||
|
|
||||||
|
@ -238,10 +243,8 @@ 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)
|
||||||
setProfile (ui.profilesComboBox->findText (profile), false);
|
setProfile (ui.profilesComboBox->findText (profile), false);
|
||||||
|
@ -257,10 +260,12 @@ 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;
|
||||||
|
ui.profilesComboBox->setCurrentIndex(next);
|
||||||
|
|
||||||
removeProfile(profile);
|
removeProfile(profile);
|
||||||
|
ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile));
|
||||||
|
|
||||||
saveSettings();
|
saveSettings();
|
||||||
|
|
||||||
|
@ -294,10 +299,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);
|
||||||
|
|
|
@ -67,6 +67,8 @@ namespace Launcher
|
||||||
Config::GameSettings &mGameSettings;
|
Config::GameSettings &mGameSettings;
|
||||||
Config::LauncherSettings &mLauncherSettings;
|
Config::LauncherSettings &mLauncherSettings;
|
||||||
|
|
||||||
|
QString mPreviousProfile;
|
||||||
|
|
||||||
QString mDataLocal;
|
QString mDataLocal;
|
||||||
|
|
||||||
void setPluginsCheckstates(Qt::CheckState state);
|
void setPluginsCheckstates(Qt::CheckState state);
|
||||||
|
@ -132,6 +134,8 @@ namespace Launcher
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#include <OgreRoot.h>
|
||||||
|
#include <OgreRenderSystem.h>
|
||||||
|
|
||||||
#include <boost/math/common_factor.hpp>
|
#include <boost/math/common_factor.hpp>
|
||||||
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
@ -159,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);
|
||||||
|
@ -193,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());
|
||||||
|
|
||||||
|
@ -331,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,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
@ -15,53 +17,61 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
try
|
||||||
SDL_SetMainReady();
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
|
||||||
{
|
{
|
||||||
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||||
|
SDL_SetMainReady();
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||||
|
{
|
||||||
|
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
// Now we make sure the current dir is set to application path
|
||||||
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
if (dir.dirName() == "MacOS") {
|
||||||
|
dir.cdUp();
|
||||||
|
dir.cdUp();
|
||||||
|
dir.cdUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
||||||
|
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
||||||
|
pluginsPath.cdUp();
|
||||||
|
pluginsPath.cd("Plugins");
|
||||||
|
|
||||||
|
QStringList libraryPaths;
|
||||||
|
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
||||||
|
app.setLibraryPaths(libraryPaths);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QDir::setCurrent(dir.absolutePath());
|
||||||
|
|
||||||
|
// Support non-latin characters
|
||||||
|
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||||
|
|
||||||
|
Launcher::MainDialog mainWin;
|
||||||
|
|
||||||
|
if (!mainWin.showFirstRunDialog())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// if (!mainWin.setup()) {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
mainWin.show();
|
||||||
|
|
||||||
|
int returnValue = app.exec();
|
||||||
|
SDL_Quit();
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
// Now we make sure the current dir is set to application path
|
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
|
||||||
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
|
||||||
pluginsPath.cdUp();
|
|
||||||
pluginsPath.cd("Plugins");
|
|
||||||
|
|
||||||
QStringList libraryPaths;
|
|
||||||
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
|
||||||
app.setLibraryPaths(libraryPaths);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QDir::setCurrent(dir.absolutePath());
|
|
||||||
|
|
||||||
// Support non-latin characters
|
|
||||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
|
||||||
|
|
||||||
Launcher::MainDialog mainWin;
|
|
||||||
|
|
||||||
if (!mainWin.showFirstRunDialog())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// if (!mainWin.setup()) {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
mainWin.show();
|
|
||||||
|
|
||||||
int returnValue = app.exec();
|
|
||||||
SDL_Quit();
|
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,8 @@ bool Launcher::MainDialog::setup()
|
||||||
if (!setupGameSettings())
|
if (!setupGameSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
mLauncherSettings.setContentList(mGameSettings);
|
||||||
|
|
||||||
if (!setupGraphicsSettings())
|
if (!setupGraphicsSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -232,6 +234,8 @@ bool Launcher::MainDialog::reloadSettings()
|
||||||
if (!setupGameSettings())
|
if (!setupGameSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
mLauncherSettings.setContentList(mGameSettings);
|
||||||
|
|
||||||
if (!setupGraphicsSettings())
|
if (!setupGraphicsSettings())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -280,8 +284,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);
|
||||||
|
@ -562,7 +566,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
|
||||||
|
|
|
@ -51,7 +51,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||||
connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
|
connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||||
this, SLOT(importerFinished(int,QProcess::ExitStatus)));
|
this, SLOT(importerFinished(int,QProcess::ExitStatus)));
|
||||||
|
|
||||||
mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
|
mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||||
|
|
||||||
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
|
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
|
||||||
this, SLOT(updateOkButton(QString)));
|
this, SLOT(updateOkButton(QString)));
|
||||||
|
@ -207,18 +207,9 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus
|
||||||
if (mProfileDialog->exec() == QDialog::Accepted)
|
if (mProfileDialog->exec() == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
const QString profile(mProfileDialog->lineEdit()->text());
|
const QString profile(mProfileDialog->lineEdit()->text());
|
||||||
const QStringList files(mGameSettings.values(QLatin1String("content")));
|
const QStringList files(mGameSettings.getContentList());
|
||||||
|
mLauncherSettings.setCurrentContentListName(profile);
|
||||||
qDebug() << "Profile " << profile << files;
|
mLauncherSettings.setContentList(profile, files);
|
||||||
|
|
||||||
// Doesn't quite work right now
|
|
||||||
mLauncherSettings.setValue(QLatin1String("Profiles/currentprofile"), profile);
|
|
||||||
|
|
||||||
foreach (const QString &file, files) {
|
|
||||||
mLauncherSettings.setMultiValue(QLatin1String("Profiles/") + profile + QLatin1String("/content"), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
mGameSettings.remove(QLatin1String("content"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +225,7 @@ void Launcher::SettingsPage::updateOkButton(const QString &text)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList profiles(mLauncherSettings.subKeys(QString("Profiles/")));
|
const QStringList profiles(mLauncherSettings.getContentLists());
|
||||||
|
|
||||||
(profiles.contains(text))
|
(profiles.contains(text))
|
||||||
? mProfileDialog->setOkButtonEnabled(false)
|
? mProfileDialog->setOkButtonEnabled(false)
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,13 +59,13 @@ void Launcher::TextInputDialog::setOkButtonEnabled(bool enabled)
|
||||||
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
||||||
okButton->setEnabled(enabled);
|
okButton->setEnabled(enabled);
|
||||||
|
|
||||||
QPalette *palette = new QPalette();
|
QPalette palette;
|
||||||
palette->setColor(QPalette::Text, Qt::red);
|
palette.setColor(QPalette::Text, Qt::red);
|
||||||
|
|
||||||
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
|
||||||
mLineEdit->setPalette(*palette);
|
mLineEdit->setPalette(palette);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,93 +56,87 @@ 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");
|
|
||||||
bpo::positional_options_description p_desc;
|
|
||||||
desc.add_options()
|
|
||||||
("help,h", "produce help message")
|
|
||||||
("verbose,v", "verbose output")
|
|
||||||
("ini,i", bpo::value<std::string>(), "morrowind.ini file")
|
|
||||||
("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
|
|
||||||
("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
|
|
||||||
("game-files,g", "import esm and esp files")
|
|
||||||
("no-archives,A", "disable bsa archives import")
|
|
||||||
("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
|
|
||||||
"Character encoding used in OpenMW game messages:\n"
|
|
||||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
|
||||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
|
||||||
"\n\twin1252 - Western European (Latin) alphabet, used by default")
|
|
||||||
;
|
|
||||||
p_desc.add("ini", 1).add("cfg", 1);
|
|
||||||
|
|
||||||
bpo::variables_map vm;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
bpo::options_description desc("Syntax: mwiniimporter <options> inifile configfile\nAllowed options");
|
||||||
|
bpo::positional_options_description p_desc;
|
||||||
|
desc.add_options()
|
||||||
|
("help,h", "produce help message")
|
||||||
|
("verbose,v", "verbose output")
|
||||||
|
("ini,i", bpo::value<std::string>(), "morrowind.ini file")
|
||||||
|
("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
|
||||||
|
("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
|
||||||
|
("game-files,g", "import esm and esp files")
|
||||||
|
("no-archives,A", "disable bsa archives import")
|
||||||
|
("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
|
||||||
|
"Character encoding used in OpenMW game messages:\n"
|
||||||
|
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||||
|
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||||
|
"\n\twin1252 - Western European (Latin) alphabet, used by default")
|
||||||
|
;
|
||||||
|
p_desc.add("ini", 1).add("cfg", 1);
|
||||||
|
|
||||||
|
bpo::variables_map vm;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
|
||||||
|
std::cout << desc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpo::notify(vm);
|
||||||
|
|
||||||
|
std::string iniFile = vm["ini"].as<std::string>();
|
||||||
|
std::string cfgFile = vm["cfg"].as<std::string>();
|
||||||
|
|
||||||
|
// if no output is given, write back to cfg file
|
||||||
|
std::string outputFile(vm["output"].as<std::string>());
|
||||||
|
if(vm["output"].defaulted()) {
|
||||||
|
outputFile = vm["cfg"].as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!boost::filesystem::exists(iniFile)) {
|
||||||
|
std::cerr << "ini file does not exist" << std::endl;
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
if(!boost::filesystem::exists(cfgFile))
|
||||||
|
std::cerr << "cfg file does not exist" << std::endl;
|
||||||
|
|
||||||
|
MwIniImporter importer;
|
||||||
|
importer.setVerbose(vm.count("verbose"));
|
||||||
|
|
||||||
|
// Font encoding settings
|
||||||
|
std::string encoding(vm["encoding"].as<std::string>());
|
||||||
|
importer.setInputEncoding(ToUTF8::calculateEncoding(encoding));
|
||||||
|
|
||||||
|
MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile);
|
||||||
|
MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile);
|
||||||
|
|
||||||
|
importer.merge(cfg, ini);
|
||||||
|
importer.mergeFallback(cfg, ini);
|
||||||
|
|
||||||
|
if(vm.count("game-files")) {
|
||||||
|
importer.importGameFiles(cfg, ini);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!vm.count("no-archives")) {
|
||||||
|
importer.importArchives(cfg, ini);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "write to: " << outputFile << std::endl;
|
||||||
|
bfs::ofstream file((bfs::path(outputFile)));
|
||||||
|
importer.writeToFile(file, cfg);
|
||||||
}
|
}
|
||||||
catch(boost::program_options::unknown_option & x)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
std::cerr << "ERROR: " << e.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")) {
|
|
||||||
std::cout << desc;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bpo::notify(vm);
|
|
||||||
|
|
||||||
std::string iniFile = vm["ini"].as<std::string>();
|
|
||||||
std::string cfgFile = vm["cfg"].as<std::string>();
|
|
||||||
|
|
||||||
// if no output is given, write back to cfg file
|
|
||||||
std::string outputFile(vm["output"].as<std::string>());
|
|
||||||
if(vm["output"].defaulted()) {
|
|
||||||
outputFile = vm["cfg"].as<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!boost::filesystem::exists(iniFile)) {
|
|
||||||
std::cerr << "ini file does not exist" << std::endl;
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
if(!boost::filesystem::exists(cfgFile))
|
|
||||||
std::cerr << "cfg file does not exist" << std::endl;
|
|
||||||
|
|
||||||
MwIniImporter importer;
|
|
||||||
importer.setVerbose(vm.count("verbose"));
|
|
||||||
|
|
||||||
// Font encoding settings
|
|
||||||
std::string encoding(vm["encoding"].as<std::string>());
|
|
||||||
importer.setInputEncoding(ToUTF8::calculateEncoding(encoding));
|
|
||||||
|
|
||||||
MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile);
|
|
||||||
MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile);
|
|
||||||
|
|
||||||
importer.merge(cfg, ini);
|
|
||||||
importer.mergeFallback(cfg, ini);
|
|
||||||
|
|
||||||
if(vm.count("game-files")) {
|
|
||||||
importer.importGameFiles(cfg, ini);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!vm.count("no-archives")) {
|
|
||||||
importer.importArchives(cfg, ini);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "write to: " << outputFile << std::endl;
|
|
||||||
bfs::ofstream file((bfs::path(outputFile)));
|
|
||||||
importer.writeToFile(file, cfg);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#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"
|
||||||
|
@ -35,6 +35,8 @@ 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);
|
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,
|
||||||
|
@ -75,7 +77,8 @@ CS::Editor::~Editor ()
|
||||||
mPidFile.close();
|
mPidFile.close();
|
||||||
|
|
||||||
if(mServer && boost::filesystem::exists(mPid))
|
if(mServer && boost::filesystem::exists(mPid))
|
||||||
remove(mPid.string().c_str()); // ignore any error
|
static_cast<void> ( // silence coverity warning
|
||||||
|
remove(mPid.string().c_str())); // ignore any error
|
||||||
|
|
||||||
// cleanup global resources used by OEngine
|
// cleanup global resources used by OEngine
|
||||||
delete OEngine::Physic::BulletShapeManager::getSingletonPtr();
|
delete OEngine::Physic::BulletShapeManager::getSingletonPtr();
|
||||||
|
@ -236,6 +239,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,47 +46,55 @@ class Application : public QApplication
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE (resources);
|
try
|
||||||
|
|
||||||
qRegisterMetaType<std::string> ("std::string");
|
|
||||||
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
|
|
||||||
|
|
||||||
OgreInit::OgreInit ogreInit;
|
|
||||||
|
|
||||||
std::auto_ptr<sh::Factory> shinyFactory;
|
|
||||||
|
|
||||||
Application application (argc, argv);
|
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
QDir::setCurrent(dir.absolutePath());
|
|
||||||
|
|
||||||
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
|
||||||
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
|
||||||
pluginsPath.cdUp();
|
|
||||||
pluginsPath.cd("Plugins");
|
|
||||||
|
|
||||||
QStringList libraryPaths;
|
|
||||||
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
|
||||||
application.setLibraryPaths(libraryPaths);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
application.setWindowIcon (QIcon (":./opencs.png"));
|
|
||||||
|
|
||||||
CS::Editor editor (ogreInit);
|
|
||||||
|
|
||||||
if(!editor.makeIPCServer())
|
|
||||||
{
|
{
|
||||||
editor.connectToIPCServer();
|
Q_INIT_RESOURCE (resources);
|
||||||
|
|
||||||
|
qRegisterMetaType<std::string> ("std::string");
|
||||||
|
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
|
||||||
|
|
||||||
|
OgreInit::OgreInit ogreInit;
|
||||||
|
|
||||||
|
std::auto_ptr<sh::Factory> shinyFactory;
|
||||||
|
|
||||||
|
Application application (argc, argv);
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
if (dir.dirName() == "MacOS") {
|
||||||
|
dir.cdUp();
|
||||||
|
dir.cdUp();
|
||||||
|
dir.cdUp();
|
||||||
|
}
|
||||||
|
QDir::setCurrent(dir.absolutePath());
|
||||||
|
|
||||||
|
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
||||||
|
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
||||||
|
pluginsPath.cdUp();
|
||||||
|
pluginsPath.cd("Plugins");
|
||||||
|
|
||||||
|
QStringList libraryPaths;
|
||||||
|
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
||||||
|
application.setLibraryPaths(libraryPaths);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
application.setWindowIcon (QIcon (":./opencs.png"));
|
||||||
|
|
||||||
|
CS::Editor editor (ogreInit);
|
||||||
|
|
||||||
|
if(!editor.makeIPCServer())
|
||||||
|
{
|
||||||
|
editor.connectToIPCServer();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shinyFactory = editor.setupGraphics();
|
||||||
|
return editor.run();
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
shinyFactory = editor.setupGraphics();
|
|
||||||
|
|
||||||
return editor.run();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row,
|
||||||
QVariant data = table.data (index);
|
QVariant data = table.data (index);
|
||||||
|
|
||||||
if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int &&
|
if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int &&
|
||||||
data.type()!=QVariant::UInt && data.type()!=static_cast<QVariant::Type> (QMetaType::Float))
|
data.type()!=QVariant::UInt)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double value = data.toDouble();
|
double value = data.toDouble();
|
||||||
|
|
|
@ -1053,13 +1053,13 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
{
|
{
|
||||||
return record.get().mCharge;
|
return record.get().mChargeInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||||
{
|
{
|
||||||
ESXRecordT record2 = record.get();
|
ESXRecordT record2 = record.get();
|
||||||
record2.mCharge = data.toInt();
|
record2.mChargeInt = data.toInt();
|
||||||
record.setModified (record2);
|
record.setModified (record2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,14 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
|
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
|
||||||
: ActorColumns (actorColumns)
|
: ActorColumns (actorColumns),
|
||||||
|
mType(NULL),
|
||||||
|
mSoul(NULL),
|
||||||
|
mScale(NULL),
|
||||||
|
mOriginal(NULL),
|
||||||
|
mCombat(NULL),
|
||||||
|
mMagic(NULL),
|
||||||
|
mStealth(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns)
|
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns)
|
||||||
|
@ -431,7 +438,14 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
|
||||||
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
|
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {}
|
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns)
|
||||||
|
: ActorColumns (actorColumns),
|
||||||
|
mRace(NULL),
|
||||||
|
mClass(NULL),
|
||||||
|
mFaction(NULL),
|
||||||
|
mHair(NULL),
|
||||||
|
mHead(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns)
|
CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns)
|
||||||
: ActorRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc, columns), mColumns (columns)
|
: ActorRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc, columns), mColumns (columns)
|
||||||
|
|
|
@ -131,6 +131,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::UniversalId (const std::string& universalId)
|
CSMWorld::UniversalId::UniversalId (const std::string& universalId)
|
||||||
|
: mIndex(0)
|
||||||
{
|
{
|
||||||
std::string::size_type index = universalId.find (':');
|
std::string::size_type index = universalId.find (':');
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include "adjusterwidget.hpp"
|
#include "adjusterwidget.hpp"
|
||||||
|
|
||||||
CSVDoc::FileDialog::FileDialog(QWidget *parent) :
|
CSVDoc::FileDialog::FileDialog(QWidget *parent) :
|
||||||
QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false)
|
QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false), mAction(ContentAction_Undefined)
|
||||||
{
|
{
|
||||||
ui.setupUi (this);
|
ui.setupUi (this);
|
||||||
resize(400, 400);
|
resize(400, 400);
|
||||||
|
@ -125,13 +125,17 @@ void CSVDoc::FileDialog::buildOpenFileView()
|
||||||
|
|
||||||
if(!mDialogBuilt)
|
if(!mDialogBuilt)
|
||||||
{
|
{
|
||||||
connect (mSelector, SIGNAL (signalAddonFileSelected (int)), this, SLOT (slotUpdateAcceptButton (int)));
|
connect (mSelector, SIGNAL (signalAddonDataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (slotAddonDataChanged(const QModelIndex&, const QModelIndex&)));
|
||||||
connect (mSelector, SIGNAL (signalAddonFileUnselected (int)), this, SLOT (slotUpdateAcceptButton (int)));
|
|
||||||
}
|
}
|
||||||
connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
|
connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::FileDialog::slotUpdateAcceptButton (int)
|
void CSVDoc::FileDialog::slotAddonDataChanged(const QModelIndex &topleft, const QModelIndex &bottomright)
|
||||||
|
{
|
||||||
|
slotUpdateAcceptButton(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVDoc::FileDialog::slotUpdateAcceptButton(int)
|
||||||
{
|
{
|
||||||
QString name = "";
|
QString name = "";
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ namespace CSVDoc
|
||||||
void slotUpdateAcceptButton (int);
|
void slotUpdateAcceptButton (int);
|
||||||
void slotUpdateAcceptButton (const QString &, bool);
|
void slotUpdateAcceptButton (const QString &, bool);
|
||||||
void slotRejected();
|
void slotRejected();
|
||||||
|
void slotAddonDataChanged(const QModelIndex& topleft, const QModelIndex& bottomright);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif // FILEDIALOG_HPP
|
#endif // FILEDIALOG_HPP
|
||||||
|
|
|
@ -18,7 +18,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
||||||
: mDocument (document), mAborted (false), mMessages (0)
|
: mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0)
|
||||||
{
|
{
|
||||||
setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str());
|
setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str());
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ void CSVDoc::LoadingDocument::nextRecord (int records)
|
||||||
void CSVDoc::LoadingDocument::abort (const std::string& error)
|
void CSVDoc::LoadingDocument::abort (const std::string& error)
|
||||||
{
|
{
|
||||||
mAborted = true;
|
mAborted = true;
|
||||||
mError->setText (QString::fromUtf8 (("Loading failed: " + error).c_str()));
|
mError->setText (QString::fromUtf8 (("<font color=red>Loading failed: " + error + "</font>").c_str()));
|
||||||
mButtons->setStandardButtons (QDialogButtonBox::Close);
|
mButtons->setStandardButtons (QDialogButtonBox::Close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -375,17 +375,20 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
|
||||||
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
|
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
|
||||||
mViewTotal (totalViews)
|
mViewTotal (totalViews)
|
||||||
{
|
{
|
||||||
QString width = CSMSettings::UserSettings::instance().settingValue
|
int width = CSMSettings::UserSettings::instance().settingValue
|
||||||
("window/default-width");
|
("window/default-width").toInt();
|
||||||
|
|
||||||
QString height = CSMSettings::UserSettings::instance().settingValue
|
int height = CSMSettings::UserSettings::instance().settingValue
|
||||||
("window/default-height");
|
("window/default-height").toInt();
|
||||||
|
|
||||||
|
width = std::max(width, 300);
|
||||||
|
height = std::max(height, 300);
|
||||||
|
|
||||||
// trick to get the window decorations and their sizes
|
// trick to get the window decorations and their sizes
|
||||||
show();
|
show();
|
||||||
hide();
|
hide();
|
||||||
resize (width.toInt() - (frameGeometry().width() - geometry().width()),
|
resize (width - (frameGeometry().width() - geometry().width()),
|
||||||
height.toInt() - (frameGeometry().height() - geometry().height()));
|
height - (frameGeometry().height() - geometry().height()));
|
||||||
|
|
||||||
mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
|
mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
|
|
||||||
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
||||||
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
|
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
|
||||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics)
|
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0)
|
||||||
{
|
{
|
||||||
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
|
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
|
||||||
mCellNode->setPosition (origin);
|
mCellNode->setPosition (origin);
|
||||||
|
@ -77,15 +77,14 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
||||||
int landIndex = land.searchId(mId);
|
int landIndex = land.searchId(mId);
|
||||||
if (landIndex != -1)
|
if (landIndex != -1)
|
||||||
{
|
{
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
|
|
||||||
Terrain::Align_XY));
|
|
||||||
|
|
||||||
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
||||||
mTerrain->loadCell(esmLand->mX,
|
|
||||||
esmLand->mY);
|
|
||||||
|
|
||||||
if(esmLand)
|
if(esmLand)
|
||||||
{
|
{
|
||||||
|
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
|
||||||
|
Terrain::Align_XY));
|
||||||
|
mTerrain->loadCell(esmLand->mX,
|
||||||
|
esmLand->mY);
|
||||||
|
|
||||||
float verts = ESM::Land::LAND_SIZE;
|
float verts = ESM::Land::LAND_SIZE;
|
||||||
float worldsize = ESM::Land::REAL_SIZE;
|
float worldsize = ESM::Land::REAL_SIZE;
|
||||||
mX = esmLand->mX;
|
mX = esmLand->mX;
|
||||||
|
@ -98,7 +97,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
||||||
|
|
||||||
CSVRender::Cell::~Cell()
|
CSVRender::Cell::~Cell()
|
||||||
{
|
{
|
||||||
mPhysics->removeHeightField(mSceneMgr, mX, mY);
|
if (mTerrain.get())
|
||||||
|
mPhysics->removeHeightField(mSceneMgr, mX, mY);
|
||||||
|
|
||||||
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
|
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
|
||||||
iter!=mObjects.end(); ++iter)
|
iter!=mObjects.end(); ++iter)
|
||||||
|
|
|
@ -346,7 +346,7 @@ namespace CSVRender
|
||||||
//plane X, upvector Y, mOffset x : x-z plane, wheel closer/further
|
//plane X, upvector Y, mOffset x : x-z plane, wheel closer/further
|
||||||
std::pair<Ogre::Vector3, Ogre::Vector3> MouseState::planeAxis()
|
std::pair<Ogre::Vector3, Ogre::Vector3> MouseState::planeAxis()
|
||||||
{
|
{
|
||||||
bool screenCoord = true;
|
const bool screenCoord = true;
|
||||||
Ogre::Vector3 dir = getCamera()->getDerivedDirection();
|
Ogre::Vector3 dir = getCamera()->getDerivedDirection();
|
||||||
|
|
||||||
QString wheelDir = "Closer/Further";
|
QString wheelDir = "Closer/Further";
|
||||||
|
|
|
@ -35,7 +35,8 @@ void CSVRender::Object::clear()
|
||||||
{
|
{
|
||||||
mObject.setNull();
|
mObject.setNull();
|
||||||
|
|
||||||
clearSceneNode (mBase);
|
if (mBase)
|
||||||
|
clearSceneNode (mBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Object::update()
|
void CSVRender::Object::update()
|
||||||
|
@ -156,11 +157,13 @@ CSVRender::Object::~Object()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
if(mPhysics) // preview may not have physics enabled
|
|
||||||
mPhysics->removeObject(mBase->getName());
|
|
||||||
|
|
||||||
if (mBase)
|
if (mBase)
|
||||||
|
{
|
||||||
|
if(mPhysics) // preview may not have physics enabled
|
||||||
|
mPhysics->removeObject(mBase->getName());
|
||||||
|
|
||||||
mBase->getCreator()->destroySceneNode (mBase);
|
mBase->getCreator()->destroySceneNode (mBase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
|
bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace CSVWorld
|
||||||
PhysicsSystem::PhysicsSystem()
|
PhysicsSystem::PhysicsSystem()
|
||||||
{
|
{
|
||||||
// Create physics. shapeLoader is deleted by the physic engine
|
// Create physics. shapeLoader is deleted by the physic engine
|
||||||
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
|
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true);
|
||||||
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
|
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,17 +138,19 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event)
|
||||||
{
|
{
|
||||||
if (event->type() == QEvent::Drop)
|
if (event->type() == QEvent::Drop)
|
||||||
{
|
{
|
||||||
QDropEvent* drop = dynamic_cast<QDropEvent*>(event);
|
if (QDropEvent* drop = dynamic_cast<QDropEvent*>(event))
|
||||||
const CSMWorld::TableMimeData* data = dynamic_cast<const CSMWorld::TableMimeData*>(drop->mimeData());
|
|
||||||
if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter);
|
|
||||||
if (handled)
|
|
||||||
{
|
{
|
||||||
mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId());
|
const CSMWorld::TableMimeData* data = dynamic_cast<const CSMWorld::TableMimeData*>(drop->mimeData());
|
||||||
|
if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter);
|
||||||
|
if (handled)
|
||||||
|
{
|
||||||
|
mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId());
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
return handled;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,12 @@ add_openmw_dir (mwgui
|
||||||
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
||||||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow
|
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
||||||
|
draganddrop
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwdialogue
|
add_openmw_dir (mwdialogue
|
||||||
dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper hypertextparser keywordsearch
|
dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper hypertextparser keywordsearch scripttest
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwscript
|
add_openmw_dir (mwscript
|
||||||
|
@ -76,7 +77,7 @@ add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
||||||
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction
|
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwstate
|
add_openmw_dir (mwstate
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
|
@ -29,6 +28,7 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)(x)
|
||||||
|
|
||||||
static const char crash_switch[] = "--cc-handle-crash";
|
static const char crash_switch[] = "--cc-handle-crash";
|
||||||
|
|
||||||
|
@ -160,7 +160,11 @@ static void gdb_info(pid_t pid)
|
||||||
printf("Executing: %s\n", cmd_buf);
|
printf("Executing: %s\n", cmd_buf);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
system(cmd_buf);
|
{ /* another special exception for "ignoring return value..." */
|
||||||
|
int unused;
|
||||||
|
unused = system(cmd_buf);
|
||||||
|
UNUSED(unused);
|
||||||
|
}
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
remove(respfile);
|
remove(respfile);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +410,13 @@ int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, co
|
||||||
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
|
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getcwd(argv0, sizeof(argv0));
|
{
|
||||||
|
/* we don't want to disable "ignoring return value" warnings, so we make
|
||||||
|
* a special exception here. */
|
||||||
|
char * unused;
|
||||||
|
unused = getcwd(argv0, sizeof(argv0));
|
||||||
|
UNUSED(unused);
|
||||||
|
}
|
||||||
retval = strlen(argv0);
|
retval = strlen(argv0);
|
||||||
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
|
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include "mwdialogue/dialoguemanagerimp.hpp"
|
#include "mwdialogue/dialoguemanagerimp.hpp"
|
||||||
#include "mwdialogue/journalimp.hpp"
|
#include "mwdialogue/journalimp.hpp"
|
||||||
|
#include "mwdialogue/scripttest.hpp"
|
||||||
|
|
||||||
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
||||||
|
|
||||||
|
@ -174,6 +175,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||||
, mSkipMenu (false)
|
, mSkipMenu (false)
|
||||||
, mUseSound (true)
|
, mUseSound (true)
|
||||||
, mCompileAll (false)
|
, mCompileAll (false)
|
||||||
|
, mCompileAllDialogue (false)
|
||||||
, mWarningsMode (1)
|
, mWarningsMode (1)
|
||||||
, mScriptContext (0)
|
, mScriptContext (0)
|
||||||
, mFSStrict (false)
|
, mFSStrict (false)
|
||||||
|
@ -206,6 +208,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||||
|
|
||||||
OMW::Engine::~Engine()
|
OMW::Engine::~Engine()
|
||||||
{
|
{
|
||||||
|
if (mOgre)
|
||||||
|
mOgre->restoreWindowGammaRamp();
|
||||||
mEnvironment.cleanup();
|
mEnvironment.cleanup();
|
||||||
delete mScriptContext;
|
delete mScriptContext;
|
||||||
delete mOgre;
|
delete mOgre;
|
||||||
|
@ -348,6 +352,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
|
|
||||||
OEngine::Render::WindowSettings windowSettings;
|
OEngine::Render::WindowSettings windowSettings;
|
||||||
windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
|
windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
|
||||||
|
windowSettings.window_border = settings.getBool("window border", "Video");
|
||||||
windowSettings.window_x = settings.getInt("resolution x", "Video");
|
windowSettings.window_x = settings.getInt("resolution x", "Video");
|
||||||
windowSettings.window_y = settings.getInt("resolution y", "Video");
|
windowSettings.window_y = settings.getInt("resolution y", "Video");
|
||||||
windowSettings.screen = settings.getInt("screen", "Video");
|
windowSettings.screen = settings.getInt("screen", "Video");
|
||||||
|
@ -391,6 +396,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
||||||
|
|
||||||
|
mOgre->setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General"));
|
||||||
|
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
{
|
{
|
||||||
std::string logo = mFallbackMap["Movies_Company_Logo"];
|
std::string logo = mFallbackMap["Movies_Company_Logo"];
|
||||||
|
@ -437,7 +444,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
if (mCompileAll)
|
if (mCompileAll)
|
||||||
{
|
{
|
||||||
std::pair<int, int> result = MWBase::Environment::get().getScriptManager()->compileAll();
|
std::pair<int, int> result = MWBase::Environment::get().getScriptManager()->compileAll();
|
||||||
|
|
||||||
if (result.first)
|
if (result.first)
|
||||||
std::cout
|
std::cout
|
||||||
<< "compiled " << result.second << " of " << result.first << " scripts ("
|
<< "compiled " << result.second << " of " << result.first << " scripts ("
|
||||||
|
@ -445,6 +451,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
<< "%)"
|
<< "%)"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
if (mCompileAllDialogue)
|
||||||
|
{
|
||||||
|
std::pair<int, int> result = MWDialogue::ScriptTest::compileAll(&mExtensions, mWarningsMode);
|
||||||
|
if (result.first)
|
||||||
|
std::cout
|
||||||
|
<< "compiled " << result.second << " of " << result.first << " dialogue script/actor combinations a("
|
||||||
|
<< 100*static_cast<double> (result.second)/result.first
|
||||||
|
<< "%)"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise and enter main loop.
|
// Initialise and enter main loop.
|
||||||
|
@ -468,9 +484,13 @@ void OMW::Engine::go()
|
||||||
// Play some good 'ol tunes
|
// Play some good 'ol tunes
|
||||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||||
|
|
||||||
// start in main menu
|
if (!mSaveGameFile.empty())
|
||||||
if (!mSkipMenu)
|
|
||||||
{
|
{
|
||||||
|
MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile);
|
||||||
|
}
|
||||||
|
else if (!mSkipMenu)
|
||||||
|
{
|
||||||
|
// start in main menu
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -509,6 +529,11 @@ void OMW::Engine::activate()
|
||||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0
|
||||||
|
|| player.getClass().getCreatureStats(player).getKnockedDown())
|
||||||
|
return;
|
||||||
|
|
||||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||||
|
|
||||||
if (ptr.isEmpty())
|
if (ptr.isEmpty())
|
||||||
|
@ -517,6 +542,14 @@ void OMW::Engine::activate()
|
||||||
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
|
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ptr.getClass().isActor())
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
|
||||||
|
if (stats.getAiSequence().isInCombat() && !stats.isDead())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
|
MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,6 +580,11 @@ void OMW::Engine::setCompileAll (bool all)
|
||||||
mCompileAll = all;
|
mCompileAll = all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OMW::Engine::setCompileAllDialogue (bool all)
|
||||||
|
{
|
||||||
|
mCompileAllDialogue = all;
|
||||||
|
}
|
||||||
|
|
||||||
void OMW::Engine::setSoundUsage(bool soundUsage)
|
void OMW::Engine::setSoundUsage(bool soundUsage)
|
||||||
{
|
{
|
||||||
mUseSound = soundUsage;
|
mUseSound = soundUsage;
|
||||||
|
@ -601,3 +639,8 @@ void OMW::Engine::enableFontExport(bool exportFonts)
|
||||||
{
|
{
|
||||||
mExportFonts = exportFonts;
|
mExportFonts = exportFonts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OMW::Engine::setSaveGameFile(const std::string &savegame)
|
||||||
|
{
|
||||||
|
mSaveGameFile = savegame;
|
||||||
|
}
|
||||||
|
|
|
@ -76,12 +76,14 @@ namespace OMW
|
||||||
bool mSkipMenu;
|
bool mSkipMenu;
|
||||||
bool mUseSound;
|
bool mUseSound;
|
||||||
bool mCompileAll;
|
bool mCompileAll;
|
||||||
|
bool mCompileAllDialogue;
|
||||||
int mWarningsMode;
|
int mWarningsMode;
|
||||||
std::string mFocusName;
|
std::string mFocusName;
|
||||||
std::map<std::string,std::string> mFallbackMap;
|
std::map<std::string,std::string> mFallbackMap;
|
||||||
bool mScriptConsoleMode;
|
bool mScriptConsoleMode;
|
||||||
std::string mStartupScript;
|
std::string mStartupScript;
|
||||||
int mActivationDistanceOverride;
|
int mActivationDistanceOverride;
|
||||||
|
std::string mSaveGameFile;
|
||||||
// Grab mouse?
|
// Grab mouse?
|
||||||
bool mGrab;
|
bool mGrab;
|
||||||
|
|
||||||
|
@ -178,6 +180,9 @@ namespace OMW
|
||||||
/// Compile all scripts (excludign dialogue scripts) at startup?
|
/// Compile all scripts (excludign dialogue scripts) at startup?
|
||||||
void setCompileAll (bool all);
|
void setCompileAll (bool all);
|
||||||
|
|
||||||
|
/// Compile all dialogue scripts at startup?
|
||||||
|
void setCompileAllDialogue (bool all);
|
||||||
|
|
||||||
/// Font encoding
|
/// Font encoding
|
||||||
void setEncoding(const ToUTF8::FromType& encoding);
|
void setEncoding(const ToUTF8::FromType& encoding);
|
||||||
|
|
||||||
|
@ -200,6 +205,9 @@ namespace OMW
|
||||||
|
|
||||||
void enableFontExport(bool exportFonts);
|
void enableFontExport(bool exportFonts);
|
||||||
|
|
||||||
|
/// Set the save game file to load after initialising the engine.
|
||||||
|
void setSaveGameFile(const std::string& savegame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Files::ConfigurationManager& mCfgMgr;
|
Files::ConfigurationManager& mCfgMgr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -130,6 +130,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
("script-all", bpo::value<bool>()->implicit_value(true)
|
("script-all", bpo::value<bool>()->implicit_value(true)
|
||||||
->default_value(false), "compile all scripts (excluding dialogue scripts) at startup")
|
->default_value(false), "compile all scripts (excluding dialogue scripts) at startup")
|
||||||
|
|
||||||
|
("script-all-dialogue", bpo::value<bool>()->implicit_value(true)
|
||||||
|
->default_value(false), "compile all dialogue scripts at startup")
|
||||||
|
|
||||||
("script-console", bpo::value<bool>()->implicit_value(true)
|
("script-console", bpo::value<bool>()->implicit_value(true)
|
||||||
->default_value(false), "enable console-only script functionality")
|
->default_value(false), "enable console-only script functionality")
|
||||||
|
|
||||||
|
@ -149,6 +152,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
|
("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
|
||||||
->default_value(true), "enable script blacklisting")
|
->default_value(true), "enable script blacklisting")
|
||||||
|
|
||||||
|
("load-savegame", bpo::value<std::string>()->default_value(""),
|
||||||
|
"load a save game file on game startup")
|
||||||
|
|
||||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||||
->default_value(false), "skip main menu on game startup")
|
->default_value(false), "skip main menu on game startup")
|
||||||
|
|
||||||
|
@ -264,12 +270,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
engine.setCompileAll(variables["script-all"].as<bool>());
|
engine.setCompileAll(variables["script-all"].as<bool>());
|
||||||
|
engine.setCompileAllDialogue(variables["script-all-dialogue"].as<bool>());
|
||||||
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
||||||
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
||||||
engine.setStartupScript (variables["script-run"].as<std::string>());
|
engine.setStartupScript (variables["script-run"].as<std::string>());
|
||||||
engine.setWarningsMode (variables["script-warn"].as<int>());
|
engine.setWarningsMode (variables["script-warn"].as<int>());
|
||||||
engine.setScriptBlacklist (variables["script-blacklist"].as<StringsVector>());
|
engine.setScriptBlacklist (variables["script-blacklist"].as<StringsVector>());
|
||||||
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
|
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
|
||||||
|
engine.setSaveGameFile (variables["load-savegame"].as<std::string>());
|
||||||
|
|
||||||
// other settings
|
// other settings
|
||||||
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||||
|
|
|
@ -69,11 +69,13 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
|
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
|
||||||
|
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
|
||||||
|
|
||||||
/// Changes faction1's opinion of faction2 by \a diff.
|
/// Changes faction1's opinion of faction2 by \a diff.
|
||||||
virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0;
|
virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0;
|
||||||
|
|
||||||
|
virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute) = 0;
|
||||||
|
|
||||||
/// @return faction1's opinion of faction2
|
/// @return faction1's opinion of faction2
|
||||||
virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0;
|
virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
|
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
|
||||||
|
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,21 +113,19 @@ namespace MWBase
|
||||||
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
||||||
OT_Assault, // Attacking a peaceful NPC
|
OT_Assault, // Attacking a peaceful NPC
|
||||||
OT_Murder, // Murdering a peaceful NPC
|
OT_Murder, // Murdering a peaceful NPC
|
||||||
OT_Trespassing, // Staying in a cell you are not allowed in (where is this defined?)
|
OT_Trespassing, // Picking the lock of an owned door/chest
|
||||||
OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of
|
OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of
|
||||||
OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft)
|
OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft)
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief Commit a crime. If any actors witness the crime and report it,
|
|
||||||
* reportCrime will be called automatically.
|
|
||||||
* @note victim may be empty
|
* @note victim may be empty
|
||||||
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
|
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
|
||||||
* @return was the crime reported?
|
* @param victimAware Is the victim already aware of the crime?
|
||||||
|
* If this parameter is false, it will be determined by a line-of-sight and awareness check.
|
||||||
|
* @return was the crime seen?
|
||||||
*/
|
*/
|
||||||
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||||
OffenseType type, int arg=0) = 0;
|
OffenseType type, int arg=0, bool victimAware=false) = 0;
|
||||||
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
|
||||||
OffenseType type, int arg=0) = 0;
|
|
||||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||||
|
@ -183,6 +181,7 @@ namespace MWBase
|
||||||
///return the list of actors which are following the given actor
|
///return the list of actors which are following the given actor
|
||||||
/**ie AiFollow is active and the target is the actor**/
|
/**ie AiFollow is active and the target is the actor**/
|
||||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
||||||
|
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
///Returns a list of actors who are fighting the given actor within the fAlarmDistance
|
///Returns a list of actors who are fighting the given actor within the fAlarmDistance
|
||||||
/** ie AiCombat is active and the target is the actor **/
|
/** ie AiCombat is active and the target is the actor **/
|
||||||
|
@ -194,16 +193,16 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
|
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
|
||||||
|
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
|
||||||
|
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
/// @param bias Can be used to add an additional aggression bias towards the target,
|
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
|
||||||
/// making it more likely for the function to return true.
|
|
||||||
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false) = 0;
|
|
||||||
|
|
||||||
/// Resurrects the player if necessary
|
/// Resurrects the player if necessary
|
||||||
virtual void keepPlayerAlive() = 0;
|
virtual void keepPlayerAlive() = 0;
|
||||||
|
|
||||||
|
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,15 +42,21 @@ namespace MWBase
|
||||||
Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position
|
Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position
|
||||||
* but do not keep it updated (the sound will not move with
|
* but do not keep it updated (the sound will not move with
|
||||||
* the object and will not stop when the object is deleted. */
|
* the object and will not stop when the object is deleted. */
|
||||||
|
Play_RemoveAtDistance = 1<<3, /* (3D only) If the listener gets further than 2000 units away
|
||||||
Play_LoopNoEnv = Play_Loop | Play_NoEnv
|
from the sound source, the sound is removed.
|
||||||
|
This is weird stuff but apparently how vanilla works for sounds
|
||||||
|
played by the PlayLoopSound family of script functions. Perhaps we
|
||||||
|
can make this cut off a more subtle fade later, but have to
|
||||||
|
be careful to not change the overall volume of areas by too much. */
|
||||||
|
Play_LoopNoEnv = Play_Loop | Play_NoEnv,
|
||||||
|
Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance
|
||||||
};
|
};
|
||||||
enum PlayType {
|
enum PlayType {
|
||||||
Play_TypeSfx = 1<<3, /* Normal SFX sound */
|
Play_TypeSfx = 1<<4, /* Normal SFX sound */
|
||||||
Play_TypeVoice = 1<<4, /* Voice sound */
|
Play_TypeVoice = 1<<5, /* Voice sound */
|
||||||
Play_TypeFoot = 1<<5, /* Footstep sound */
|
Play_TypeFoot = 1<<6, /* Footstep sound */
|
||||||
Play_TypeMusic = 1<<6, /* Music track */
|
Play_TypeMusic = 1<<7, /* Music track */
|
||||||
Play_TypeMovie = 1<<7, /* Movie audio track */
|
Play_TypeMovie = 1<<8, /* Movie audio track */
|
||||||
Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie
|
Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,13 @@ namespace MWBase
|
||||||
///
|
///
|
||||||
/// \note Slot must belong to the current character.
|
/// \note Slot must belong to the current character.
|
||||||
|
|
||||||
virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
|
virtual void loadGame (const std::string& filepath) = 0;
|
||||||
///< Load a saved game file from \a slot.
|
///< Load a saved game directly from the given file path. This will search the CharacterManager
|
||||||
///
|
/// for a Character containing this save file, and set this Character current if one was found.
|
||||||
/// \note \a slot must belong to \a character.
|
/// Otherwise, a new Character will be created.
|
||||||
|
|
||||||
|
virtual void loadGame (const MWState::Character *character, const std::string& filepath) = 0;
|
||||||
|
///< Load a saved game file belonging to the given character.
|
||||||
|
|
||||||
///Simple saver, writes over the file if already existing
|
///Simple saver, writes over the file if already existing
|
||||||
/** Used for quick save and autosave **/
|
/** Used for quick save and autosave **/
|
||||||
|
|
|
@ -240,9 +240,11 @@ namespace MWBase
|
||||||
/** No guarentee of actually closing the window **/
|
/** No guarentee of actually closing the window **/
|
||||||
virtual void exitCurrentGuiMode() = 0;
|
virtual void exitCurrentGuiMode() = 0;
|
||||||
|
|
||||||
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
||||||
virtual void staticMessageBox(const std::string& message) = 0;
|
virtual void staticMessageBox(const std::string& message) = 0;
|
||||||
virtual void removeStaticMessageBox() = 0;
|
virtual void removeStaticMessageBox() = 0;
|
||||||
|
virtual void interactiveMessageBox (const std::string& message,
|
||||||
|
const std::vector<std::string>& buttons = std::vector<std::string>(), bool block=false) = 0;
|
||||||
|
|
||||||
/// returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
/// returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||||
virtual int readPressedButton() = 0;
|
virtual int readPressedButton() = 0;
|
||||||
|
@ -308,7 +310,7 @@ namespace MWBase
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
|
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
|
||||||
virtual int countSavedGameRecords() const = 0;
|
virtual int countSavedGameRecords() const = 0;
|
||||||
|
|
||||||
/// Does the current stack of GUI-windows permit saving?
|
/// Does the current stack of GUI-windows permit saving?
|
||||||
|
@ -342,6 +344,11 @@ namespace MWBase
|
||||||
virtual void setWerewolfOverlay(bool set) = 0;
|
virtual void setWerewolfOverlay(bool set) = 0;
|
||||||
|
|
||||||
virtual void toggleDebugWindow() = 0;
|
virtual void toggleDebugWindow() = 0;
|
||||||
|
|
||||||
|
/// Cycle to next or previous spell
|
||||||
|
virtual void cycleSpell(bool next) = 0;
|
||||||
|
/// Cycle to next or previous weapon
|
||||||
|
virtual void cycleWeapon(bool next) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ namespace ESM
|
||||||
struct Enchantment;
|
struct Enchantment;
|
||||||
struct Book;
|
struct Book;
|
||||||
struct EffectList;
|
struct EffectList;
|
||||||
|
struct CreatureLevList;
|
||||||
|
struct ItemLevList;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -102,10 +104,11 @@ namespace MWBase
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual int countSavedGameRecords() const = 0;
|
virtual int countSavedGameRecords() const = 0;
|
||||||
|
virtual int countSavedGameCells() const = 0;
|
||||||
|
|
||||||
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
|
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
|
||||||
|
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
|
virtual void readRecord (ESM::ESMReader& reader, uint32_t type,
|
||||||
const std::map<int, int>& contentFileMap) = 0;
|
const std::map<int, int>& contentFileMap) = 0;
|
||||||
|
|
||||||
virtual MWWorld::CellStore *getExterior (int x, int y) = 0;
|
virtual MWWorld::CellStore *getExterior (int x, int y) = 0;
|
||||||
|
@ -281,7 +284,8 @@ namespace MWBase
|
||||||
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
|
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0;
|
virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
||||||
|
///< @return an updated Ptr in case the Ptr's cell changes
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0;
|
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0;
|
||||||
|
@ -358,6 +362,14 @@ namespace MWBase
|
||||||
///< Create a new record (of type book) in the ESM store.
|
///< Create a new record (of type book) in the ESM store.
|
||||||
/// \return pointer to created record
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) = 0;
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) = 0;
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
virtual void update (float duration, bool paused) = 0;
|
virtual void update (float duration, bool paused) = 0;
|
||||||
|
|
||||||
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
|
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
|
||||||
|
@ -381,12 +393,14 @@ namespace MWBase
|
||||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
|
||||||
virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0;
|
||||||
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
||||||
|
virtual bool isWading(const MWWorld::Ptr &object) const = 0;
|
||||||
///Is the head of the creature underwater?
|
///Is the head of the creature underwater?
|
||||||
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
|
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
|
||||||
virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||||
|
|
||||||
virtual void togglePOV() = 0;
|
virtual void togglePOV() = 0;
|
||||||
|
virtual bool isFirstPerson() const = 0;
|
||||||
virtual void togglePreviewMode(bool enable) = 0;
|
virtual void togglePreviewMode(bool enable) = 0;
|
||||||
virtual bool toggleVanityMode(bool enable) = 0;
|
virtual bool toggleVanityMode(bool enable) = 0;
|
||||||
virtual void allowVanityMode(bool allow) = 0;
|
virtual void allowVanityMode(bool allow) = 0;
|
||||||
|
@ -534,7 +548,7 @@ namespace MWBase
|
||||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0;
|
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0;
|
||||||
|
|
||||||
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
|
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
|
const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0;
|
||||||
|
|
||||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "../mwworld//cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/physicssystem.hpp"
|
#include "../mwworld/physicssystem.hpp"
|
||||||
#include "../mwworld/action.hpp"
|
#include "../mwworld/action.hpp"
|
||||||
|
@ -30,20 +31,18 @@ namespace MWClass
|
||||||
return ptr.get<ESM::Activator>()->mBase->mId;
|
return ptr.get<ESM::Activator>()->mBase->mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
||||||
{
|
{
|
||||||
const std::string model = getModel(ptr);
|
|
||||||
if (!model.empty()) {
|
if (!model.empty()) {
|
||||||
MWRender::Actors& actors = renderingInterface.getActors();
|
MWRender::Actors& actors = renderingInterface.getActors();
|
||||||
actors.insertActivator(ptr);
|
actors.insertActivator(ptr, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
const std::string model = getModel(ptr);
|
|
||||||
if(!model.empty())
|
if(!model.empty())
|
||||||
physics.addObject(ptr);
|
physics.addObject(ptr, model);
|
||||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,10 @@ namespace MWClass
|
||||||
/// Return ID of \a ptr
|
/// Return ID of \a ptr
|
||||||
virtual std::string getId (const MWWorld::Ptr& ptr) const;
|
virtual std::string getId (const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
|
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const;
|
||||||
///< Add reference into a cell for rendering
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const;
|
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const;
|
||||||
|
|
||||||
virtual std::string getName (const MWWorld::Ptr& ptr) const;
|
virtual std::string getName (const MWWorld::Ptr& ptr) const;
|
||||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue